Kurt Horimoto
Kurt Horimoto

Reputation: 99

Downcasting PartialKeyPath to ReferenceWriteableKeyPath using generics?

I want a simple serialization implementation that stores values of various KeyPaths for a class and applies them. I know this can be implemented by storing vars manually, but I'd prefer to use KeyPaths since it would be easier to add additional paths. See example below:

class Model {
  var intValue: Int
  var boolValue: Bool
}

class ModelState {
  static let keyPaths = [ \Model.intValue, \Model.boolValue ]
  let values: [PartialKeyPath<Model>, Any]
  init(model: Model) {
    var values = [PartialKeyPath<Model>, Any]()
    Self.keyPaths.forEach { values[$0] = model[keyPath: $0 }
    self.values = values
  }
}

extension Model {
  var state: ModelState {
    get { return ModelState(model: self }
    set { newValue.values.forEach { (keyPath, value) in applyValue(keyPath, value) } }
  }

  private func applyValue<T>(_ keyPath: PartialKeyPath<Model>, value: T) {
    if let writeable = keyPath as? ReferenceWriteableKeyPath<Model, T> {
      self[keyPath: writeable] = value
    }
  } 
}

If I add a breakpoint in applyValue(), the keyPath is shown as the expected ReferenceWriteableKeyPath. Similarly, if I attempt to typecast the KeyPath by explicitly stating the expected value type (e.g. ReferenceWriteableKeyPath<Model, Int> or ReferenceWriteableKeyPath<Model, Bool>), the typecast works correctly. The code as written does not ever enter into the condition, however. Does anyone see the issue with the code or know how to make this generic downcast work?

Upvotes: 0

Views: 500

Answers (0)

Related Questions