0

I've some entities (for example hashtags, mentions etc) should be extracted from a text. To make things re-usable I've created some protocols / structures like this:

struct Match {
  var value: String
  var range: Range<String>
}

protocol Entity {

  associatedtype instructions: RegexInstructions

  var fullMatch: Match { get }
  var partialMatches: [instructions.PartialKeys: Match] { get }
}

// instructions holding keys for regex subgroups and regex string, to understand how an entity should/could be extracted
protocol RegexInstructions {

  associatedtype PartialKeys: EntityPartialKeys

  var regexString: String { get }
}

typealias EntityPartialKeys = RawRepresentable & Hashable

I've Match struct, to hold regex matches' value and range. Protocol Entity is my container for extracted regex matches. It's instructions associated type needed for understanding how an entity should be extracted and how it's variables will be filled.

Now I'm creating some entities:

struct EntityA  : Entity {
  typealias instructions = InstructionA

  var fullMatch: Match
  var partialMatches: [instructions.PartialKeys : Match]

}

struct InstructionA: RegexInstructions  {
  enum PartialKeys: String, EntityPartialKeys {
    case x, y, z
  }
  var regexString: String {
    return "A regex string"
  }
}

/// and more entities

And a regex executing service class is where I stuck:

class RegExecuter {
  private(set) var registered: [Entity.Type] = [] // ---> Protocol 'Entity' can only be used as a generic constraint because it has Self or associated type requirements
  let text: String

  init(withTexh text: String) {
    self.text = text
  }
  func register(entityType: Entity.Type) {
    registered.append(entityType)
  }

  func searchAll() -> [Entity] { // ---> Protocol 'Entity' can only be used as a generic constraint because it has Self or associated type requirements
    var entitiesFound: [Entity] = [] // ---> Protocol 'Entity' can only be used as a generic constraint because it has Self or associated type requirements
    for entityType in registered {
      entitiesFound.append(contentsOf: Regex.search(entityType, inText: text))  // here I'm using type.instructions to understand how an entity type could be extracted from text and creating an entity of that type
    }
    return entitiesFound
  }
}

let regExecuter = RegExecuter.init(withText: "a text")
// register needed entities
regExecuter.register(EntityA.self)
regExecuter.register(EntityB.self)
regExecuter.register(EntityC.self)

let foundEntities = regExecuter.searchAll()

What I'm trying to do here is something like UITableView's UITableViewCell registration.

Service should know what to search (It's going to search some objects conforming Entity protocol but which ones?) So I'm trying to register Entity's Types, so service will know what to search, how to search and how to process found matches.

Since protocols with associatedtypes should be used as generics, I'm stuck. I've tried many things, from type erasure to creating a BaseEntity protocol for Entity protocol, without having associatedtypes, to be able to use a downcasting / upcasting, without luck. Hope someone can help me to achieve this.

Arda Oğul Üçpınar
  • 881
  • 1
  • 14
  • 38

0 Answers0