Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
COWed
/// Conform references types for use in the COW wrapper to this protocol
protocol Cowable: class {
/// Make a new unique instance of `copied`
static func makeUnique(_ copied: Self) -> Self
}
/// A wrapper that turns a Cowable reference type into a value-semantic
/// type with access to all of its properties
@dynamicMemberLookup
struct COW<Cowed: Cowable> {
private var _cowed: Cowed
init(_ cowing: Cowed) {
_cowed = cowing
}
public subscript<T>(dynamicMember keyPath: KeyPath<Cowed,T>) -> T {
get { _cowed[keyPath: keyPath] }
}
public subscript<T>(dynamicMember keyPath: WritableKeyPath<Cowed,T>) -> T {
get { _cowed[keyPath: keyPath] }
set {
if !isKnownUniquelyReferenced(&_cowed) { _cowed = .makeUnique(_cowed) }
_cowed[keyPath: keyPath] = newValue
}
}
}
extension COW: CustomStringConvertible where Cowed: CustomStringConvertible {
var description: String { _cowed.description }
}
extension Texture: CustomStringConvertible {
var description: String { "Texture(isSparkly: \(isSparkly)" }
}
final class Texture {
init(isSparkly: Bool) { self.isSparkly = isSparkly }
var isSparkly: Bool
}
extension Texture: Cowable {
static func makeUnique(_ copied: Texture) -> Texture {
Texture(isSparkly: copied.isSparkly)
}
}
struct Material {
public var roughness: Float
public var texture: COW<Texture> = COW(Texture(isSparkly: false))
}
var m1 = Material(roughness: 0.5)
var m2 = m1
m1.texture.isSparkly = true
print(m1)
print(m2)
@ktraunmueller

This comment has been minimized.

Copy link

commented Jun 7, 2019

Shouldn't

private var _cowed: Cowed

be

private let _cowed: Cowed

since Cowed is constrained to class types (by Cowable restrictions) anyway?

@lilyball

This comment has been minimized.

Copy link

commented Jun 13, 2019

In the talk they used ReferenceWritableKeyPath, but this gist just uses WritableKeyPath. I admit I'm not sure what the practical difference is (the keypath documentation is rather lacking).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.