@@ -45,36 +45,30 @@ extension EffectPublisher {
45
45
_cancellablesLock. lock ( )
46
46
defer { _cancellablesLock. unlock ( ) }
47
47
48
- let id = _CancelToken ( id: id)
49
48
if cancelInFlight {
50
- _cancellationCancellables [ id ] ? . forEach { $0 . cancel ( ) }
49
+ _cancellationCancellables. cancel ( id : id )
51
50
}
52
51
53
52
let cancellationSubject = PassthroughSubject < Void , Never > ( )
54
53
55
- var cancellationCancellable : AnyCancellable !
56
- cancellationCancellable = AnyCancellable {
54
+ var cancellable : AnyCancellable !
55
+ cancellable = AnyCancellable {
57
56
_cancellablesLock. sync {
58
57
cancellationSubject. send ( ( ) )
59
58
cancellationSubject. send ( completion: . finished)
60
- _cancellationCancellables [ id] ? . remove ( cancellationCancellable)
61
- if _cancellationCancellables [ id] ? . isEmpty == . some( true ) {
62
- _cancellationCancellables [ id] = nil
63
- }
59
+ _cancellationCancellables. remove ( cancellable, at: id)
64
60
}
65
61
}
66
62
67
63
return publisher. prefix ( untilOutputFrom: cancellationSubject)
68
64
. handleEvents (
69
65
receiveSubscription: { _ in
70
- _ = _cancellablesLock. sync {
71
- _cancellationCancellables [ id, default: [ ] ] . insert (
72
- cancellationCancellable
73
- )
66
+ _cancellablesLock. sync {
67
+ _cancellationCancellables. insert ( cancellable, at: id)
74
68
}
75
69
} ,
76
- receiveCompletion: { _ in cancellationCancellable . cancel ( ) } ,
77
- receiveCancel: cancellationCancellable . cancel
70
+ receiveCompletion: { _ in cancellable . cancel ( ) } ,
71
+ receiveCancel: cancellable . cancel
78
72
)
79
73
}
80
74
. eraseToAnyPublisher ( )
@@ -113,7 +107,7 @@ extension EffectPublisher {
113
107
public static func cancel( id: AnyHashable ) -> Self {
114
108
. fireAndForget {
115
109
_cancellablesLock. sync {
116
- _cancellationCancellables [ . init ( id: id) ] ? . forEach { $0 . cancel ( ) }
110
+ _cancellationCancellables. cancel ( id: id)
117
111
}
118
112
}
119
113
}
@@ -201,22 +195,18 @@ extension EffectPublisher {
201
195
cancelInFlight: Bool = false ,
202
196
operation: @Sendable @escaping ( ) async throws -> T
203
197
) async rethrows -> T {
204
- let id = _CancelToken ( id: id)
205
198
let ( cancellable, task) = _cancellablesLock. sync { ( ) -> ( AnyCancellable , Task < T , Error > ) in
206
199
if cancelInFlight {
207
- _cancellationCancellables [ id ] ? . forEach { $0 . cancel ( ) }
200
+ _cancellationCancellables. cancel ( id : id )
208
201
}
209
202
let task = Task { try await operation ( ) }
210
203
let cancellable = AnyCancellable { task. cancel ( ) }
211
- _cancellationCancellables [ id , default : [ ] ] . insert ( cancellable)
204
+ _cancellationCancellables. insert ( cancellable, at : id )
212
205
return ( cancellable, task)
213
206
}
214
207
defer {
215
208
_cancellablesLock. sync {
216
- _cancellationCancellables [ id] ? . remove ( cancellable)
217
- if _cancellationCancellables [ id] ? . isEmpty == . some( true ) {
218
- _cancellationCancellables [ id] = nil
219
- }
209
+ _cancellationCancellables. remove ( cancellable, at: id)
220
210
}
221
211
}
222
212
do {
@@ -231,22 +221,18 @@ extension EffectPublisher {
231
221
cancelInFlight: Bool = false ,
232
222
operation: @Sendable @escaping ( ) async throws -> T
233
223
) async rethrows -> T {
234
- let id = _CancelToken ( id: id)
235
224
let ( cancellable, task) = _cancellablesLock. sync { ( ) -> ( AnyCancellable , Task < T , Error > ) in
236
225
if cancelInFlight {
237
- _cancellationCancellables [ id ] ? . forEach { $0 . cancel ( ) }
226
+ _cancellationCancellables. cancel ( id : id )
238
227
}
239
228
let task = Task { try await operation ( ) }
240
229
let cancellable = AnyCancellable { task. cancel ( ) }
241
- _cancellationCancellables [ id , default : [ ] ] . insert ( cancellable)
230
+ _cancellationCancellables. insert ( cancellable, at : id )
242
231
return ( cancellable, task)
243
232
}
244
233
defer {
245
234
_cancellablesLock. sync {
246
- _cancellationCancellables [ id] ? . remove ( cancellable)
247
- if _cancellationCancellables [ id] ? . isEmpty == . some( true ) {
248
- _cancellationCancellables [ id] = nil
249
- }
235
+ _cancellationCancellables. remove ( cancellable, at: id)
250
236
}
251
237
}
252
238
do {
@@ -301,7 +287,9 @@ extension Task where Success == Never, Failure == Never {
301
287
///
302
288
/// - Parameter id: An identifier.
303
289
public static func cancel< ID: Hashable & Sendable > ( id: ID ) {
304
- _cancellablesLock. sync { _cancellationCancellables [ . init( id: id) ] ? . forEach { $0. cancel ( ) } }
290
+ _cancellablesLock. sync {
291
+ _cancellationCancellables. cancel ( id: id)
292
+ }
305
293
}
306
294
307
295
/// Cancel any currently in-flight operation with the given identifier.
@@ -315,7 +303,7 @@ extension Task where Success == Never, Failure == Never {
315
303
}
316
304
}
317
305
318
- @_spi ( Internals) public struct _CancelToken : Hashable {
306
+ @_spi ( Internals) public struct _CancelID : Hashable {
319
307
let id : AnyHashable
320
308
let discriminator : ObjectIdentifier
321
309
@@ -325,8 +313,8 @@ extension Task where Success == Never, Failure == Never {
325
313
}
326
314
}
327
315
328
- @_spi ( Internals) public var _cancellationCancellables : [ _CancelToken : Set < AnyCancellable > ] = [ : ]
329
- @ _spi ( Internals ) public let _cancellablesLock = NSRecursiveLock ( )
316
+ @_spi ( Internals) public var _cancellationCancellables = CancellablesCollection ( )
317
+ private let _cancellablesLock = NSRecursiveLock ( )
330
318
331
319
@rethrows
332
320
private protocol _ErrorMechanism {
@@ -346,3 +334,41 @@ extension _ErrorMechanism {
346
334
}
347
335
348
336
extension Result : _ErrorMechanism { }
337
+
338
+ @_spi ( Internals)
339
+ public class CancellablesCollection {
340
+ var storage : [ _CancelID : Set < AnyCancellable > ] = [ : ]
341
+
342
+ func insert(
343
+ _ cancellable: AnyCancellable ,
344
+ at id: AnyHashable
345
+ ) {
346
+ let cancelID = _CancelID ( id: id)
347
+ self . storage [ cancelID, default: [ ] ] . insert ( cancellable)
348
+ }
349
+
350
+ func remove(
351
+ _ cancellable: AnyCancellable ,
352
+ at id: AnyHashable
353
+ ) {
354
+ let cancelID = _CancelID ( id: id)
355
+ self . storage [ cancelID] ? . remove ( cancellable)
356
+ if self . storage [ cancelID] ? . isEmpty == true {
357
+ self . storage [ cancelID] = nil
358
+ }
359
+ }
360
+
361
+ func cancel( id: AnyHashable ) {
362
+ let cancelID = _CancelID ( id: id)
363
+ self . storage [ cancelID] ? . forEach { $0. cancel ( ) }
364
+ self . storage [ cancelID] = nil
365
+ }
366
+
367
+ public func exists( at id: AnyHashable ) -> Bool {
368
+ return self . storage [ _CancelID ( id: id) ] != nil
369
+ }
370
+
371
+ public var count : Int {
372
+ return self . storage. count
373
+ }
374
+ }
0 commit comments