{"id":13995112,"url":"https://github.com/ChimeHQ/ConcurrencyPlus","last_synced_at":"2025-07-22T21:32:07.072Z","repository":{"id":40494628,"uuid":"507557164","full_name":"ChimeHQ/ConcurrencyPlus","owner":"ChimeHQ","description":"Utilities for working with Swift Concurrency","archived":true,"fork":false,"pushed_at":"2023-11-29T17:08:54.000Z","size":112,"stargazers_count":253,"open_issues_count":0,"forks_count":11,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-07-20T17:08:40.506Z","etag":null,"topics":["async","concurrency","ios","macos","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChimeHQ.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-06-26T11:36:40.000Z","updated_at":"2024-05-23T04:14:30.000Z","dependencies_parsed_at":"2023-11-29T18:28:36.465Z","dependency_job_id":"462de831-839e-410e-ae8a-e9dbc5294cba","html_url":"https://github.com/ChimeHQ/ConcurrencyPlus","commit_stats":{"total_commits":53,"total_committers":5,"mean_commits":10.6,"dds":0.09433962264150941,"last_synced_commit":"8dc56499412a373d617d50d059116bccf44b9874"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChimeHQ%2FConcurrencyPlus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChimeHQ%2FConcurrencyPlus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChimeHQ%2FConcurrencyPlus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChimeHQ%2FConcurrencyPlus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChimeHQ","download_url":"https://codeload.github.com/ChimeHQ/ConcurrencyPlus/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":214675465,"owners_count":15768156,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","concurrency","ios","macos","swift"],"created_at":"2024-08-09T14:03:15.437Z","updated_at":"2024-08-09T14:15:33.855Z","avatar_url":"https://github.com/ChimeHQ.png","language":"Swift","readme":"\u003cdiv align=\"center\"\u003e\n\n[![Build Status][build status badge]][build status]\n[![Platforms][platforms badge]][platforms]\n[![Documentation][documentation badge]][documentation]\n\n\u003c/div\u003e\n\n# ConcurrencyPlus\nUtilities for working with Swift Concurrency\n\n⚠️ Better, more-focused libraries have since been extracted from this one. ⚠️\n\n- For an async-compatible queue, check out [Queue](https://github.com/mattmassicotte/Queue)\n- For async support in XPC, try [AsyncXPCConnection](https://github.com/ChimeHQ/AsyncXPCConnection)\n- For help with MainActor stuff, see [MainOffender](https://github.com/mattmassicotte/MainOffender)\n\nThis is a really small library with some types and extensions that may be useful when working with Swift's concurrency system.\n\n- A `TaskQueue` for queuing tasks in FIFO ordering\n- `CheckedContinuation` extensions for improved ergonomics\n- `Task` extensions for improved ergonomics when used to bridge to non-async code\n- `NSXPCConnection` extensions for safe async integration\n- `MainActor.runUnsafely` to help work around incorrectly- or insufficiently-annotated code not under your control\n- `OwnershipTransferring` to move a non-Sendable value across actor boundaries\n- `SendableBox` to lie to the compiler about Sendable conformance\n- `RelaxedDispatchQueue` a very thin `DispatchQueue` wrapper with relaxed argument sendability constraints\n\n## TaskQueue\n\n```swift\nlet queue = TaskQueue()\n\nqueue.addOperation {\n    await asyncFunction()\n    await anotherAsyncFunction()\n}\n\n// This can can also return the underlying Task, so you can cancel, or await a value\nlet task = await queue.addOperation {\n    return await makeValue()\n}\n\nlet value = try await task.value\n```\n\n```swift\n// Without .ordered, the execution order of these tasks is not well-defined.\nTask.ordered {\n    event1()\n}\n\nTask.ordered(priority: .background) {\n    event2()\n}\n\nTask.ordered {\n    event3()\n}\n```\n\n## Task Ergonomics\n\nSome handy functions that ease integration with existing callbacks.\n\n```swift\nfunc callbackOptionalPair(_ block: @escaping (Int?, Error?) -\u003e Void) {\n    Task.relayResult(to: block) {\n        // ... return async value or throw...\n    }\n}\n\nfunc callbackResult(_ block: @escaping (Result\u003cInt, Error\u003e) -\u003e Void) {\n    Task.relayResult(to: block) {\n        // ... return async value or throw...\n    }\n}\n\nfunc callbackOptionalError(_ block: @escaping (Error?) -\u003e Void) {\n    Task.relayResult(to: block) {\n        // ... possibly throw...\n    }\n}\n```\n\n## OwnershipTransferring\n\nThis is a tool for moving a value across actor boundaries in a way that will keep the compiler happy. It is reasonably unsafe. You have to be very careful about how the moved value is accessed.\n\n```swift\nactor MyActor {\n    let nonSendable: UnsendableType\n\n    init(_ transfer: OwnershipTransferring\u003cUnsendableType\u003e) {\n        self.nonSendable = transfer.takeOwnership()\n    }\n}\n\nlet nonSendable = UnsendableType()\nlet transfer = OwnershipTransferring(nonSendable)\n\nlet myActor = MyActor(transfer) // no warnings!\n\ntransfer.hasOwnershipBeenTransferred() // true\ntransfer.takeOwnership() // this will crash\n```\n\n## RelaxedDispatchQueue\n\n`DispatchQueue` now has implicit `@Sendable` closure arguments. This is a highly-disruptive change, as it makes queues no longer feasible as a means of non-Sendable state protection. Wrap up that that queue and carry on.\n\n```swift\nlet nonSendable = UnsendableType()\nlet queue = RelaxedDisptachQueue(label: \"myqueue\")\n\nqueue.async {\n    nonSendable.doThing() // no warnings\n}\n```\n\n## Working with XPC\n\nYou might be tempted to make your XPC interface functions `async`. This approach does not handle connection failures and will violate the Structured Concurrency contract, resulting in hangs. See the post [\"ExtensionKit and XPC\"](https://www.chimehq.com/blog/extensionkit-xpc) for context.\n\nThis little `NSXPCConnection` extension provides a safe way to get into the async world.\n\n```swift\nfunc withContinuation\u003cService, T\u003e(\n    function: String = #function, \n    _ body: (Service, CheckedContinuation\u003cT, Error\u003e) -\u003e Void\n) async throws -\u003e T\n```\n\nThere are also some extensions on `CheckedContinuation` to make it easier to use in the context of XPC. These are really handy for resuming from common reply patterns.\n\nGiven an XPC service like this in your code:\n\n```swift\nprotocol XPCService {\n    func errorMethod(reply: (Error?) -\u003e Void)\n    func valueAndErrorMethod(reply: (String?, Error?) -\u003e Void)\n    func dataAndErrorMethod(reply: (Data?, Error?) -\u003e Void)\n}\n```\n\nThe continuation helpers allow bridging like:\n\n```swift\ntry await withContinuation { service, continuation in\n    service.errorMethod(reply: continuation.resumingHandler)\n}\n\ntry await withContinuation { service, continuation in\n    service.valueAndErrorMethod(reply: continuation.resumingHandler)\n}\n\n// this one will try to use JSONDecoder on the resulting data\ntry await withContinuation { service, continuation in\n    service.dataAndErrorMethod(reply: continuation.resumingHandler)\n}\n```\n\n## Other Useful Projects\n\nThese libraries might be useful and are definitely worth checking out as well.\n\n- [AnyAsyncSequence](https://github.com/vsanthanam/AnyAsyncSequence): super-focused on addressing the lack of type-erased sequences\n- [AsyncAlgorithms](https://github.com/apple/swift-async-algorithms): Apple-owned reactive extensions to `AsyncSequence`\n- [AsyncExtensions](https://github.com/sideeffect-io/AsyncExtensions): Companion to AsyncAlgorithms to add additional reactive features\n- [Asynchrone](https://github.com/reddavis/Asynchrone): Extensions to bring reactive features to `AsyncSequence`\n\n## Suggestions or Feedback\n\nWe'd love to hear from you! Please open up an issue or pull request.\n\nPlease note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.\n\n[build status]: https://github.com/ChimeHQ/ConcurrencyPlus/actions\n[build status badge]: https://github.com/ChimeHQ/ConcurrencyPlus/workflows/CI/badge.svg\n[license]: https://opensource.org/licenses/BSD-3-Clause\n[license badge]: https://img.shields.io/github/license/ChimeHQ/ConcurrencyPlus\n[platforms]: https://swiftpackageindex.com/ChimeHQ/ConcurrencyPlus\n[platforms badge]: https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FChimeHQ%2FConcurrencyPlus%2Fbadge%3Ftype%3Dplatforms\n[documentation]: https://swiftpackageindex.com/ChimeHQ/ConcurrencyPlus/main/documentation\n[documentation badge]: https://img.shields.io/badge/Documentation-DocC-blue\n","funding_links":[],"categories":["Swift"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FChimeHQ%2FConcurrencyPlus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FChimeHQ%2FConcurrencyPlus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FChimeHQ%2FConcurrencyPlus/lists"}