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