@@ -71,7 +71,8 @@ internal struct StoreContext {
71
71
let ( key, _) = lookupAtomKeyAndOverride ( of: atom)
72
72
73
73
if let cache = lookupCache ( of: atom, for: key) {
74
- update ( atom: atom, for: key, cache: cache, newValue: value)
74
+ switchContext ( scope: cache. initializedScope)
75
+ . update ( atom: atom, for: key, cache: cache, newValue: value)
75
76
}
76
77
}
77
78
@@ -81,7 +82,8 @@ internal struct StoreContext {
81
82
82
83
if let cache = lookupCache ( of: atom, for: key) {
83
84
let newValue = mutating ( cache. value, body)
84
- update ( atom: atom, for: key, cache: cache, newValue: newValue)
85
+ switchContext ( scope: cache. initializedScope)
86
+ . update ( atom: atom, for: key, cache: cache, newValue: newValue)
85
87
}
86
88
}
87
89
@@ -128,7 +130,10 @@ internal struct StoreContext {
128
130
@_disfavoredOverload
129
131
func refresh< Node: AsyncAtom > ( _ atom: Node ) async -> Node . Produced {
130
132
let ( key, override) = lookupAtomKeyAndOverride ( of: atom)
131
- let context = prepareForTransaction ( of: atom, for: key)
133
+ let cache = lookupCache ( of: atom, for: key)
134
+ let localContext = switchContext ( scope: cache? . initializedScope)
135
+ let context = localContext. prepareForTransaction ( of: atom, for: key)
136
+
132
137
let value : Node . Produced
133
138
134
139
if let override {
@@ -140,14 +145,14 @@ internal struct StoreContext {
140
145
141
146
await atom. refreshProducer. refreshValue ( value, context)
142
147
143
- guard let cache = lookupCache ( of : atom , for : key ) else {
148
+ guard let cache else {
144
149
checkAndRelease ( for: key)
145
150
return value
146
151
}
147
152
148
153
// Notify update unless it's cancelled or terminated by other operations.
149
154
if !Task. isCancelled && !context. isTerminated {
150
- update ( atom: atom, for: key, cache: cache, newValue: value)
155
+ localContext . update ( atom: atom, for: key, cache: cache, newValue: value)
151
156
}
152
157
153
158
return value
@@ -156,8 +161,10 @@ internal struct StoreContext {
156
161
@usableFromInline
157
162
func refresh< Node: Refreshable > ( _ atom: Node ) async -> Node . Produced {
158
163
let ( key, _) = lookupAtomKeyAndOverride ( of: atom)
159
- let state = getState ( of: atom, for: key)
160
- let currentContext = AtomCurrentContext ( store: self )
164
+ let cache = lookupCache ( of: atom, for: key)
165
+ let localContext = switchContext ( scope: cache? . initializedScope)
166
+ let state = localContext. getState ( of: atom, for: key)
167
+ let currentContext = AtomCurrentContext ( store: localContext)
161
168
162
169
// Detach the dependencies once to delay updating the downstream until
163
170
// this atom's value refresh is complete.
@@ -167,14 +174,14 @@ internal struct StoreContext {
167
174
// Restore dependencies when the refresh is completed.
168
175
attachDependencies ( dependencies, for: key)
169
176
170
- guard let transactionState = state. transactionState, let cache = lookupCache ( of : atom , for : key ) else {
177
+ guard let transactionState = state. transactionState, let cache else {
171
178
checkAndRelease ( for: key)
172
179
return value
173
180
}
174
181
175
182
// Notify update unless it's cancelled or terminated by other operations.
176
183
if !Task. isCancelled && !transactionState. isTerminated {
177
- update ( atom: atom, for: key, cache: cache, newValue: value)
184
+ localContext . update ( atom: atom, for: key, cache: cache, newValue: value)
178
185
}
179
186
180
187
return value
@@ -186,14 +193,18 @@ internal struct StoreContext {
186
193
let ( key, override) = lookupAtomKeyAndOverride ( of: atom)
187
194
188
195
if let cache = lookupCache ( of: atom, for: key) {
189
- let newValue = getValue ( of: atom, for: key, override: override)
190
- update ( atom: atom, for: key, cache: cache, newValue: newValue)
196
+ let localContext = switchContext ( scope: cache. initializedScope)
197
+ let newValue = localContext. getValue ( of: atom, for: key, override: override)
198
+ localContext. update ( atom: atom, for: key, cache: cache, newValue: newValue)
191
199
}
192
200
}
193
201
194
202
@usableFromInline
195
203
func reset( _ atom: some Resettable ) {
196
- let currentContext = AtomCurrentContext ( store: self )
204
+ let ( key, _) = lookupAtomKeyAndOverride ( of: atom)
205
+ let cache = lookupCache ( of: atom, for: key)
206
+ let localContext = switchContext ( scope: cache? . initializedScope)
207
+ let currentContext = AtomCurrentContext ( store: localContext)
197
208
atom. reset ( context: currentContext)
198
209
}
199
210
@@ -306,22 +317,27 @@ private extension StoreContext {
306
317
updatedScopes [ currentScope. key] = currentScope
307
318
}
308
319
309
- func transitiveUpdate ( for key: AtomKey , cache: some AtomCacheProtocol ) {
320
+ func updatePropagation ( for key: AtomKey , cache: some AtomCacheProtocol ) {
310
321
// Dependents must be updated with the scope at which they were initialised.
311
- let localContext = StoreContext (
312
- store: store,
313
- rootScope: rootScope,
314
- currentScope: cache. initializedScope
315
- )
322
+ let localContext = switchContext ( scope: cache. initializedScope)
316
323
317
- let didUpdate = localContext. transitiveUpdate ( for: key, cache: cache)
324
+ // Overridden atoms don't get updated transitively.
325
+ let newValue = localContext. getValue ( of: cache. atom, for: key, override: nil )
318
326
319
- guard didUpdate else {
327
+ store. state. caches [ key] = cache. updated ( value: newValue)
328
+
329
+ // Check whether if the dependent atoms should be updated transitively.
330
+ guard cache. atom. producer. shouldUpdate ( cache. value, newValue) else {
320
331
// Record the atom to avoid downstream from being update.
321
332
skippedDependencies. insert ( key)
322
333
return
323
334
}
324
335
336
+ // Perform side effects before updating downstream.
337
+ let state = localContext. getState ( of: cache. atom, for: key)
338
+ let currentContext = AtomCurrentContext ( store: localContext)
339
+ state. effect. updated ( context: currentContext)
340
+
325
341
if let scope = cache. initializedScope {
326
342
updatedScopes [ scope. key] = scope
327
343
}
@@ -362,7 +378,7 @@ private extension StoreContext {
362
378
363
379
if let cache, let dependencyCache {
364
380
performUpdate ( dependency: dependencyCache. atom) {
365
- transitiveUpdate ( for: key, cache: cache)
381
+ updatePropagation ( for: key, cache: cache)
366
382
}
367
383
}
368
384
@@ -384,30 +400,12 @@ private extension StoreContext {
384
400
notifyUpdateToObservers ( scopes: updatedScopes. values)
385
401
}
386
402
387
- func transitiveUpdate( for key: AtomKey , cache: some AtomCacheProtocol ) -> Bool {
388
- // Overridden atoms don't get updated transitively.
389
- let newValue = getValue ( of: cache. atom, for: key, override: nil )
390
-
391
- store. state. caches [ key] = cache. updated ( value: newValue)
392
-
393
- // Check whether if the dependent atoms should be updated transitively.
394
- guard cache. atom. producer. shouldUpdate ( cache. value, newValue) else {
395
- return false
396
- }
397
-
398
- // Perform side effects before updating downstream.
399
- let state = getState ( of: cache. atom, for: key)
400
- let currentContext = AtomCurrentContext ( store: self )
401
- state. effect. updated ( context: currentContext)
402
- return true
403
- }
404
-
405
403
func release( for key: AtomKey ) {
406
404
let dependencies = store. graph. dependencies. removeValue ( forKey: key)
407
405
let state = store. state. states. removeValue ( forKey: key)
406
+ let cache = store. state. caches. removeValue ( forKey: key)
408
407
409
408
store. graph. children. removeValue ( forKey: key)
410
- store. state. caches. removeValue ( forKey: key)
411
409
store. state. subscriptions. removeValue ( forKey: key)
412
410
413
411
if let dependencies {
@@ -419,8 +417,12 @@ private extension StoreContext {
419
417
420
418
state? . transactionState? . terminate ( )
421
419
422
- let currentContext = AtomCurrentContext ( store: self )
423
- state? . effect. released ( context: currentContext)
420
+ if let state, let cache {
421
+ // It must call release effect with the scope at which they were initialised.
422
+ let localContext = switchContext ( scope: cache. initializedScope)
423
+ let currentContext = AtomCurrentContext ( store: localContext)
424
+ state. effect. released ( context: currentContext)
425
+ }
424
426
}
425
427
426
428
func checkAndRelease( for key: AtomKey ) {
@@ -505,7 +507,8 @@ private extension StoreContext {
505
507
506
508
return AtomProducerContext ( store: self , transactionState: transactionState) { newValue in
507
509
if let cache = lookupCache ( of: atom, for: key) {
508
- update ( atom: atom, for: key, cache: cache, newValue: newValue)
510
+ switchContext ( scope: cache. initializedScope)
511
+ . update ( atom: atom, for: key, cache: cache, newValue: newValue)
509
512
}
510
513
}
511
514
}
@@ -640,4 +643,12 @@ private extension StoreContext {
640
643
observer. onUpdate ( snapshot)
641
644
}
642
645
}
646
+
647
+ func switchContext( scope: Scope ? ) -> StoreContext {
648
+ StoreContext (
649
+ store: store,
650
+ rootScope: rootScope,
651
+ currentScope: scope
652
+ )
653
+ }
643
654
}
0 commit comments