Skip to content

Releases: swhitty/IdentifiableContinuation

0.4.0 Swift 6 Language Mode

10 Sep 04:47
1a6d86a
Compare
Choose a tag to compare

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)

06 Aug 22:18
7981436
Compare
Choose a tag to compare

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

14 Jul 02:12
900560d
Compare
Choose a tag to compare

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

14 Apr 22:36
8ff767a
Compare
Choose a tag to compare

Preserves calling #function passing it to the inner CheckedContinuation allowing for better diagnostics.

Actor Isolation

11 Mar 06:21
de0b23e
Compare
Choose a tag to compare

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

24 May 22:34
73f0374
Compare
Choose a tag to compare

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

21 May 03:27
7d0b437
Compare
Choose a tag to compare

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

20 May 01:48
aad418d
Compare
Choose a tag to compare

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)
}