blob: 5517f178c154a1f920ce5aa8e31b1ebfd5a5a586 [file] [log] [blame]
// RUN: %target-run-simple-swift | %FileCheck %s
// REQUIRES: executable_test
protocol Observed: AnyObject {
func broadcastValueWillChange<T>(newValue: T)
}
struct Other<Value: Equatable> {
var value: Value
func hello() -> String {
return "Hello from \(value)"
}
}
@propertyWrapper
struct Observable<Value: Equatable> {
private var stored: Value
init(wrappedValue: Value) {
self.stored = wrappedValue
}
var wrappedValue: Value {
get { fatalError("called wrappedValue getter") }
set { fatalError("called wrappedValue setter") }
}
var projectedValue: Other<Value> {
get { fatalError("called projectedValue getter") }
set { fatalError("called projectedValue setter") }
}
static subscript<EnclosingSelf: Observed, FinalValue>(
_enclosingInstance observed: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, FinalValue>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
) -> Value {
get {
observed[keyPath: storageKeyPath].stored
}
set {
if observed[keyPath: storageKeyPath].stored != newValue {
observed.broadcastValueWillChange(newValue: newValue)
}
observed[keyPath: storageKeyPath].stored = newValue
}
}
static subscript<EnclosingSelf: Observed>(
_enclosingInstance observed: EnclosingSelf,
projected wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Other<Value>>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
) -> Other<Value> {
get {
Other(value: observed[keyPath: storageKeyPath].stored)
}
set {
}
}
}
class MyType<T: Equatable>: Observed {
@Observable var x: T
init(x: T) {
self.x = x
}
func broadcastValueWillChange<T>(newValue: T) {
print("Value of 'x' is changing from \(x) to \(newValue)")
print($x.hello())
}
}
func testMyType(_ myType: MyType<Int>) {
// CHECK: Value of 'x' is changing from 17 to 42
// CHECK-NEXT: Hello from 17
myType.x = 42
// CHECK-NEXT: Value of 'x' is changing from 42 to 25
// CHECK-NEXT: Hello from 42
myType.x = 42
myType.x = 25
}
testMyType(MyType(x: 17))