FWIW with SE-0420, we can now implement this using the latest toolchain:
func withCancellingContinuation<T>(
isolation: isolated (any Actor)? = #isolation,
operation: (CheckedContinuation<T, Error>) -> Void,
onCancel handler: @Sendable () -> Void
) async throws -> T {
try await withTaskCancellationHandler {
try await withCheckedThrowingContinuation { continuation in
_ = isolation
operation(continuation)
}
} onCancel: {
handler()
}
}
Note: current version requires caller to explicitly pass #isolation
:
try await withCancellingContinuation(isolation: #isolation) {
self.assertIsolated()
$0.resume()
} onCancel: {
print("🐟")
}