diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4356a9c..e96a1f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,45 +16,45 @@ concurrency: jobs: library: name: macOS + runs-on: macos-14 strategy: matrix: - xcode: ['14.3.1'] + xcode: ['15.4'] config: ['debug', 'release'] - runs-on: macos-13 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Select Xcode ${{ matrix.xcode }} run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app - name: Run ${{ matrix.config }} tests run: CONFIG=${{ matrix.config }} make test linux: - name: Linux + name: Linux (Swift ${{ matrix.swift }}) + runs-on: ubuntu-latest strategy: matrix: - os: [ubuntu-20.04] config: ['debug', 'release'] - runs-on: ${{ matrix.os }} + swift: + - '5.10' + container: swift:${{ matrix.swift }} steps: - - uses: actions/checkout@v3 - - name: Build - run: swift build + - uses: actions/checkout@v4 - name: Run tests run: swift test -c ${{ matrix.config }} wasm: - name: Wasm - runs-on: ubuntu-latest - strategy: - matrix: - include: - - { toolchain: wasm-5.7.1-RELEASE } - steps: - - uses: actions/checkout@v3 - - run: echo "${{ matrix.toolchain }}" > .swift-version - - uses: swiftwasm/swiftwasm-action@v5.7 - with: - shell-action: carton test --environment node + name: Wasm + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: bytecodealliance/actions/wasmtime/setup@v1 + - uses: swiftwasm/setup-swiftwasm@v1 + with: + swift-version: "wasm-5.9.2-RELEASE" + - name: Build tests + run: swift build --triple wasm32-unknown-wasi --build-tests + - name: Run tests + run: wasmtime --dir . .build/debug/swift-concurrency-extrasPackageTests.wasm windows: name: Windows @@ -66,9 +66,9 @@ jobs: steps: - uses: compnerd/gha-setup-swift@main with: - branch: swift-5.8-release - tag: 5.8-RELEASE + branch: swift-5.10-release + tag: 5.10-RELEASE - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run tests run: swift build -c ${{ matrix.config }} diff --git a/Package.swift b/Package.swift index f1d0fb0..1bec85e 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.6 +// swift-tools-version: 5.9 import PackageDescription @@ -36,14 +36,9 @@ let package = Package( ) #endif -//for target in package.targets { -// target.swiftSettings = target.swiftSettings ?? [] -// target.swiftSettings?.append( -// .unsafeFlags([ -// "-c", "release", -// "-emit-module-interface", "-enable-library-evolution", -// "-Xfrontend", "-warn-concurrency", -// "-Xfrontend", "-enable-actor-data-race-checks", -// ]) -// ) -//} +for target in package.targets { + target.swiftSettings = target.swiftSettings ?? [] + target.swiftSettings!.append(contentsOf: [ + .enableExperimentalFeature("StrictConcurrency") + ]) +} diff --git a/Package@swift-6.0.swift b/Package@swift-6.0.swift new file mode 100644 index 0000000..6eb7001 --- /dev/null +++ b/Package@swift-6.0.swift @@ -0,0 +1,37 @@ +// swift-tools-version: 6.0 + +import PackageDescription + +let package = Package( + name: "swift-concurrency-extras", + platforms: [ + .iOS(.v13), + .macOS(.v10_15), + .tvOS(.v13), + .watchOS(.v6), + ], + products: [ + .library( + name: "ConcurrencyExtras", + targets: ["ConcurrencyExtras"] + ) + ], + targets: [ + .target( + name: "ConcurrencyExtras" + ), + .testTarget( + name: "ConcurrencyExtrasTests", + dependencies: [ + "ConcurrencyExtras" + ] + ), + ] +) + +#if !os(Windows) + // Add the documentation compiler plugin if possible + package.dependencies.append( + .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0") + ) +#endif diff --git a/Sources/ConcurrencyExtras/AsyncStream.swift b/Sources/ConcurrencyExtras/AsyncStream.swift index 6dfa2ea..d547647 100644 --- a/Sources/ConcurrencyExtras/AsyncStream.swift +++ b/Sources/ConcurrencyExtras/AsyncStream.swift @@ -65,66 +65,6 @@ extension AsyncStream { } } - #if swift(<5.9) - /// Constructs and returns a stream along with its backing continuation. - /// - /// A back-port of [SE-0388: Convenience Async[Throwing]Stream.makeStream methods][se-0388]. - /// - /// This is handy for immediately escaping the continuation from an async stream, which - /// typically requires multiple steps: - /// - /// ```swift - /// var _continuation: AsyncStream.Continuation! - /// let stream = AsyncStream { continuation = $0 } - /// let continuation = _continuation! - /// - /// // vs. - /// - /// let (stream, continuation) = AsyncStream.makeStream(of: Int.self) - /// ``` - /// - /// This tool is usually used for tests where we need to supply an async sequence to a - /// dependency endpoint and get access to its continuation so that we can emulate the dependency - /// emitting data. For example, suppose you have a dependency exposing an async sequence for - /// listening to notifications. To test this you can use `makeStream`: - /// - /// ```swift - /// func testScreenshots() { - /// let screenshots = AsyncStream.makeStream(of: Void.self) - /// - /// let model = withDependencies { - /// $0.screenshots = { screenshots.stream } - /// } operation: { - /// FeatureModel() - /// } - /// - /// XCTAssertEqual(model.screenshotCount, 0) - /// screenshots.continuation.yield() // Simulate a screenshot being taken. - /// XCTAssertEqual(model.screenshotCount, 1) - /// } - /// ``` - /// - /// > Warning: ⚠️ `AsyncStream` does not support multiple subscribers, therefore you can only - /// > use this helper to test features that do not subscribe multiple times to the dependency - /// > endpoint. - /// - /// [se-0388]: https://github.com/apple/swift-evolution/blob/main/proposals/0388-async-stream-factory.md - /// - /// - Parameters: - /// - elementType: The type of element the `AsyncStream` produces. - /// - limit: A Continuation.BufferingPolicy value to set the stream’s buffering behavior. By - /// default, the stream buffers an unlimited number of elements. You can also set the policy - /// to buffer a specified number of oldest or newest elements. - /// - Returns: An `AsyncStream`. - public static func makeStream( - of elementType: Element.Type = Element.self, - bufferingPolicy limit: Continuation.BufferingPolicy = .unbounded - ) -> (stream: Self, continuation: Continuation) { - var continuation: Continuation! - return (Self(elementType, bufferingPolicy: limit) { continuation = $0 }, continuation) - } - #endif - /// An `AsyncStream` that never emits and never completes unless cancelled. public static var never: Self { Self { _ in } diff --git a/Sources/ConcurrencyExtras/AsyncThrowingStream.swift b/Sources/ConcurrencyExtras/AsyncThrowingStream.swift index 829b0ae..cb16e23 100644 --- a/Sources/ConcurrencyExtras/AsyncThrowingStream.swift +++ b/Sources/ConcurrencyExtras/AsyncThrowingStream.swift @@ -18,68 +18,6 @@ extension AsyncThrowingStream where Failure == Error { } } - #if swift(<5.9) - /// Constructs and returns a stream along with its backing continuation. - /// - /// A back-port of [SE-0388: Convenience Async[Throwing]Stream.makeStream methods][se-0388]. - /// - /// This is handy for immediately escaping the continuation from an async stream, which - /// typically requires multiple steps: - /// - /// ```swift - /// var _continuation: AsyncThrowingStream.Continuation! - /// let stream = AsyncThrowingStream { continuation = $0 } - /// let continuation = _continuation! - /// - /// // vs. - /// - /// let (stream, continuation) = AsyncThrowingStream.makeStream(of: Int.self) - /// ``` - /// - /// This tool is usually used for tests where we need to supply an async sequence to a - /// dependency endpoint and get access to its continuation so that we can emulate the dependency - /// emitting data. For example, suppose you have a dependency exposing an async sequence for - /// listening to notifications. To test this you can use `makeStream`: - /// - /// ```swift - /// func testScreenshots() { - /// let screenshots = AsyncThrowingStream.makeStream(of: Void.self) - /// - /// let model = withDependencies { - /// $0.screenshots = { screenshots.stream } - /// } operation: { - /// FeatureModel() - /// } - /// - /// XCTAssertEqual(model.screenshotCount, 0) - /// screenshots.continuation.yield() // Simulate a screenshot being taken. - /// XCTAssertEqual(model.screenshotCount, 1) - /// } - /// ``` - /// - /// > Warning: ⚠️ `AsyncThrowingStream` does not support multiple subscribers, therefore you can - /// > only use this helper to test features that do not subscribe multiple times to the - /// > dependency endpoint. - /// - /// [se-0388]: https://github.com/apple/swift-evolution/blob/main/proposals/0388-async-stream-factory.md - /// - /// - Parameters: - /// - elementType: The type of element the `AsyncThrowingStream` produces. - /// - failureType: The type of failure the `AsyncThrowingStream` throws. - /// - limit: A Continuation.BufferingPolicy value to set the stream’s buffering behavior. By - /// default, the stream buffers an unlimited number of elements. You can also set the policy - /// to buffer a specified number of oldest or newest elements. - /// - Returns: An `AsyncThrowingStream`. - public static func makeStream( - of elementType: Element.Type = Element.self, - throwing failureType: Failure.Type = Failure.self, - bufferingPolicy limit: Continuation.BufferingPolicy = .unbounded - ) -> (stream: Self, continuation: Continuation) { - var continuation: Continuation! - return (Self(elementType, bufferingPolicy: limit) { continuation = $0 }, continuation) - } - #endif - /// An `AsyncThrowingStream` that never emits and never completes unless cancelled. public static var never: Self { Self { _ in } diff --git a/Tests/ConcurrencyExtrasTests/AsyncStreamTests.swift b/Tests/ConcurrencyExtrasTests/AsyncStreamTests.swift index d6a5ebb..8971539 100644 --- a/Tests/ConcurrencyExtrasTests/AsyncStreamTests.swift +++ b/Tests/ConcurrencyExtrasTests/AsyncStreamTests.swift @@ -4,7 +4,7 @@ @available(iOS 15, *) private let sendable: @Sendable () async -> AsyncStream = { - await NotificationCenter.default + NotificationCenter.default .notifications(named: UIApplication.userDidTakeScreenshotNotification) .map { _ in } .eraseToStream() @@ -20,7 +20,7 @@ @available(iOS 15, *) private let sendableThrowing: @Sendable () async -> AsyncThrowingStream = { - await NotificationCenter.default + NotificationCenter.default .notifications(named: UIApplication.userDidTakeScreenshotNotification) .map { _ in } .eraseToThrowingStream()