16
16
/// of a type.
17
17
@available ( SwiftStdlib 5 . 9 , * )
18
18
public 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
+ }
23
110
}
24
111
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 > ] ( )
28
115
29
- mutating func generateId( ) -> Int {
116
+ internal mutating func generateId( ) -> Int {
30
117
defer { id &+= 1 }
31
118
return id
32
119
}
33
120
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 {
35
149
let id = generateId ( )
36
- observations [ id] = Observation ( properties : properties , observer : observer )
150
+ observations [ id] = Observation ( kind : . values ( ValuesObserver ( storage : storage ) ) , properties : properties )
37
151
for keyPath in properties {
38
152
lookups [ keyPath, default: [ ] ] . insert ( id)
39
153
}
40
154
return id
41
155
}
42
156
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 {
46
167
if var ids = lookups [ keyPath] {
47
168
ids. remove ( id)
48
169
if ids. count == 0 {
@@ -52,49 +173,130 @@ public struct ObservationRegistrar: Sendable {
52
173
}
53
174
}
54
175
}
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
+ }
55
196
}
197
+ return trackers
56
198
}
57
199
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 ] ( )
60
203
if let ids = lookups [ keyPath] {
61
204
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)
64
207
cancel ( id)
65
208
}
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)
66
221
}
67
222
}
68
- return observers
69
223
}
70
224
}
71
225
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 }
74
230
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
+ }
76
238
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) }
79
241
}
80
242
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 ) {
82
248
state. withCriticalRegion { $0. cancel ( id) }
83
249
}
250
+
251
+ internal func cancelAll( ) {
252
+ state. withCriticalRegion { $0. cancelAll ( ) }
253
+ }
84
254
85
- func willSet< Subject, Member> (
255
+ internal func willSet< Subject: Observable , Member> (
86
256
_ subject: Subject ,
87
257
keyPath: KeyPath < Subject , Member >
88
258
) {
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 {
91
275
action ( )
92
276
}
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 ( )
93
291
}
94
292
}
95
293
96
- let context = Context ( )
294
+ internal var context : Context {
295
+ return extent. context
296
+ }
97
297
298
+ private var extent = Extent ( )
299
+
98
300
/// Creates an instance of the observation registrar.
99
301
///
100
302
/// You don't need to create an instance of
@@ -133,7 +335,7 @@ public struct ObservationRegistrar: Sendable {
133
335
) {
134
336
context. willSet ( subject, keyPath: keyPath)
135
337
}
136
-
338
+
137
339
/// A property observation called after setting the value of the subject.
138
340
///
139
341
/// - Parameters:
@@ -143,7 +345,7 @@ public struct ObservationRegistrar: Sendable {
143
345
_ subject: Subject ,
144
346
keyPath: KeyPath < Subject , Member >
145
347
) {
146
-
348
+ context . didSet ( subject , keyPath : keyPath )
147
349
}
148
350
149
351
/// Identifies mutations to the transactions registered for observers.
0 commit comments