Skip to content

Commit 6c67658

Browse files
mbrandonwp4checo
authored andcommitted
Add @_unsafeInheritExecutor to withTaskCancellation(id:) (#1779)
* Add @_unsafeInheritExecutor to withTaskCancellation(id:) * wip (cherry picked from commit 48f0cc66000a23690ebbd7b65ea57fb7e7769825) # Conflicts: # Package.resolved # Sources/ComposableArchitecture/Effects/Cancellation.swift
1 parent 6895873 commit 6c67658

File tree

1 file changed

+51
-3
lines changed

1 file changed

+51
-3
lines changed

Sources/ComposableArchitecture/Effects/Cancellation.swift

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ extension EffectProducer {
7676
}
7777
}
7878

79-
_cancellationCancellables[id, default: []].insert(
79+
_cancellationCancellables[id, default: []].insert(
8080
cancellationDisposable
81-
)
81+
)
8282

8383
return SignalProducer(values.value)
8484
.concat(subject.output.producer)
@@ -164,6 +164,7 @@ extension EffectProducer {
164164
}
165165
}
166166

167+
#if swift(>=5.7)
167168
/// Execute an operation with a cancellation identifier.
168169
///
169170
/// If the operation is in-flight when `Task.cancel(id:)` is called with the same identifier, the
@@ -206,13 +207,44 @@ extension EffectProducer {
206207
/// - operation: An async operation.
207208
/// - Throws: An error thrown by the operation.
208209
/// - Returns: A value produced by operation.
210+
@_unsafeInheritExecutor
209211
public func withTaskCancellation<T: Sendable>(
210212
id: AnyHashable,
211213
cancelInFlight: Bool = false,
212214
operation: @Sendable @escaping () async throws -> T
213215
) async rethrows -> T {
214216
let id = _CancelToken(id: id)
215-
let (cancellable, task) = _cancellablesLock.sync { () -> (AnyDisposable, Task<T, Error>) in
217+
let (cancellable, task) = _cancellablesLock.sync { () -> (AnyDisposable, Task<T, Error>) in
218+
if cancelInFlight {
219+
_cancellationCancellables[id]?.forEach { $0.dispose() }
220+
}
221+
let task = Task { try await operation() }
222+
let cancellable = AnyDisposable { task.cancel() }
223+
_cancellationCancellables[id, default: []].insert(cancellable)
224+
return (cancellable, task)
225+
}
226+
defer {
227+
_cancellablesLock.sync {
228+
_cancellationCancellables[id]?.remove(cancellable)
229+
if _cancellationCancellables[id]?.isEmpty == .some(true) {
230+
_cancellationCancellables[id] = nil
231+
}
232+
}
233+
}
234+
do {
235+
return try await task.cancellableValue
236+
} catch {
237+
return try Result<T, Error>.failure(error)._rethrowGet()
238+
}
239+
}
240+
#else
241+
public func withTaskCancellation<T: Sendable>(
242+
id: AnyHashable,
243+
cancelInFlight: Bool = false,
244+
operation: @Sendable @escaping () async throws -> T
245+
) async rethrows -> T {
246+
let id = _CancelToken(id: id)
247+
let (cancellable, task) = _cancellablesLock.sync { () -> (AnyDisposable, Task<T, Error>) in
216248
if cancelInFlight {
217249
_cancellationCancellables[id]?.forEach { $0.dispose() }
218250
}
@@ -235,7 +267,9 @@ public func withTaskCancellation<T: Sendable>(
235267
return try Result<T, Error>.failure(error)._rethrowGet()
236268
}
237269
}
270+
#endif
238271

272+
#if swift(>=5.7)
239273
/// Execute an operation with a cancellation identifier.
240274
///
241275
/// A convenience for calling ``withTaskCancellation(id:cancelInFlight:operation:)-4dtr6`` with a
@@ -248,6 +282,7 @@ public func withTaskCancellation<T: Sendable>(
248282
/// - operation: An async operation.
249283
/// - Throws: An error thrown by the operation.
250284
/// - Returns: A value produced by operation.
285+
@_unsafeInheritExecutor
251286
public func withTaskCancellation<T: Sendable>(
252287
id: Any.Type,
253288
cancelInFlight: Bool = false,
@@ -259,6 +294,19 @@ public func withTaskCancellation<T: Sendable>(
259294
operation: operation
260295
)
261296
}
297+
#else
298+
public func withTaskCancellation<T: Sendable>(
299+
id: Any.Type,
300+
cancelInFlight: Bool = false,
301+
operation: @Sendable @escaping () async throws -> T
302+
) async rethrows -> T {
303+
try await withTaskCancellation(
304+
id: ObjectIdentifier(id),
305+
cancelInFlight: cancelInFlight,
306+
operation: operation
307+
)
308+
}
309+
#endif
262310

263311
extension Task where Success == Never, Failure == Never {
264312
/// Cancel any currently in-flight operation with the given identifier.

0 commit comments

Comments
 (0)