Initial
This commit is contained in:
113
Package.resolved
Normal file
113
Package.resolved
Normal file
@@ -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
|
||||
}
|
||||
@@ -5,19 +5,24 @@ import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "swift-composable-subscriber",
|
||||
platforms: [
|
||||
.iOS(.v13),
|
||||
.macOS(.v10_15),
|
||||
.tvOS(.v13),
|
||||
.watchOS(.v6),
|
||||
],
|
||||
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"]),
|
||||
.library(name: "ComposableSubscriber", targets: ["ComposableSubscriber"]),
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/pointfreeco/swift-composable-architecture", .upToNextMajor(from: "1.0.0")),
|
||||
],
|
||||
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: "ComposableSubscriber",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
]
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
59
Sources/ComposableSubscriber/SubscriberReducer.swift
Normal file
59
Sources/ComposableSubscriber/SubscriberReducer.swift
Normal file
@@ -0,0 +1,59 @@
|
||||
import ComposableArchitecture
|
||||
|
||||
extension Reducer {
|
||||
func subscribe<TriggerAction, T>(
|
||||
on triggerAction: CaseKeyPath<Action, TriggerAction>,
|
||||
to stream: @escaping () async throws -> AsyncStream<T>,
|
||||
with responseAction: CaseKeyPath<Action, T>
|
||||
) -> _SubscribeReducer<Self, TriggerAction, T> {
|
||||
.init(
|
||||
parent: self,
|
||||
on: triggerAction,
|
||||
to: stream,
|
||||
with: responseAction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct _SubscribeReducer<Parent: Reducer, TriggerAction, T>: Reducer {
|
||||
@usableFromInline
|
||||
let parent: Parent
|
||||
|
||||
@usableFromInline
|
||||
let triggerAction: AnyCasePath<Parent.Action, TriggerAction>
|
||||
|
||||
@usableFromInline
|
||||
let stream: () async throws -> AsyncStream<T>
|
||||
|
||||
@usableFromInline
|
||||
let responseAction: AnyCasePath<Parent.Action, T>
|
||||
|
||||
init(
|
||||
parent: Parent,
|
||||
on triggerAction: CaseKeyPath<Parent.Action, TriggerAction>,
|
||||
to stream: @escaping () async throws -> AsyncStream<T>,
|
||||
with responseAction: CaseKeyPath<Parent.Action, T>
|
||||
) {
|
||||
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<Parent.Action> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
// The Swift Programming Language
|
||||
// https://docs.swift.org/swift-book
|
||||
Reference in New Issue
Block a user