Created
June 6, 2019 18:37
-
-
Save airspeedswift/71ccddc27354be908dd92a52a34a776f to your computer and use it in GitHub Desktop.
COWed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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) | |
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
Shouldn't
be
since
Cowed
is constrained to class types (byCowable
restrictions) anyway?