wip
This commit is contained in:
@@ -4,38 +4,179 @@ import OSLog
|
|||||||
extension Effect {
|
extension Effect {
|
||||||
|
|
||||||
/// An effect that throws a runtime warning and optionally logs an error message.
|
/// An effect that throws a runtime warning and optionally logs an error message.
|
||||||
|
///
|
||||||
|
/// This effect uses `XCTFail` to throw a runtime warning and will also log the message
|
||||||
|
/// if a logger is supplied.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
///```swift
|
||||||
|
/// @Reducer
|
||||||
|
/// struct MyFeature {
|
||||||
|
/// ...
|
||||||
|
/// enum Action {
|
||||||
|
/// case receive(TaskResult<Int>)
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// @Dependency(\.logger) var logger
|
||||||
|
///
|
||||||
|
/// var body: some ReducerOf<Self> {
|
||||||
|
/// Reduce { state, action in
|
||||||
|
/// switch action {
|
||||||
|
/// case .receive(.failure(_)):
|
||||||
|
/// return .fail("Failed retreiving number fact.", log: { logger.debug("\($0)") })
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///```
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - message: The message for the failure reason.
|
||||||
|
/// - logger: An optional logger to use to log the message.
|
||||||
|
public static func fail(
|
||||||
|
_ message: String,
|
||||||
|
log: (@Sendable (String) -> Void)? = nil
|
||||||
|
) -> Self {
|
||||||
|
XCTFail("\(message)")
|
||||||
|
log?(message)
|
||||||
|
return .none
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An effect that throws a runtime warning and optionally logs an error message.
|
||||||
|
///
|
||||||
|
/// This effect uses `XCTFail` to throw a runtime warning and will also log the message
|
||||||
|
/// if a logger is supplied.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
///```swift
|
||||||
|
/// @Reducer
|
||||||
|
/// struct MyFeature {
|
||||||
|
/// ...
|
||||||
|
/// enum Action {
|
||||||
|
/// case receive(TaskResult<Int>)
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// @Dependency(\.logger) var logger
|
||||||
|
///
|
||||||
|
/// var body: some ReducerOf<Self> {
|
||||||
|
/// Reduce { state, action in
|
||||||
|
/// switch action {
|
||||||
|
/// case .receive(.failure(_)):
|
||||||
|
/// return .fail("Failed retreiving number fact.", logger: logger)
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///```
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - message: The message for the failure reason.
|
||||||
|
/// - logger: An optional logger to use to log the message.
|
||||||
@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
|
@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
|
||||||
public static func fail(
|
public static func fail(
|
||||||
_ message: String,
|
_ message: String,
|
||||||
logger: Logger? = nil
|
logger: Logger? = nil
|
||||||
) -> Self {
|
) -> Self {
|
||||||
XCTFail("\(message)")
|
.fail(message, log: { logger?.error("\($0)") })
|
||||||
logger?.error("\(message)")
|
|
||||||
return .none
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// An effect that throws a runtime warning and optionally logs an error message.
|
/// An effect that throws a runtime warning and optionally logs an error message.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// This effect uses `XCTFail` to throw a runtime warning and will also log the message
|
||||||
|
/// if a logger is supplied.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
///```swift
|
||||||
|
/// @Reducer
|
||||||
|
/// struct MyFeature {
|
||||||
|
/// ...
|
||||||
|
/// enum Action {
|
||||||
|
/// case receive(TaskResult<Int>)
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// @Dependency(\.logger) var logger
|
||||||
|
///
|
||||||
|
/// var body: some ReducerOf<Self> {
|
||||||
|
/// Reduce { state, action in
|
||||||
|
/// switch action {
|
||||||
|
/// case let .receive(.failure(error)):
|
||||||
|
/// return .fail(error: error, logger: logger)
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///```
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - prefix: The prefix for the error message for the failure.
|
||||||
|
/// - error: The error for the failure..
|
||||||
|
/// - logger: A logger to use to log the message.
|
||||||
@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
|
@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
|
||||||
public static func fail(
|
public static func fail(
|
||||||
prefix: String = "Failed error:",
|
prefix: String = "Failed error:",
|
||||||
error: any Error,
|
error: any Error,
|
||||||
logger: Logger
|
logger: Logger
|
||||||
) -> Self {
|
) -> Self {
|
||||||
return .fail(prefix: prefix, error: error, log: { logger.error("\($0)") })
|
.fail(prefix: prefix, error: error, log: { logger.error("\($0)") })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An effect that throws a runtime warning and optionally logs an error message.
|
/// An effect that throws a runtime warning and optionally logs an error message.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// This effect uses `XCTFail` to throw a runtime warning and will also log the message
|
||||||
|
/// if a logger is supplied.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
///```swift
|
||||||
|
/// @Reducer
|
||||||
|
/// struct MyFeature {
|
||||||
|
/// ...
|
||||||
|
/// enum Action {
|
||||||
|
/// case receive(TaskResult<Int>)
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// @Dependency(\.logger) var logger
|
||||||
|
///
|
||||||
|
/// var body: some ReducerOf<Self> {
|
||||||
|
/// Reduce { state, action in
|
||||||
|
/// switch action {
|
||||||
|
/// case .receive(.failure(_)):
|
||||||
|
/// return .fail("Failed retreiving number fact.", log: { logger.debug("\($0)") })
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///```
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - prefix: The prefix for the error message for the failure.
|
||||||
|
/// - error: The error for the failure..
|
||||||
|
/// - log: A log handler to use to log the message.
|
||||||
public static func fail(
|
public static func fail(
|
||||||
prefix: String = "Failed error:",
|
prefix: String = "Failed error:",
|
||||||
error: any Error,
|
error: any Error,
|
||||||
log: ((String) -> Void)? = nil
|
log: (@Sendable (String) -> Void)? = nil
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let message = "\(prefix) \(error.localizedDescription)"
|
return .fail("\(prefix) \(error.localizedDescription)", log: log)
|
||||||
XCTFail("\(message)")
|
|
||||||
log?("\(message)")
|
|
||||||
return .none
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,13 @@
|
|||||||
import ComposableArchitecture
|
import ComposableArchitecture
|
||||||
import OSLog
|
|
||||||
|
|
||||||
extension Effect {
|
extension Effect {
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
static func receive<T>(
|
static func receive<Input, Result>(
|
||||||
_ casePath: AnyCasePath<Action, TaskResult<T>>,
|
operation: ReceiveOperation<Action, Input, Result>
|
||||||
_ operation: @escaping @Sendable () async throws -> T
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
.run { send in
|
.run { send in
|
||||||
await send(casePath.embed(
|
await operation(send: send)
|
||||||
TaskResult { try await operation() }
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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(casePath.embed(
|
|
||||||
TaskResult { try await operation() }
|
|
||||||
.map(transform)
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +16,7 @@ extension Effect {
|
|||||||
action toResult: CaseKeyPath<Action, TaskResult<T>>,
|
action toResult: CaseKeyPath<Action, TaskResult<T>>,
|
||||||
operation: @escaping @Sendable () async throws -> T
|
operation: @escaping @Sendable () async throws -> T
|
||||||
) -> Self {
|
) -> Self {
|
||||||
.receive(AnyCasePath(toResult), operation)
|
.receive(operation: .case(AnyCasePath(toResult), operation))
|
||||||
}
|
}
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
@@ -43,7 +25,7 @@ extension Effect {
|
|||||||
operation: @escaping @Sendable () async throws -> T,
|
operation: @escaping @Sendable () async throws -> T,
|
||||||
transform: @escaping @Sendable (T) -> V
|
transform: @escaping @Sendable (T) -> V
|
||||||
) -> Self {
|
) -> Self {
|
||||||
.receive(AnyCasePath(toResult), operation, transform)
|
.receive(operation: .case(AnyCasePath(toResult), operation, transform))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +36,7 @@ extension Effect where Action: ReceiveAction {
|
|||||||
_ operation: @escaping @Sendable () async throws -> T,
|
_ operation: @escaping @Sendable () async throws -> T,
|
||||||
transform: @escaping @Sendable (T) -> Action.ReceiveAction
|
transform: @escaping @Sendable (T) -> Action.ReceiveAction
|
||||||
) -> Self {
|
) -> Self {
|
||||||
.receive(AnyCasePath(unsafe: Action.receive), operation, transform)
|
.receive(operation: .case(AnyCasePath(unsafe: Action.receive), operation, transform))
|
||||||
}
|
}
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
@@ -68,3 +50,51 @@ extension Effect where Action: ReceiveAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@usableFromInline
|
||||||
|
struct ReceiveOperation<Action, Input, Result> {
|
||||||
|
|
||||||
|
@usableFromInline
|
||||||
|
let embed: @Sendable (TaskResult<Result>) -> Action
|
||||||
|
|
||||||
|
@usableFromInline
|
||||||
|
let operation: @Sendable () async throws -> Input
|
||||||
|
|
||||||
|
@usableFromInline
|
||||||
|
let transform: @Sendable (Input) -> Result
|
||||||
|
|
||||||
|
@usableFromInline
|
||||||
|
func callAsFunction(send: Send<Action>) async {
|
||||||
|
await send(embed(
|
||||||
|
TaskResult { try await operation() }
|
||||||
|
.map(transform)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
@usableFromInline
|
||||||
|
static func `case`(
|
||||||
|
_ casePath: AnyCasePath<Action, TaskResult<Result>>,
|
||||||
|
_ operation: @escaping @Sendable () async throws -> Input,
|
||||||
|
_ transform: @escaping @Sendable (Input) -> Result
|
||||||
|
) -> Self {
|
||||||
|
.init(embed: { casePath.embed($0) }, operation: operation, transform: transform)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ReceiveOperation where Input == Result {
|
||||||
|
|
||||||
|
@usableFromInline
|
||||||
|
init(
|
||||||
|
embed: @escaping @Sendable (TaskResult<Result>) -> Action,
|
||||||
|
operation: @escaping @Sendable () async throws -> Input
|
||||||
|
) {
|
||||||
|
self.init(embed: embed, operation: operation, transform: { $0 })
|
||||||
|
}
|
||||||
|
|
||||||
|
@usableFromInline
|
||||||
|
static func `case`(
|
||||||
|
_ casePath: AnyCasePath<Action, TaskResult<Result>>,
|
||||||
|
_ operation: @escaping @Sendable () async throws -> Input
|
||||||
|
) -> Self {
|
||||||
|
.init(embed: { casePath.embed($0) }, operation: operation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,3 +30,20 @@ enum SetAction<State, Action, Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@usableFromInline
|
||||||
|
struct SetAction2<State, Action, Value> {
|
||||||
|
let operation: @Sendable (inout State, Value) -> Void
|
||||||
|
|
||||||
|
init(_ operation: @escaping @Sendable (inout State, Value) -> Void) {
|
||||||
|
self.operation = operation
|
||||||
|
}
|
||||||
|
|
||||||
|
static func keyPath(
|
||||||
|
_ keyPath: WritableKeyPath<State, Value>
|
||||||
|
) -> Self {
|
||||||
|
.init({ state, value in
|
||||||
|
state[keyPath: keyPath] = value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import Foundation
|
|||||||
import OSLog
|
import OSLog
|
||||||
|
|
||||||
public enum OnFailAction<State, Action> {
|
public enum OnFailAction<State, Action> {
|
||||||
case fail(prefix: String? = nil, log: ((String) -> Void)? = nil)
|
case fail(prefix: String? = nil, log: (@Sendable (String) -> Void)? = nil)
|
||||||
case operation((inout State, Error) -> Effect<Action>)
|
case operation((inout State, Error) -> Effect<Action>)
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
|
|||||||
@@ -188,13 +188,15 @@ public struct _OnReceiveReducer<Parent: Reducer, Value>: Reducer {
|
|||||||
action: Parent.Action
|
action: Parent.Action
|
||||||
) -> Effect<Parent.Action> {
|
) -> Effect<Parent.Action> {
|
||||||
let baseEffects = parent.reduce(into: &state, action: action)
|
let baseEffects = parent.reduce(into: &state, action: action)
|
||||||
var setEffects = Effect<Action>.none
|
|
||||||
|
|
||||||
if let value = receiveAction(action) {
|
guard let value = receiveAction(action) else {
|
||||||
setEffects = setAction(state: &state, value: value)
|
return baseEffects
|
||||||
}
|
}
|
||||||
|
|
||||||
return .merge(baseEffects, setEffects)
|
return .merge(
|
||||||
|
baseEffects,
|
||||||
|
setAction(state: &state, value: value)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,13 +210,13 @@ public struct _ReceiveOnTriggerReducer<
|
|||||||
let parent: Parent
|
let parent: Parent
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
let triggerAction: (Parent.Action) -> TriggerAction?
|
let triggerAction: @Sendable (Parent.Action) -> TriggerAction?
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
let toReceiveAction: (TaskResult<Value>) -> Parent.Action
|
let toReceiveAction: @Sendable (TaskResult<Value>) -> Parent.Action
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
let resultHandler: () async throws -> Value
|
let resultHandler: @Sendable () async throws -> Value
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
init(
|
init(
|
||||||
@@ -242,11 +244,7 @@ public struct _ReceiveOnTriggerReducer<
|
|||||||
|
|
||||||
return .merge(
|
return .merge(
|
||||||
baseEffects,
|
baseEffects,
|
||||||
.run { send in
|
.receive(operation: .init(embed: toReceiveAction, operation: resultHandler))
|
||||||
await send(toReceiveAction(
|
|
||||||
TaskResult { try await resultHandler() }
|
|
||||||
))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user