diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d3550a..7132576 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: ruby-version: '3.3.5' bundler-cache: true - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_16.4.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_26.1.1.app/Contents/Developer - name: Download visionOS run: | sudo xcodebuild -runFirstLaunch @@ -31,15 +31,15 @@ jobs: sudo xcodebuild -downloadPlatform visionOS sudo xcodebuild -runFirstLaunch - name: Lint Podspec - run: bundle exec pod lib lint --verbose --fail-fast --swift-version=6.0 + run: bundle exec pod lib lint --verbose --fail-fast --swift-version=6.2 spm-16: - name: Build Xcode 16 + name: Build Xcode 26 runs-on: macos-15 strategy: matrix: platforms: [ 'iOS_18,watchOS_11', - 'macOS_15,tvOS_18', + 'macOS_26,tvOS_18', 'visionOS_2' ] fail-fast: false @@ -53,7 +53,7 @@ jobs: ruby-version: '3.3.5' bundler-cache: true - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_16.4.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_26.1.1.app/Contents/Developer - name: Download visionOS if: matrix.platforms == 'visionOS_2' run: | @@ -72,7 +72,7 @@ jobs: fail_ci_if_error: true verbose: true spm-16-swift: - name: Swift Build Xcode 16 + name: Swift Build Xcode 26 runs-on: macos-15 permissions: contents: read @@ -84,37 +84,13 @@ jobs: ruby-version: '3.3.5' bundler-cache: true - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_16.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_26.1.1.app/Contents/Developer - name: Build and Test Framework run: xcrun swift test -c release -Xswiftc -enable-testing - linux-6-0: - name: "Build and Test on Linux Swift 6.0" + linux-6-2: + name: "Build and Test on Linux Swift 6.2" runs-on: ubuntu-24.04 - container: swift:6.0 - permissions: - contents: read - steps: - - name: Checkout Repo - uses: actions/checkout@v5 - - name: Build and Test Framework - run: swift test -c release --enable-code-coverage -Xswiftc -enable-testing - - name: Prepare Coverage Reports - run: | - llvm-cov export -format="lcov" .build/x86_64-unknown-linux-gnu/release/swift-async-queuePackageTests.xctest -instr-profile .build/x86_64-unknown-linux-gnu/release/codecov/default.profdata > coverage.lcov - - name: Install curl for Codecov - run: | - apt-get update - apt-get install -y --no-install-recommends curl ca-certificates - - name: Upload Coverage Reports - if: success() - uses: codecov/codecov-action@v5 - with: - fail_ci_if_error: true - verbose: true - linux-6-1: - name: "Build and Test on Linux Swift 6.1" - runs-on: ubuntu-24.04 - container: swift:6.1 + container: swift:6.2 permissions: contents: read steps: @@ -148,7 +124,7 @@ jobs: lint-swift: name: Lint Swift runs-on: ubuntu-latest - container: swift:6.0 + container: swift:6.2 permissions: contents: read steps: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f16c3ff..ca4e178 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -40,7 +40,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v5 - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_16.4.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_26.1.1.app/Contents/Developer # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.swiftformat b/.swiftformat index 7cd7eb1..05d8160 100644 --- a/.swiftformat +++ b/.swiftformat @@ -1,5 +1,7 @@ # format options --indent tab +--tab-width 4 +--smart-tabs disabled --modifierorder nonisolated,open,public,internal,fileprivate,private,private(set),final,override,required,convenience --ranges no-space --extensionacl on-declarations @@ -8,6 +10,7 @@ --storedvarattrs same-line --hexgrouping none --decimalgrouping 3 +--trailing-commas always # rules --enable isEmpty @@ -17,4 +20,4 @@ --disable blankLineAfterSwitchCase # global ---swiftversion 6.0 +--swiftversion 6.2 diff --git a/AsyncQueue.podspec b/AsyncQueue.podspec index 59806d9..495eff7 100644 --- a/AsyncQueue.podspec +++ b/AsyncQueue.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |s| s.name = 'AsyncQueue' - s.version = '0.7.2' + s.version = '1.0.0' s.license = 'MIT' s.summary = 'A queue that enables ordered sending of events from synchronous to asynchronous code.' s.homepage = 'https://github.com/dfed/swift-async-queue' s.authors = 'Dan Federman' s.source = { :git => 'https://github.com/dfed/swift-async-queue.git', :tag => s.version } - s.swift_version = '6.0' + s.swift_version = '6.2' s.source_files = 'Sources/**/*.{swift}' s.ios.deployment_target = '13.0' s.tvos.deployment_target = '13.0' diff --git a/CLI/Package.resolved b/CLI/Package.resolved index bd44c6f..da9defb 100644 --- a/CLI/Package.resolved +++ b/CLI/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "b2996d8b20521bfede6aa79472b75c70d7ac765721c6e529be7f5e3dc3d95b1d", + "originHash" : "68099791c3b1055022fb878528fe59c819641e12e52b565f7d561a2dc0c1c5f0", "pins" : [ { "identity" : "swiftformat", "kind" : "remoteSourceControl", "location" : "https://github.com/nicklockwood/SwiftFormat", "state" : { - "revision" : "1d02d0f54a5123c3ef67084b318f4421427b7a51", - "version" : "0.56.2" + "revision" : "e6fe3e445b95bca110da34e42c15d7c23ecef29a", + "version" : "0.58.6" } } ], diff --git a/CLI/Package.swift b/CLI/Package.swift index f536f52..caf3e61 100644 --- a/CLI/Package.swift +++ b/CLI/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 6.0 +// swift-tools-version: 6.2 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -12,5 +12,5 @@ let package = Package( dependencies: [ .package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.56.1"), ], - targets: [] + targets: [], ) diff --git a/Package.swift b/Package.swift index d3ef00f..236fe4f 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 6.0 +// swift-tools-version: 6.2 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -16,7 +16,7 @@ let package = Package( products: [ .library( name: "AsyncQueue", - targets: ["AsyncQueue"] + targets: ["AsyncQueue"], ), ], targets: [ @@ -25,14 +25,16 @@ let package = Package( dependencies: [], swiftSettings: [ .swiftLanguageMode(.v6), - ] + .treatAllWarnings(as: .error), + ], ), .testTarget( name: "AsyncQueueTests", dependencies: ["AsyncQueue"], swiftSettings: [ .swiftLanguageMode(.v6), - ] + .treatAllWarnings(as: .error), + ], ), - ] + ], ) diff --git a/README.md b/README.md index cfe3177..755654c 100644 --- a/README.md +++ b/README.md @@ -241,7 +241,7 @@ To install swift-async-queue in your project with [Swift Package Manager](https: ```swift dependencies: [ - .package(url: "https://github.com/dfed/swift-async-queue", from: "0.7.0"), + .package(url: "https://github.com/dfed/swift-async-queue", from: "1.0.0"), ] ``` @@ -250,7 +250,7 @@ dependencies: [ To install swift-async-queue in your project with [CocoaPods](https://blog.cocoapods.org/CocoaPods-Specs-Repo), add the following to your `Podfile`: ``` -pod 'AsyncQueue', '~> 0.7.0' +pod 'AsyncQueue', '~> 1.0.0' ``` ## Contributing diff --git a/Scripts/build.swift b/Scripts/build.swift index 2412713..3af8069 100755 --- a/Scripts/build.swift +++ b/Scripts/build.swift @@ -23,7 +23,7 @@ enum TaskError: Error { enum Platform: String, CaseIterable, CustomStringConvertible { case iOS_18 case tvOS_18 - case macOS_15 + case macOS_26 case macCatalyst_15 case watchOS_11 case visionOS_2 @@ -36,8 +36,8 @@ enum Platform: String, CaseIterable, CustomStringConvertible { case .tvOS_18: "platform=tvOS Simulator,OS=18.5,name=Apple TV" - case .macOS_15, - .macCatalyst_15: + case .macOS_26, + .macCatalyst_15: "platform=OS X" case .watchOS_11: @@ -56,9 +56,9 @@ enum Platform: String, CaseIterable, CustomStringConvertible { case .tvOS_18: "appletvsimulator" - case .macOS_15, - .macCatalyst_15: - "macosx15.5" + case .macOS_26, + .macCatalyst_15: + "macosx26.1" case .watchOS_11: "watchsimulator" diff --git a/Sources/AsyncQueue/ActorQueue.swift b/Sources/AsyncQueue/ActorQueue.swift index 575310a..82c3d40 100644 --- a/Sources/AsyncQueue/ActorQueue.swift +++ b/Sources/AsyncQueue/ActorQueue.swift @@ -102,7 +102,7 @@ public final class ActorQueue: @unchecked Sendable { fileprivate struct ActorTask: Sendable { init( executionContext: ActorType, - task: @escaping @Sendable (isolated ActorType) async -> Void + task: @escaping @Sendable (isolated ActorType) async -> Void, ) { self.executionContext = executionContext self.task = task @@ -152,7 +152,7 @@ extension Task { public init( priority: TaskPriority? = nil, on actorQueue: ActorQueue, - operation: @Sendable @escaping (isolated ActorType) async -> Success + operation: @Sendable @escaping (isolated ActorType) async -> Success, ) where Failure == Never { let delivery = Delivery() let semaphore = Semaphore() @@ -163,7 +163,7 @@ extension Task { delivery.execute({ @Sendable executionContext in await delivery.sendValue(operation(executionContext)) }, in: executionContext, priority: priority) - } + }, ) actorQueue.taskStreamContinuation.yield(task) self.init(priority: priority) { @@ -172,7 +172,7 @@ extension Task { await semaphore.signal() return await delivery.getValue() }, - onCancel: delivery.cancel + onCancel: delivery.cancel, ) } } @@ -207,7 +207,7 @@ extension Task { public init( priority: TaskPriority? = nil, on actorQueue: ActorQueue, - operation: @escaping @Sendable (isolated ActorType) async throws -> Success + operation: @escaping @Sendable (isolated ActorType) async throws -> Success, ) where Failure == any Error { let delivery = Delivery() let semaphore = Semaphore() @@ -222,7 +222,7 @@ extension Task { await delivery.sendFailure(error) } }, in: executionContext, priority: priority) - } + }, ) actorQueue.taskStreamContinuation.yield(task) self.init(priority: priority) { @@ -231,7 +231,7 @@ extension Task { await semaphore.signal() return try await delivery.getValue() }, - onCancel: delivery.cancel + onCancel: delivery.cancel, ) } } @@ -266,7 +266,7 @@ extension Task { public init( priority: TaskPriority? = nil, on actorQueue: ActorQueue, - operation: @MainActor @escaping () async -> Success + operation: @MainActor @escaping () async -> Success, ) where Failure == Never { let delivery = Delivery() let semaphore = Semaphore() @@ -277,7 +277,7 @@ extension Task { delivery.execute({ @Sendable executionContext in await delivery.sendValue(operation()) }, in: executionContext, priority: priority) - } + }, ) actorQueue.taskStreamContinuation.yield(task) self.init(priority: priority) { @@ -286,7 +286,7 @@ extension Task { await semaphore.signal() return await delivery.getValue() }, - onCancel: delivery.cancel + onCancel: delivery.cancel, ) } } @@ -321,7 +321,7 @@ extension Task { public init( priority: TaskPriority? = nil, on actorQueue: ActorQueue, - operation: @escaping @MainActor () async throws -> Success + operation: @escaping @MainActor () async throws -> Success, ) where Failure == any Error { let delivery = Delivery() let semaphore = Semaphore() @@ -336,7 +336,7 @@ extension Task { await delivery.sendFailure(error) } }, in: executionContext, priority: priority) - } + }, ) actorQueue.taskStreamContinuation.yield(task) self.init(priority: priority) { @@ -345,7 +345,7 @@ extension Task { await semaphore.signal() return try await delivery.getValue() }, - onCancel: delivery.cancel + onCancel: delivery.cancel, ) } } diff --git a/Sources/AsyncQueue/CancellableQueue.swift b/Sources/AsyncQueue/CancellableQueue.swift index 3346105..b5c3209 100644 --- a/Sources/AsyncQueue/CancellableQueue.swift +++ b/Sources/AsyncQueue/CancellableQueue.swift @@ -76,7 +76,7 @@ extension Task { public init( priority: TaskPriority? = nil, on actorQueue: CancellableQueue>, - operation: @Sendable @escaping (isolated ActorType) async -> Success + operation: @Sendable @escaping (isolated ActorType) async -> Success, ) where Failure == Never { let identifier = UUID() self.init(priority: priority, on: actorQueue.underlyingQueue, operation: { @@ -116,7 +116,7 @@ extension Task { public init( priority: TaskPriority? = nil, on actorQueue: CancellableQueue>, - operation: @escaping @Sendable (isolated ActorType) async throws -> Success + operation: @escaping @Sendable (isolated ActorType) async throws -> Success, ) where Failure == any Error { let identifier = UUID() self.init(priority: priority, on: actorQueue.underlyingQueue, operation: { @@ -156,7 +156,7 @@ extension Task { public init( priority: TaskPriority? = nil, on actorQueue: CancellableQueue>, - operation: @MainActor @escaping () async -> Success + operation: @MainActor @escaping () async -> Success, ) where Failure == Never { let identifier = UUID() self.init(priority: priority, on: actorQueue.underlyingQueue, operation: { @@ -196,7 +196,7 @@ extension Task { public init( priority: TaskPriority? = nil, on actorQueue: CancellableQueue>, - operation: @escaping @MainActor () async throws -> Success + operation: @escaping @MainActor () async throws -> Success, ) where Failure == any Error { let identifier = UUID() self.init(priority: priority, on: actorQueue.underlyingQueue, operation: { @@ -233,7 +233,7 @@ extension Task { @discardableResult public init( on fifoQueue: CancellableQueue, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success, ) where Failure == Never { let identifier = UUID() self.init(on: fifoQueue.underlyingQueue, operation: { @@ -270,7 +270,7 @@ extension Task { @discardableResult public init( on fifoQueue: CancellableQueue, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success, ) where Failure == any Error { let identifier = UUID() self.init(on: fifoQueue.underlyingQueue, operation: { @@ -312,7 +312,7 @@ extension Task { priority: TaskPriority? = nil, on fifoQueue: CancellableQueue, isolatedTo isolatedActor: ActorType, - operation: @Sendable @escaping (isolated ActorType) async -> Success + operation: @Sendable @escaping (isolated ActorType) async -> Success, ) where Failure == Never { let identifier = UUID() self.init(priority: priority, on: fifoQueue.underlyingQueue, isolatedTo: isolatedActor, operation: { @@ -354,7 +354,7 @@ extension Task { priority: TaskPriority? = nil, on fifoQueue: CancellableQueue, isolatedTo isolatedActor: ActorType, - operation: @Sendable @escaping (isolated ActorType) async throws -> Success + operation: @Sendable @escaping (isolated ActorType) async throws -> Success, ) where Failure == any Error { let identifier = UUID() self.init(priority: priority, on: fifoQueue.underlyingQueue, isolatedTo: isolatedActor, operation: { diff --git a/Sources/AsyncQueue/FIFOQueue.swift b/Sources/AsyncQueue/FIFOQueue.swift index d9dee23..194fc37 100644 --- a/Sources/AsyncQueue/FIFOQueue.swift +++ b/Sources/AsyncQueue/FIFOQueue.swift @@ -84,7 +84,7 @@ extension Task { @discardableResult public init( on fifoQueue: FIFOQueue, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async -> Success, ) where Failure == Never { let delivery = Delivery() let semaphore = Semaphore() @@ -102,7 +102,7 @@ extension Task { await semaphore.signal() return await delivery.getValue() }, - onCancel: delivery.cancel + onCancel: delivery.cancel, ) } } @@ -134,7 +134,7 @@ extension Task { @discardableResult public init( on fifoQueue: FIFOQueue, - @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success + @_inheritActorContext @_implicitSelfCapture operation: sending @escaping @isolated(any) () async throws -> Success, ) where Failure == any Error { let delivery = Delivery() let semaphore = Semaphore() @@ -156,7 +156,7 @@ extension Task { await semaphore.signal() return try await delivery.getValue() }, - onCancel: delivery.cancel + onCancel: delivery.cancel, ) } } @@ -193,7 +193,7 @@ extension Task { priority: TaskPriority? = nil, on fifoQueue: FIFOQueue, isolatedTo isolatedActor: ActorType, - operation: @Sendable @escaping (isolated ActorType) async -> Success + operation: @Sendable @escaping (isolated ActorType) async -> Success, ) where Failure == Never { let delivery = Delivery() let semaphore = Semaphore() @@ -210,7 +210,7 @@ extension Task { await semaphore.signal() return await delivery.getValue() }, - onCancel: delivery.cancel + onCancel: delivery.cancel, ) } } @@ -247,7 +247,7 @@ extension Task { priority: TaskPriority? = nil, on fifoQueue: FIFOQueue, isolatedTo isolatedActor: ActorType, - operation: @Sendable @escaping (isolated ActorType) async throws -> Success + operation: @Sendable @escaping (isolated ActorType) async throws -> Success, ) where Failure == any Error { let delivery = Delivery() let semaphore = Semaphore() @@ -268,7 +268,7 @@ extension Task { await semaphore.signal() return try await delivery.getValue() }, - onCancel: delivery.cancel + onCancel: delivery.cancel, ) } } diff --git a/Sources/AsyncQueue/Utilities/Delivery.swift b/Sources/AsyncQueue/Utilities/Delivery.swift index 3ce6d4a..bae0655 100644 --- a/Sources/AsyncQueue/Utilities/Delivery.swift +++ b/Sources/AsyncQueue/Utilities/Delivery.swift @@ -31,8 +31,7 @@ actor Delivery { self.failure = failure } - nonisolated - func cancel() { + nonisolated func cancel() { taskContainer.withLock { $0.isCancelled = true $0.task?.cancel() @@ -43,7 +42,7 @@ actor Delivery { func execute( _ operation: sending @escaping (isolated ActorType) async -> Void, in context: isolated ActorType, - priority: TaskPriority? = nil + priority: TaskPriority? = nil, ) -> Task { // In Swift 6, a `Task` enqueued from an actor begins executing immediately on that actor. // Since we're running on our actor's context already, we can just dispatch a Task to get first-enqueued-first-start task execution. diff --git a/Tests/AsyncQueueTests/ExpectationTests.swift b/Tests/AsyncQueueTests/ExpectationTests.swift index 376f58f..eb3cbc1 100644 --- a/Tests/AsyncQueueTests/ExpectationTests.swift +++ b/Tests/AsyncQueueTests/ExpectationTests.swift @@ -33,7 +33,7 @@ struct ExpectationTests { expect: { expectation, _, _ in #expect(expectation) confirmation() - } + }, ) await systemUnderTest.fulfill().value } @@ -47,7 +47,7 @@ struct ExpectationTests { expect: { expectation, _, _ in #expect(expectation) confirmation() - } + }, ) await systemUnderTest.fulfill().value await systemUnderTest.fulfill().value @@ -62,7 +62,7 @@ struct ExpectationTests { expect: { expectation, _, _ in #expect(!expectation) confirmation() - } + }, ) await systemUnderTest.fulfill().value } @@ -98,7 +98,7 @@ struct ExpectationTests { expect: { expectation, _, _ in #expect(!expectation) confirmation() - } + }, ) await systemUnderTest.fulfillment(withinSeconds: 0) } diff --git a/Tests/AsyncQueueTests/Utilities/Counter.swift b/Tests/AsyncQueueTests/Utilities/Counter.swift index 8ac2e78..fa13d87 100644 --- a/Tests/AsyncQueueTests/Utilities/Counter.swift +++ b/Tests/AsyncQueueTests/Utilities/Counter.swift @@ -28,14 +28,14 @@ actor Counter { filePath: String = #filePath, fileID: String = #fileID, line: Int = #line, - column: Int = #column + column: Int = #column, ) { increment() #expect(expectedCount == count, sourceLocation: .init( fileID: fileID, filePath: filePath, line: line, - column: column + column: column, )) } diff --git a/Tests/AsyncQueueTests/Utilities/Expectation.swift b/Tests/AsyncQueueTests/Utilities/Expectation.swift index a6073de..4fc245e 100644 --- a/Tests/AsyncQueueTests/Utilities/Expectation.swift +++ b/Tests/AsyncQueueTests/Utilities/Expectation.swift @@ -26,17 +26,17 @@ public actor Expectation { // MARK: Initialization public init( - expectedCount: UInt = 1 + expectedCount: UInt = 1, ) { self.init( expectedCount: expectedCount, - expect: { #expect($0, $1, sourceLocation: $2) } + expect: { #expect($0, $1, sourceLocation: $2) }, ) } init( expectedCount: UInt, - expect: @escaping (Bool, Comment?, SourceLocation) -> Void + expect: @escaping (Bool, Comment?, SourceLocation) -> Void, ) { self.expectedCount = expectedCount self.expect = expect @@ -49,7 +49,7 @@ public actor Expectation { filePath: String = #filePath, fileID: String = #fileID, line: Int = #line, - column: Int = #column + column: Int = #column, ) async { guard !isComplete else { return } let wait = Task { @@ -58,7 +58,7 @@ public actor Expectation { fileID: fileID, filePath: filePath, line: line, - column: column + column: column, )) } waits.append(wait) @@ -66,19 +66,18 @@ public actor Expectation { } @discardableResult - nonisolated - public func fulfill( + nonisolated public func fulfill( filePath: String = #filePath, fileID: String = #fileID, line: Int = #line, - column: Int = #column + column: Int = #column, ) -> Task { Task { await self._fulfill( filePath: filePath, fileID: fileID, line: line, - column: column + column: column, ) } } @@ -98,7 +97,7 @@ public actor Expectation { filePath: String, fileID: String, line: Int, - column: Int + column: Int, ) { fulfillCount += 1 guard isComplete else { return } @@ -109,8 +108,8 @@ public actor Expectation { fileID: fileID, filePath: filePath, line: line, - column: column - ) + column: column, + ), ) for wait in waits { wait.cancel()