We have now added a CoW struct that we can use to wrap heavy structs and give them copy on write behaviour.
@dynamicMemberLookup
struct CoW<T> {
init(_ value: T) {
_storage = Storage(value)
}
public subscript<V>(dynamicMember keyPath: WritableKeyPath<T, V>) -> V {
get { value[keyPath: keyPath] }
set { value[keyPath: keyPath] = newValue }
}
var value: T {
get {
return _storage.value
}
set {
if isKnownUniquelyReferenced(&_storage) {
_storage.value = value
} else {
_storage = Storage(newValue)
}
}
}
private var _storage: Storage<T>
private class Storage<T> {
var value: T
init(_ value: T) {
self.value = value
}
}
}
extension CoW: Equatable where T: Equatable {
static func == (lhs: CoW<T>, rhs: CoW<T>) -> Bool {
return lhs.value == rhs.value
}
}
Not sure if the @dynamicMemberLookup
should be used or not, but I think it will let us skip the value-part when accessing properties on the storage.
Now we can easily wrap state objects when needed:
var articleListState:CoW<ArticleListState> = CoW(ArticleListState.initialState())