1616/// of a type.
1717@available ( SwiftStdlib 5 . 9 , * )
1818public struct ObservationRegistrar : Sendable {
19- struct State : @unchecked Sendable {
20- struct Observation {
21- var properties : Set < AnyKeyPath >
22- var observer : @Sendable ( ) -> Void
19+ internal class ValueObservationStorage {
20+ func emit< Element> ( _ element: Element ) -> Bool { return false }
21+ func cancel( ) { }
22+ }
23+
24+ private struct ValuesObserver {
25+ private let storage : ValueObservationStorage
26+
27+ internal init ( storage: ValueObservationStorage ) {
28+ self . storage = storage
29+ }
30+
31+ internal func emit< Element> ( _ element: Element ) -> Bool {
32+ storage. emit ( element)
33+ }
34+
35+ internal func cancel( ) {
36+ storage. cancel ( )
37+ }
38+ }
39+
40+ private struct State : @unchecked Sendable {
41+ private enum ObservationKind {
42+ case willSetTracking( @Sendable ( ) -> Void )
43+ case didSetTracking( @Sendable ( ) -> Void )
44+ case computed( @Sendable ( Any ) -> Void )
45+ case values( ValuesObserver )
46+ }
47+
48+ private struct Observation {
49+ private var kind : ObservationKind
50+ internal var properties : Set < AnyKeyPath >
51+
52+ internal init ( kind: ObservationKind , properties: Set < AnyKeyPath > ) {
53+ self . kind = kind
54+ self . properties = properties
55+ }
56+
57+ var willSetTracker : ( @Sendable ( ) -> Void ) ? {
58+ switch kind {
59+ case . willSetTracking( let tracker) :
60+ return tracker
61+ default :
62+ return nil
63+ }
64+ }
65+
66+ var didSetTracker : ( @Sendable ( ) -> Void ) ? {
67+ switch kind {
68+ case . didSetTracking( let tracker) :
69+ return tracker
70+ default :
71+ return nil
72+ }
73+ }
74+
75+ var observer : ( @Sendable ( Any ) -> Void ) ? {
76+ switch kind {
77+ case . computed( let observer) :
78+ return observer
79+ default :
80+ return nil
81+ }
82+ }
83+
84+ var isValueObserver : Bool {
85+ switch kind {
86+ case . values:
87+ return true
88+ default :
89+ return false
90+ }
91+ }
92+
93+ func emit< Element> ( _ value: Element ) -> Bool {
94+ switch kind {
95+ case . values( let observer) :
96+ return observer. emit ( value)
97+ default :
98+ return false
99+ }
100+ }
101+
102+ func cancel( ) {
103+ switch kind {
104+ case . values( let observer) :
105+ observer. cancel ( )
106+ default :
107+ break
108+ }
109+ }
23110 }
24111
25- var id = 0
26- var observations = [ Int : Observation] ( )
27- var lookups = [ AnyKeyPath : Set < Int > ] ( )
112+ private var id = 0
113+ private var observations = [ Int : Observation] ( )
114+ private var lookups = [ AnyKeyPath : Set < Int > ] ( )
28115
29- mutating func generateId( ) -> Int {
116+ internal mutating func generateId( ) -> Int {
30117 defer { id &+= 1 }
31118 return id
32119 }
33120
34- mutating func registerTracking( for properties: Set < AnyKeyPath > , observer: @Sendable @escaping ( ) -> Void ) -> Int {
121+ internal mutating func registerTracking( for properties: Set < AnyKeyPath > , willSet observer: @Sendable @escaping ( ) -> Void ) -> Int {
122+ let id = generateId ( )
123+ observations [ id] = Observation ( kind: . willSetTracking( observer) , properties: properties)
124+ for keyPath in properties {
125+ lookups [ keyPath, default: [ ] ] . insert ( id)
126+ }
127+ return id
128+ }
129+
130+ internal mutating func registerTracking( for properties: Set < AnyKeyPath > , didSet observer: @Sendable @escaping ( ) -> Void ) -> Int {
131+ let id = generateId ( )
132+ observations [ id] = Observation ( kind: . didSetTracking( observer) , properties: properties)
133+ for keyPath in properties {
134+ lookups [ keyPath, default: [ ] ] . insert ( id)
135+ }
136+ return id
137+ }
138+
139+ internal mutating func registerComputedValues( for properties: Set < AnyKeyPath > , observer: @Sendable @escaping ( Any ) -> Void ) -> Int {
140+ let id = generateId ( )
141+ observations [ id] = Observation ( kind: . computed( observer) , properties: properties)
142+ for keyPath in properties {
143+ lookups [ keyPath, default: [ ] ] . insert ( id)
144+ }
145+ return id
146+ }
147+
148+ internal mutating func registerValues( for properties: Set < AnyKeyPath > , storage: ValueObservationStorage ) -> Int {
35149 let id = generateId ( )
36- observations [ id] = Observation ( properties : properties , observer : observer )
150+ observations [ id] = Observation ( kind : . values ( ValuesObserver ( storage : storage ) ) , properties : properties )
37151 for keyPath in properties {
38152 lookups [ keyPath, default: [ ] ] . insert ( id)
39153 }
40154 return id
41155 }
42156
43- mutating func cancel( _ id: Int ) {
44- if let tracking = observations. removeValue ( forKey: id) {
45- for keyPath in tracking. properties {
157+ internal func valueObservers( for keyPath: AnyKeyPath ) -> Set < Int > {
158+ guard let ids = lookups [ keyPath] else {
159+ return [ ]
160+ }
161+ return ids. filter { observations [ $0] ? . isValueObserver == true }
162+ }
163+
164+ internal mutating func cancel( _ id: Int ) {
165+ if let observation = observations. removeValue ( forKey: id) {
166+ for keyPath in observation. properties {
46167 if var ids = lookups [ keyPath] {
47168 ids. remove ( id)
48169 if ids. count == 0 {
@@ -52,49 +173,130 @@ public struct ObservationRegistrar: Sendable {
52173 }
53174 }
54175 }
176+ observation. cancel ( )
177+ }
178+ }
179+
180+ internal mutating func cancelAll( ) {
181+ for observation in observations. values {
182+ observation. cancel ( )
183+ }
184+ observations. removeAll ( )
185+ lookups. removeAll ( )
186+ }
187+
188+ internal mutating func willSet( keyPath: AnyKeyPath ) -> [ @Sendable ( ) -> Void ] {
189+ var trackers = [ @Sendable ( ) -> Void ] ( )
190+ if let ids = lookups [ keyPath] {
191+ for id in ids {
192+ if let tracker = observations [ id] ? . willSetTracker {
193+ trackers. append ( tracker)
194+ }
195+ }
55196 }
197+ return trackers
56198 }
57199
58- mutating func willSet( keyPath: AnyKeyPath ) -> [ @Sendable ( ) -> Void ] {
59- var observers = [ @Sendable ( ) -> Void ] ( )
200+ internal mutating func didSet< Subject: Observable , Member> ( keyPath: KeyPath < Subject , Member > ) -> ( [ @Sendable ( Any ) -> Void ] , [ @Sendable ( ) -> Void ] ) {
201+ var observers = [ @Sendable ( Any ) -> Void ] ( )
202+ var trackers = [ @Sendable ( ) -> Void ] ( )
60203 if let ids = lookups [ keyPath] {
61204 for id in ids {
62- if let observation = observations [ id] {
63- observers. append ( observation . observer)
205+ if let observer = observations [ id] ? . observer {
206+ observers. append ( observer)
64207 cancel ( id)
65208 }
209+ if let tracker = observations [ id] ? . didSetTracker {
210+ trackers. append ( tracker)
211+ }
212+ }
213+ }
214+ return ( observers, trackers)
215+ }
216+
217+ internal mutating func emit< Element> ( _ value: Element , ids: Set < Int > ) {
218+ for id in ids {
219+ if observations [ id] ? . emit ( value) == true {
220+ cancel ( id)
66221 }
67222 }
68- return observers
69223 }
70224 }
71225
72- struct Context : Sendable {
73- let state = _ManagedCriticalState ( State ( ) )
226+ internal struct Context : Sendable {
227+ private let state = _ManagedCriticalState ( State ( ) )
228+
229+ internal var id : ObjectIdentifier { state. id }
74230
75- var id : ObjectIdentifier { state. id }
231+ internal func registerTracking( for properties: Set < AnyKeyPath > , willSet observer: @Sendable @escaping ( ) -> Void ) -> Int {
232+ state. withCriticalRegion { $0. registerTracking ( for: properties, willSet: observer) }
233+ }
234+
235+ internal func registerTracking( for properties: Set < AnyKeyPath > , didSet observer: @Sendable @escaping ( ) -> Void ) -> Int {
236+ state. withCriticalRegion { $0. registerTracking ( for: properties, didSet: observer) }
237+ }
76238
77- func registerTracking ( for properties: Set < AnyKeyPath > , observer: @Sendable @escaping ( ) -> Void ) -> Int {
78- state. withCriticalRegion { $0. registerTracking ( for: properties, observer: observer) }
239+ internal func registerComputedValues ( for properties: Set < AnyKeyPath > , observer: @Sendable @escaping ( Any ) -> Void ) -> Int {
240+ state. withCriticalRegion { $0. registerComputedValues ( for: properties, observer: observer) }
79241 }
80242
81- func cancel( _ id: Int ) {
243+ internal func registerValues( for properties: Set < AnyKeyPath > , storage: ValueObservationStorage ) -> Int {
244+ state. withCriticalRegion { $0. registerValues ( for: properties, storage: storage) }
245+ }
246+
247+ internal func cancel( _ id: Int ) {
82248 state. withCriticalRegion { $0. cancel ( id) }
83249 }
250+
251+ internal func cancelAll( ) {
252+ state. withCriticalRegion { $0. cancelAll ( ) }
253+ }
84254
85- func willSet< Subject, Member> (
255+ internal func willSet< Subject: Observable , Member> (
86256 _ subject: Subject ,
87257 keyPath: KeyPath < Subject , Member >
88258 ) {
89- let actions = state. withCriticalRegion { $0. willSet ( keyPath: keyPath) }
90- for action in actions {
259+ let tracking = state. withCriticalRegion { $0. willSet ( keyPath: keyPath) }
260+ for action in tracking {
261+ action ( )
262+ }
263+ }
264+
265+ internal func didSet< Subject: Observable , Member> (
266+ _ subject: Subject ,
267+ keyPath: KeyPath < Subject , Member >
268+ ) {
269+ let ( ids, ( actions, tracking) ) = state. withCriticalRegion { ( $0. valueObservers ( for: keyPath) , $0. didSet ( keyPath: keyPath) ) }
270+ if !ids. isEmpty {
271+ let value = subject [ keyPath: keyPath]
272+ state. withCriticalRegion { $0. emit ( value, ids: ids) }
273+ }
274+ for action in tracking {
91275 action ( )
92276 }
277+ for action in actions {
278+ action ( subject)
279+ }
280+ }
281+ }
282+
283+ private final class Extent : @unchecked Sendable {
284+ let context = Context ( )
285+
286+ init ( ) {
287+ }
288+
289+ deinit {
290+ context. cancelAll ( )
93291 }
94292 }
95293
96- let context = Context ( )
294+ internal var context : Context {
295+ return extent. context
296+ }
97297
298+ private var extent = Extent ( )
299+
98300 /// Creates an instance of the observation registrar.
99301 ///
100302 /// You don't need to create an instance of
@@ -133,7 +335,7 @@ public struct ObservationRegistrar: Sendable {
133335 ) {
134336 context. willSet ( subject, keyPath: keyPath)
135337 }
136-
338+
137339 /// A property observation called after setting the value of the subject.
138340 ///
139341 /// - Parameters:
@@ -143,7 +345,7 @@ public struct ObservationRegistrar: Sendable {
143345 _ subject: Subject ,
144346 keyPath: KeyPath < Subject , Member >
145347 ) {
146-
348+ context . didSet ( subject , keyPath : keyPath )
147349 }
148350
149351 /// Identifies mutations to the transactions registered for observers.
0 commit comments