Releases: swhitty/swift-identifiable-continuation
0.6.0 Swift 6+
0.5.0 Rename swift-identifiable-continuation
Renames package to swift-identifiable-continuation
Usage is low so the impact should be minimal, GitHub will redirect but Package.swift will need to be updated.
0.4.0 Swift 6 Language Mode
Adds support for Swift 6 language mode when building with Xcode 16 (RC)
Uses variation of lock from swift-mutex
Swift 6 (Xcode 6 Beta 5)
Adds support for Swift 6, inheriting actor isolation through the new #isolation keyword (SE-420).
let val: String = await withIdentifiableContinuation {
continuations[$0.id] = $0
}Swift 5 must continuation to pass an isolated reference to the current actor.
let val: String = await withIdentifiableContinuation(isolation: self) {
continuations[$0.id] = $0
}Swift 6
Adds support for Swift 6, inheriting actor isolation through the new #isolation keyword (SE-420).
let val: String = await withIdentifiableContinuation {
continuations[$0.id] = $0
}Swift 5 must continuation to pass an isolated reference to the current actor.
let val: String = await withIdentifiableContinuation(isolation: self) {
continuations[$0.id] = $0
}Preserve calling #function
Preserves calling #function passing it to the inner CheckedContinuation allowing for better diagnostics.
Actor Isolation
Adds explicit actor isolation to ensure the closure is executed within the actors isolation:
let val: String = await withIdentifiableContinuation(isolation: self) {
$0.resume(returning: "bar")
}This allows actors to synchronously start continuations and mutate their isolated state before suspension occurs. The onCancel: handler is @Sendable and can be called at any time after the body has completed. Manually check Task.isCancelled before creating the continuation to prevent performing unrequired work.
let val: String = await withIdentifiableContinuation(isolation: self) {
// executed within actor isolation so can immediatley mutate actor state
continuations[$0.id] = $0
} onCancel: { id in
// @Sendable closure executed outside of actor isolation requires `await` to mutate actor state
Task { await self.cancelContinuation(with: id) }
}Previous versions used async closures and unstructured tasks to work with actors but SE-0420 Inheritance of Actor isolation includes the new #isolation keyword that will allow isolation: self to be automatically filled in by the compiler.
Async Handlers
Adds support for async closures, making it easy to store the continuations within an actor:
let val: String? = await withIdentifiableContinuation {
await someActor.insertContinuation($0)
} onCancel: {
await someActor.cancelContinuation(for: $0)
}The onCancel: handler is still guaranteed to be called after the continuation body executes to completion, even if the task is already cancelled.
Initial Release
IdentifiableContinuation is a lightweight wrapper around CheckedContinuation and UnsafeContinuation that conforms to Identifiable and including an easy to use cancellation handler with the id.
Usage is similar to existing continuations:
let val: String = await withIdentifiableContinuation {
$0.resume(returning: "bar")
}The continuation includes an id that can be attached to an asynchronous task enabling the onCancel handler to cancel it.
let val: String? = await withIdentifiableContinuation { continuation in
foo.startTask(for: continuation.id) { result
continuation.resume(returning: result)
}
} onCancel: { id in
foo.cancelTask(for: id)
}Initial Release
IdentifiableContinuation is a lightweight wrapper around CheckedContinuation and UnsafeContinuation that conforms to Identifiable and including an easy to use cancellation handler with the id.
Usage is similar to existing continuations:
let val: String = await withIdentifiableContinuation {
$0.resume(returning: "bar")
}The continuation includes an id that can be attached to an asynchronous task enabling the onCancel handler to cancel it.
let val: String? = await withIdentifiableContinuation { continuation in
foo.startTask(for: continuation.id) { result
continuation.resume(returning: result)
}
} onCancel: { id in
foo.cancelTask(for: id)
}