diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..baf36dc --- /dev/null +++ b/Package.resolved @@ -0,0 +1,113 @@ +{ + "pins" : [ + { + "identity" : "combine-schedulers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/combine-schedulers", + "state" : { + "revision" : "9dc9cbe4bc45c65164fa653a563d8d8db61b09bb", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-case-paths", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-case-paths", + "state" : { + "revision" : "bba1111185863c9288c5f047770f421c3b7793a4", + "version" : "1.1.3" + } + }, + { + "identity" : "swift-clocks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-clocks", + "state" : { + "revision" : "a8421d68068d8f45fbceb418fbf22c5dad4afd33", + "version" : "1.0.2" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections", + "state" : { + "revision" : "a902f1823a7ff3c9ab2fba0f992396b948eda307", + "version" : "1.0.5" + } + }, + { + "identity" : "swift-composable-architecture", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-composable-architecture", + "state" : { + "revision" : "cb9c1f845b3b981da787452beee893826210eb7a", + "version" : "1.5.5" + } + }, + { + "identity" : "swift-concurrency-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-concurrency-extras", + "state" : { + "revision" : "bb5059bde9022d69ac516803f4f227d8ac967f71", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-custom-dump", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-custom-dump", + "state" : { + "revision" : "aedcf6f4cd486ccef5b312ccac85d4b3f6e58605", + "version" : "1.1.2" + } + }, + { + "identity" : "swift-dependencies", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-dependencies", + "state" : { + "revision" : "101ba87f8de2cb7a80e0c0551370f6981a03022a", + "version" : "1.1.4" + } + }, + { + "identity" : "swift-identified-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-identified-collections", + "state" : { + "revision" : "d1e45f3e1eee2c9193f5369fa9d70a6ddad635e8", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax", + "state" : { + "revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036", + "version" : "509.0.2" + } + }, + { + "identity" : "swiftui-navigation", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swiftui-navigation", + "state" : { + "revision" : "78f9d72cf667adb47e2040aa373185c88c63f0dc", + "version" : "1.2.0" + } + }, + { + "identity" : "xctest-dynamic-overlay", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", + "state" : { + "revision" : "23cbf2294e350076ea4dbd7d5d047c1e76b03631", + "version" : "1.0.2" + } + } + ], + "version" : 2 +} diff --git a/Package.swift b/Package.swift index 1fb58d9..17472e4 100644 --- a/Package.swift +++ b/Package.swift @@ -4,20 +4,25 @@ import PackageDescription let package = Package( - name: "swift-composable-subscriber", - products: [ - // Products define the executables and libraries a package produces, making them visible to other packages. - .library( - name: "swift-composable-subscriber", - targets: ["swift-composable-subscriber"]), - ], - targets: [ - // Targets are the basic building blocks of a package, defining a module or a test suite. - // Targets can depend on other targets in this package and products from dependencies. - .target( - name: "swift-composable-subscriber"), - .testTarget( - name: "swift-composable-subscriberTests", - dependencies: ["swift-composable-subscriber"]), - ] + name: "swift-composable-subscriber", + platforms: [ + .iOS(.v13), + .macOS(.v10_15), + .tvOS(.v13), + .watchOS(.v6), + ], + products: [ + .library(name: "ComposableSubscriber", targets: ["ComposableSubscriber"]), + ], + dependencies: [ + .package(url: "https://github.com/pointfreeco/swift-composable-architecture", .upToNextMajor(from: "1.0.0")), + ], + targets: [ + .target( + name: "ComposableSubscriber", + dependencies: [ + .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), + ] + ), + ] ) diff --git a/Sources/ComposableSubscriber/SubscriberReducer.swift b/Sources/ComposableSubscriber/SubscriberReducer.swift new file mode 100644 index 0000000..bd560f7 --- /dev/null +++ b/Sources/ComposableSubscriber/SubscriberReducer.swift @@ -0,0 +1,59 @@ +import ComposableArchitecture + +extension Reducer { + func subscribe( + on triggerAction: CaseKeyPath, + to stream: @escaping () async throws -> AsyncStream, + with responseAction: CaseKeyPath + ) -> _SubscribeReducer { + .init( + parent: self, + on: triggerAction, + to: stream, + with: responseAction + ) + } +} + +struct _SubscribeReducer: Reducer { + @usableFromInline + let parent: Parent + + @usableFromInline + let triggerAction: AnyCasePath + + @usableFromInline + let stream: () async throws -> AsyncStream + + @usableFromInline + let responseAction: AnyCasePath + + init( + parent: Parent, + on triggerAction: CaseKeyPath, + to stream: @escaping () async throws -> AsyncStream, + with responseAction: CaseKeyPath + ) { + self.parent = parent + self.triggerAction = AnyCasePath(triggerAction) + self.stream = stream + self.responseAction = AnyCasePath(responseAction) + } + + func reduce(into state: inout Parent.State, action: Parent.Action) -> Effect { + let effects = parent.reduce(into: &state, action: action) + + guard self.triggerAction.extract(from: action) != nil else { + return effects + } + + return .merge( + effects, + .run { send in + for await value in try await stream() { + await send(responseAction.embed(value)) + } + } + ) + } +} diff --git a/Sources/swift-composable-subscriber/swift_composable_subscriber.swift b/Sources/swift-composable-subscriber/swift_composable_subscriber.swift deleted file mode 100644 index 08b22b8..0000000 --- a/Sources/swift-composable-subscriber/swift_composable_subscriber.swift +++ /dev/null @@ -1,2 +0,0 @@ -// The Swift Programming Language -// https://docs.swift.org/swift-book