feat: Refactors / moves into individual files, wip.
This commit is contained in:
@@ -1,33 +1,66 @@
|
||||
import ComposableArchitecture
|
||||
import OSLog
|
||||
|
||||
extension Effect where Action: ReceiveAction {
|
||||
|
||||
public static func receive(
|
||||
_ operation: @escaping () async throws -> Action.ReceiveAction
|
||||
extension Effect {
|
||||
|
||||
@usableFromInline
|
||||
static func receive<T>(
|
||||
_ casePath: AnyCasePath<Action, TaskResult<T>>,
|
||||
_ operation: @escaping @Sendable () async throws -> T
|
||||
) -> Self {
|
||||
.run { send in
|
||||
await send(.receive(
|
||||
await send(casePath.embed(
|
||||
TaskResult { try await operation() }
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
public static func receive<T>(
|
||||
_ operation: @escaping () async throws -> T,
|
||||
transform: @escaping (T) -> Action.ReceiveAction
|
||||
|
||||
@usableFromInline
|
||||
static func receive<T, V>(
|
||||
_ casePath: AnyCasePath<Action, TaskResult<V>>,
|
||||
_ operation: @escaping @Sendable () async throws -> T,
|
||||
_ transform: @escaping @Sendable (T) -> V
|
||||
) -> Self {
|
||||
.run { send in
|
||||
await send(.receive(
|
||||
await send(casePath.embed(
|
||||
TaskResult { try await operation() }
|
||||
.map(transform)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public static func receive<T>(
|
||||
action toResult: CaseKeyPath<Action, TaskResult<T>>,
|
||||
operation: @escaping @Sendable () async throws -> T
|
||||
) -> Self {
|
||||
.receive(AnyCasePath(toResult), operation)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public static func receive<T, V>(
|
||||
action toResult: CaseKeyPath<Action, TaskResult<V>>,
|
||||
operation: @escaping @Sendable () async throws -> T,
|
||||
transform: @escaping @Sendable (T) -> V
|
||||
) -> Self {
|
||||
.receive(AnyCasePath(toResult), operation, transform)
|
||||
}
|
||||
}
|
||||
|
||||
extension Effect where Action: ReceiveAction {
|
||||
|
||||
@inlinable
|
||||
public static func receive<T>(
|
||||
_ operation: @escaping @Sendable () async throws -> T,
|
||||
transform: @escaping @Sendable (T) -> Action.ReceiveAction
|
||||
) -> Self {
|
||||
.receive(AnyCasePath(unsafe: Action.receive), operation, transform)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public static func receive<T>(
|
||||
_ toReceiveAction: CaseKeyPath<Action.ReceiveAction, T>,
|
||||
_ operation: @escaping () async throws -> T
|
||||
_ operation: @escaping @Sendable () async throws -> T
|
||||
) -> Self {
|
||||
return .receive(operation) {
|
||||
AnyCasePath(toReceiveAction).embed($0)
|
||||
|
||||
32
Sources/ComposableSubscriber/Internal/SetAction.swift
Normal file
32
Sources/ComposableSubscriber/Internal/SetAction.swift
Normal file
@@ -0,0 +1,32 @@
|
||||
import ComposableArchitecture
|
||||
import Foundation
|
||||
|
||||
@usableFromInline
|
||||
enum SetAction<State, Action, Value> {
|
||||
case operation(f: (inout State, Value) -> Effect<Action>)
|
||||
case keyPath(WritableKeyPath<State, Value>, effect: Effect<Action>)
|
||||
case optionalKeyPath(WritableKeyPath<State, Value?>, effect: Effect<Action>)
|
||||
|
||||
@usableFromInline
|
||||
func callAsFunction(state: inout State, value: Value) -> Effect<Action> {
|
||||
switch self {
|
||||
case let .operation(f: f):
|
||||
return f(&state, value)
|
||||
case let .keyPath(keyPath, effect):
|
||||
state[keyPath: keyPath] = value
|
||||
return effect
|
||||
case let .optionalKeyPath(keyPath, effect):
|
||||
state[keyPath: keyPath] = value
|
||||
return effect
|
||||
}
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
static func operation(_ f: @escaping (inout State, Value) -> Void) -> Self {
|
||||
.operation(f: { state, value in
|
||||
f(&state, value)
|
||||
return .none
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,13 +4,7 @@ import OSLog
|
||||
|
||||
public enum OnFailAction<State, Action> {
|
||||
case fail(prefix: String? = nil, log: ((String) -> Void)? = nil)
|
||||
case handle((inout State, Error) -> Void)
|
||||
|
||||
@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
|
||||
@inlinable
|
||||
static func fail(prefix: String? = nil, logger: Logger) -> Self {
|
||||
.fail(prefix: prefix, log: { logger.error("\($0)") })
|
||||
}
|
||||
case operation((inout State, Error) -> Effect<Action>)
|
||||
|
||||
@usableFromInline
|
||||
func callAsFunction(state: inout State, error: Error) -> Effect<Action> {
|
||||
@@ -21,10 +15,45 @@ public enum OnFailAction<State, Action> {
|
||||
} else {
|
||||
return .fail(error: error, log: log)
|
||||
}
|
||||
case let .handle(handler):
|
||||
handler(&state, error)
|
||||
return .none
|
||||
case let .operation(handler):
|
||||
return handler(&state, error)
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
|
||||
@inlinable
|
||||
static func fail(prefix: String? = nil, logger: Logger) -> Self {
|
||||
.fail(prefix: prefix, log: { logger.error("\($0)") })
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public static func set(
|
||||
_ operation: @escaping @Sendable (inout State, Error) -> Void
|
||||
) -> Self {
|
||||
.operation(
|
||||
SetAction.operation(operation).callAsFunction(state:value:)
|
||||
)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public static func set(
|
||||
_ operation: @escaping @Sendable (inout State, Error) -> Effect<Action>
|
||||
) -> Self {
|
||||
.operation(
|
||||
SetAction.operation(f: operation).callAsFunction(state:value:)
|
||||
)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public static func set(
|
||||
keyPath: WritableKeyPath<State, Error?>,
|
||||
effect: Effect<Action> = .none
|
||||
) -> Self {
|
||||
.operation(
|
||||
SetAction.optionalKeyPath(
|
||||
keyPath,
|
||||
effect: effect
|
||||
).callAsFunction(state:value:)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,55 +3,73 @@ import OSLog
|
||||
|
||||
extension Reducer {
|
||||
|
||||
@inlinable
|
||||
public func onReceive<V>(
|
||||
@usableFromInline
|
||||
func onReceive<V>(
|
||||
action toReceiveAction: CaseKeyPath<Action, V>,
|
||||
set setAction: @escaping (inout State, V) -> Effect<Action>
|
||||
) -> _ReceiveReducer<Self, V> {
|
||||
set setAction: SetAction<State, Action, V>
|
||||
) -> _OnReceiveReducer<Self, V> {
|
||||
.init(
|
||||
parent: self,
|
||||
receiveAction: { AnyCasePath(toReceiveAction).extract(from: $0) },
|
||||
setAction: setAction
|
||||
)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func onReceive<V>(
|
||||
action toReceiveAction: CaseKeyPath<Action, V>,
|
||||
set setAction: @escaping (inout State, V) -> Effect<Action>
|
||||
) -> _OnReceiveReducer<Self, V> {
|
||||
self.onReceive(
|
||||
action: toReceiveAction,
|
||||
set: .operation(f: setAction)
|
||||
)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func onReceive<V>(
|
||||
action toReceiveAction: CaseKeyPath<Action, V>,
|
||||
set setAction: @escaping (inout State, V) -> Void
|
||||
) -> _ReceiveReducer<Self, V> {
|
||||
.init(
|
||||
parent: self,
|
||||
receiveAction: { AnyCasePath(toReceiveAction).extract(from: $0) },
|
||||
setAction: { state, value in
|
||||
) -> _OnReceiveReducer<Self, V> {
|
||||
self.onReceive(
|
||||
action: toReceiveAction,
|
||||
set: .operation(f: { state, value in
|
||||
setAction(&state, value)
|
||||
return .none
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func onReceive<V>(
|
||||
action toReceiveAction: CaseKeyPath<Action, V>,
|
||||
set toStateKeyPath: WritableKeyPath<State, V>
|
||||
) -> _ReceiveReducer<Self, V> {
|
||||
self.onReceive(action: toReceiveAction, set: toStateKeyPath.callAsFunction(root:value:))
|
||||
set toStateKeyPath: WritableKeyPath<State, V>,
|
||||
effect: Effect<Action> = .none
|
||||
) -> _OnReceiveReducer<Self, V> {
|
||||
self.onReceive(
|
||||
action: toReceiveAction,
|
||||
set: .keyPath(toStateKeyPath, effect: effect)
|
||||
)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func onReceive<V>(
|
||||
action toReceiveAction: CaseKeyPath<Action, V>,
|
||||
set toStateKeyPath: WritableKeyPath<State, V?>
|
||||
) -> _ReceiveReducer<Self, V> {
|
||||
self.onReceive(action: toReceiveAction, set: toStateKeyPath.callAsFunction(root:value:))
|
||||
set toStateKeyPath: WritableKeyPath<State, V?>,
|
||||
effect: Effect<Action> = .none
|
||||
) -> _OnReceiveReducer<Self, V> {
|
||||
self.onReceive(
|
||||
action: toReceiveAction,
|
||||
set: .optionalKeyPath(toStateKeyPath, effect: effect)
|
||||
)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func onReceive<V>(
|
||||
@usableFromInline
|
||||
func onReceive<V>(
|
||||
action toReceiveAction: CaseKeyPath<Action, TaskResult<V>>,
|
||||
onFail: OnFailAction<State, Action>? = nil,
|
||||
onSuccess setAction: @escaping (inout State, V) -> Void
|
||||
) -> _ReceiveReducer<Self, TaskResult<V>> {
|
||||
onSuccess setAction: SetAction<State, Action, V>
|
||||
) -> _OnReceiveReducer<Self, TaskResult<V>> {
|
||||
self.onReceive(action: toReceiveAction) { state, result in
|
||||
switch result {
|
||||
case let .failure(error):
|
||||
@@ -60,50 +78,50 @@ extension Reducer {
|
||||
}
|
||||
return .none
|
||||
case let .success(value):
|
||||
setAction(&state, value)
|
||||
return .none
|
||||
return setAction(state: &state, value: value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func onReceive<V>(
|
||||
action toReceiveAction: CaseKeyPath<Action, TaskResult<V>>,
|
||||
onSuccess setAction: @escaping (inout State, V) -> Void,
|
||||
onFail: OnFailAction<State, Action>? = nil
|
||||
) -> _OnReceiveReducer<Self, TaskResult<V>> {
|
||||
self.onReceive(
|
||||
action: toReceiveAction,
|
||||
onFail: onFail,
|
||||
onSuccess: .operation(setAction)
|
||||
)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func onReceive<V>(
|
||||
action toReceiveAction: CaseKeyPath<Action, TaskResult<V>>,
|
||||
set toStateKeyPath: WritableKeyPath<State, V>,
|
||||
onFail: OnFailAction<State, Action>? = nil
|
||||
) -> _ReceiveReducer<Self, TaskResult<V>> {
|
||||
self.onReceive(action: toReceiveAction) { state, result in
|
||||
switch result {
|
||||
case let .failure(error):
|
||||
if let onFail {
|
||||
return onFail(state: &state, error: error)
|
||||
}
|
||||
return .none
|
||||
case let .success(value):
|
||||
toStateKeyPath(root: &state, value: value)
|
||||
return .none
|
||||
}
|
||||
}
|
||||
onFail: OnFailAction<State, Action>? = nil,
|
||||
effect: Effect<Action> = .none
|
||||
) -> _OnReceiveReducer<Self, TaskResult<V>> {
|
||||
self.onReceive(
|
||||
action: toReceiveAction,
|
||||
onFail: onFail,
|
||||
onSuccess: .keyPath(toStateKeyPath, effect: effect)
|
||||
)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func onReceive<V>(
|
||||
action toReceiveAction: CaseKeyPath<Action, TaskResult<V>>,
|
||||
set toStateKeyPath: WritableKeyPath<State, V?>,
|
||||
onFail: OnFailAction<State, Action>? = nil
|
||||
) -> _ReceiveReducer<Self, TaskResult<V>> {
|
||||
self.onReceive(action: toReceiveAction) { state, result in
|
||||
switch result {
|
||||
case let .failure(error):
|
||||
if let onFail {
|
||||
return onFail(state: &state, error: error)
|
||||
}
|
||||
return .none
|
||||
case let .success(value):
|
||||
toStateKeyPath(root: &state, value: value)
|
||||
return .none
|
||||
}
|
||||
}
|
||||
onFail: OnFailAction<State, Action>? = nil,
|
||||
effect: Effect<Action> = .none
|
||||
) -> _OnReceiveReducer<Self, TaskResult<V>> {
|
||||
self.onReceive(
|
||||
action: toReceiveAction,
|
||||
onFail: onFail,
|
||||
onSuccess: .optionalKeyPath(toStateKeyPath, effect: effect)
|
||||
)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
@@ -126,7 +144,7 @@ extension Reducer where Action: ReceiveAction {
|
||||
@inlinable
|
||||
public func receive<TriggerAction, Value>(
|
||||
on triggerAction: CaseKeyPath<Action, TriggerAction>,
|
||||
with embedCasePath: CaseKeyPath<Action.ReceiveAction, Value>,
|
||||
case embedCasePath: CaseKeyPath<Action.ReceiveAction, Value>,
|
||||
result resultHandler: @escaping @Sendable () async throws -> Value
|
||||
) -> _ReceiveOnTriggerReducer<Self, TriggerAction, Action.ReceiveAction> {
|
||||
.init(
|
||||
@@ -142,16 +160,7 @@ extension Reducer where Action: ReceiveAction {
|
||||
}
|
||||
}
|
||||
|
||||
extension WritableKeyPath {
|
||||
|
||||
@usableFromInline
|
||||
func callAsFunction(root: inout Root, value: Value) {
|
||||
root[keyPath: self] = value
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct _ReceiveReducer<Parent: Reducer, Value>: Reducer {
|
||||
public struct _OnReceiveReducer<Parent: Reducer, Value>: Reducer {
|
||||
|
||||
@usableFromInline
|
||||
let parent: Parent
|
||||
@@ -160,13 +169,13 @@ public struct _ReceiveReducer<Parent: Reducer, Value>: Reducer {
|
||||
let receiveAction: (Parent.Action) -> Value?
|
||||
|
||||
@usableFromInline
|
||||
let setAction: (inout Parent.State, Value) -> Effect<Parent.Action>
|
||||
let setAction: SetAction<Parent.State, Parent.Action, Value>
|
||||
|
||||
@usableFromInline
|
||||
init(
|
||||
parent: Parent,
|
||||
receiveAction: @escaping (Parent.Action) -> Value?,
|
||||
setAction: @escaping (inout Parent.State, Value) -> Effect<Parent.Action>
|
||||
setAction: SetAction<Parent.State, Parent.Action, Value>
|
||||
) {
|
||||
self.parent = parent
|
||||
self.receiveAction = receiveAction
|
||||
@@ -182,7 +191,7 @@ public struct _ReceiveReducer<Parent: Reducer, Value>: Reducer {
|
||||
var setEffects = Effect<Action>.none
|
||||
|
||||
if let value = receiveAction(action) {
|
||||
setEffects = setAction(&state, value)
|
||||
setEffects = setAction(state: &state, value: value)
|
||||
}
|
||||
|
||||
return .merge(baseEffects, setEffects)
|
||||
@@ -286,9 +286,14 @@ extension Reducer {
|
||||
/// return .none
|
||||
/// }
|
||||
/// }
|
||||
/// .subscribe(using: \.number, to: numberFactStream, on: \.task, with: \.receive) { numberFact in
|
||||
/// "\(numberFact) Appended with my custom transformation."
|
||||
/// }
|
||||
/// .subscribe(
|
||||
/// to: numberFactStream,
|
||||
/// using: \.number,
|
||||
/// on: \.task,
|
||||
/// with: \.receiveNumberFact
|
||||
/// ) { numberFact in
|
||||
/// "\(numberFact) Appended with my custom transformation."
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@@ -513,6 +518,7 @@ public struct _SubscribeReducer<Parent: Reducer, TriggerAction, StreamElement, V
|
||||
@usableFromInline
|
||||
let transform: (StreamElement) -> Value
|
||||
|
||||
@usableFromInline
|
||||
init(
|
||||
parent: Parent,
|
||||
on triggerAction: CaseKeyPath<Parent.Action, TriggerAction>,
|
||||
Reference in New Issue
Block a user