feat: Adding more helpers, wip
This commit is contained in:
@@ -1,20 +1,6 @@
|
|||||||
import ComposableArchitecture
|
import ComposableArchitecture
|
||||||
import OSLog
|
import OSLog
|
||||||
|
|
||||||
public protocol ReceiveAction<ReceiveAction> {
|
|
||||||
associatedtype ReceiveAction
|
|
||||||
static func receive(_ result: TaskResult<ReceiveAction>) -> Self
|
|
||||||
|
|
||||||
var result: TaskResult<ReceiveAction>? { get }
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ReceiveAction {
|
|
||||||
|
|
||||||
public var result: TaskResult<ReceiveAction>? {
|
|
||||||
AnyCasePath(unsafe: Self.receive).extract(from: self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Effect where Action: ReceiveAction {
|
extension Effect where Action: ReceiveAction {
|
||||||
|
|
||||||
public static func receive(
|
public static func receive(
|
||||||
|
|||||||
30
Sources/ComposableSubscriber/OnFailAction.swift
Normal file
30
Sources/ComposableSubscriber/OnFailAction.swift
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import ComposableArchitecture
|
||||||
|
import Foundation
|
||||||
|
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)") })
|
||||||
|
}
|
||||||
|
|
||||||
|
@usableFromInline
|
||||||
|
func callAsFunction(state: inout State, error: Error) -> Effect<Action> {
|
||||||
|
switch self {
|
||||||
|
case let .fail(prefix, log):
|
||||||
|
if let prefix {
|
||||||
|
return .fail(prefix: prefix, error: error, log: log)
|
||||||
|
} else {
|
||||||
|
return .fail(error: error, log: log)
|
||||||
|
}
|
||||||
|
case let .handle(handler):
|
||||||
|
handler(&state, error)
|
||||||
|
return .none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
15
Sources/ComposableSubscriber/ReceiveAction.swift
Normal file
15
Sources/ComposableSubscriber/ReceiveAction.swift
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import ComposableArchitecture
|
||||||
|
|
||||||
|
public protocol ReceiveAction<ReceiveAction> {
|
||||||
|
associatedtype ReceiveAction
|
||||||
|
static func receive(_ result: TaskResult<ReceiveAction>) -> Self
|
||||||
|
|
||||||
|
var result: TaskResult<ReceiveAction>? { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ReceiveAction {
|
||||||
|
|
||||||
|
public var result: TaskResult<ReceiveAction>? {
|
||||||
|
AnyCasePath(unsafe: Self.receive).extract(from: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -105,33 +105,41 @@ extension Reducer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@inlinable
|
||||||
|
public func receive<TriggerAction, Value>(
|
||||||
|
on triggerAction: CaseKeyPath<Action, TriggerAction>,
|
||||||
|
with receiveAction: CaseKeyPath<Action, TaskResult<Value>>,
|
||||||
|
result resultHandler: @escaping @Sendable () async throws -> Value
|
||||||
|
) -> _ReceiveOnTriggerReducer<Self, TriggerAction, Value> {
|
||||||
|
.init(
|
||||||
|
parent: self,
|
||||||
|
triggerAction: { AnyCasePath(triggerAction).extract(from: $0) },
|
||||||
|
toReceiveAction: { AnyCasePath(receiveAction).embed($0) },
|
||||||
|
resultHandler: resultHandler
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum OnFailAction<State, Action> {
|
extension Reducer where Action: ReceiveAction {
|
||||||
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
|
@inlinable
|
||||||
static func fail(prefix: String? = nil, logger: Logger) -> Self {
|
public func receive<TriggerAction, Value>(
|
||||||
.fail(prefix: prefix, log: { logger.error("\($0)") })
|
on triggerAction: CaseKeyPath<Action, TriggerAction>,
|
||||||
|
with embedCasePath: CaseKeyPath<Action.ReceiveAction, Value>,
|
||||||
|
result resultHandler: @escaping @Sendable () async throws -> Value
|
||||||
|
) -> _ReceiveOnTriggerReducer<Self, TriggerAction, Action.ReceiveAction> {
|
||||||
|
.init(
|
||||||
|
parent: self,
|
||||||
|
triggerAction: { AnyCasePath(triggerAction).extract(from: $0) },
|
||||||
|
toReceiveAction: { AnyCasePath(unsafe: Action.receive).embed($0) },
|
||||||
|
resultHandler: {
|
||||||
|
try await AnyCasePath(embedCasePath).embed(
|
||||||
|
resultHandler()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
@usableFromInline
|
|
||||||
func callAsFunction(state: inout State, error: Error) -> Effect<Action> {
|
|
||||||
switch self {
|
|
||||||
case let .fail(prefix, log):
|
|
||||||
if let prefix {
|
|
||||||
return .fail(prefix: prefix, error: error, log: log)
|
|
||||||
} else {
|
|
||||||
return .fail(error: error, log: log)
|
|
||||||
}
|
}
|
||||||
case let .handle(handler):
|
|
||||||
handler(&state, error)
|
|
||||||
return .none
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension WritableKeyPath {
|
extension WritableKeyPath {
|
||||||
@@ -181,7 +189,11 @@ public struct _ReceiveReducer<Parent: Reducer, Value>: Reducer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct _OnRecieveReducer<Parent: Reducer, TriggerAction, Value>: Reducer {
|
public struct _ReceiveOnTriggerReducer<
|
||||||
|
Parent: Reducer,
|
||||||
|
TriggerAction,
|
||||||
|
Value
|
||||||
|
>: Reducer {
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
let parent: Parent
|
let parent: Parent
|
||||||
@@ -198,9 +210,9 @@ public struct _OnRecieveReducer<Parent: Reducer, TriggerAction, Value>: Reducer
|
|||||||
@usableFromInline
|
@usableFromInline
|
||||||
init(
|
init(
|
||||||
parent: Parent,
|
parent: Parent,
|
||||||
triggerAction: @escaping (Parent.Action) -> TriggerAction?,
|
triggerAction: @escaping @Sendable (Parent.Action) -> TriggerAction?,
|
||||||
toReceiveAction: @escaping (TaskResult<Value>) -> Parent.Action,
|
toReceiveAction: @escaping @Sendable (TaskResult<Value>) -> Parent.Action,
|
||||||
resultHandler: @escaping () -> Value
|
resultHandler: @escaping @Sendable () async throws -> Value
|
||||||
) {
|
) {
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.triggerAction = triggerAction
|
self.triggerAction = triggerAction
|
||||||
|
|||||||
@@ -127,19 +127,22 @@ struct ReducerWithReceiveAction {
|
|||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.receive(on: \.task, with: \.currentNumber) {
|
||||||
Reduce<State, Action> { state, action in
|
|
||||||
switch action {
|
|
||||||
|
|
||||||
case .receive:
|
|
||||||
return .none
|
|
||||||
|
|
||||||
case .task:
|
|
||||||
return .receive(\.currentNumber) {
|
|
||||||
try await numberClient.currentNumber()
|
try await numberClient.currentNumber()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
// Reduce<State, Action> { state, action in
|
||||||
|
// switch action {
|
||||||
|
//
|
||||||
|
// case .receive:
|
||||||
|
// return .none
|
||||||
|
//
|
||||||
|
// case .task:
|
||||||
|
// return .receive(\.currentNumber) {
|
||||||
|
// try await numberClient.currentNumber()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user