import ComposableArchitecture extension Reducer { public func onReceive( action toReceiveAction: CaseKeyPath, set setAction: @escaping (inout State, V) -> Void ) -> _ReceiveReducer { .init( parent: self, receiveAction: AnyCasePath(toReceiveAction), setAction: setAction ) } public func onReceive( action toReceiveAction: CaseKeyPath, set toStateKeyPath: WritableKeyPath ) -> _ReceiveReducer { self.onReceive(action: toReceiveAction, set: toStateKeyPath.callAsFunction(root:value:)) } public func onReceive( action toReceiveAction: CaseKeyPath, set toStateKeyPath: WritableKeyPath ) -> _ReceiveReducer { self.onReceive(action: toReceiveAction, set: toStateKeyPath.callAsFunction(root:value:)) } public func onReceive( action toReceiveAction: CaseKeyPath>, onSuccess setAction: @escaping (inout State, V) -> Void, onFail: OnFailAction? = nil ) -> _ReceiveReducer> { self.onReceive(action: toReceiveAction) { state, result in switch result { case let .failure(error): if let onFail { onFail(state: &state, error: error) } case let .success(value): setAction(&state, value) } } } public func onReceive( action toReceiveAction: CaseKeyPath>, onSuccess toStateKeyPath: WritableKeyPath, onFail: OnFailAction? = nil ) -> _ReceiveReducer> { self.onReceive(action: toReceiveAction) { state, result in switch result { case let .failure(error): if let onFail { onFail(state: &state, error: error) } case let .success(value): toStateKeyPath(root: &state, value: value) } } } public func onReceive( action toReceiveAction: CaseKeyPath>, onSuccess toStateKeyPath: WritableKeyPath, onFail: OnFailAction? = nil ) -> _ReceiveReducer> { self.onReceive(action: toReceiveAction) { state, result in switch result { case let .failure(error): if let onFail { onFail(state: &state, error: error) } case let .success(value): toStateKeyPath(root: &state, value: value) } } } } public enum OnFailAction { case xctFail case handle((inout State, Error) -> Void) @usableFromInline func callAsFunction(state: inout State, error: Error) { switch self { case .xctFail: XCTFail("\(error)") case let .handle(handler): handler(&state, error) } } } fileprivate extension WritableKeyPath { func callAsFunction(root: inout Root, value: Value) { root[keyPath: self] = value } } public struct _ReceiveReducer: Reducer { @usableFromInline let parent: Parent @usableFromInline let receiveAction: AnyCasePath @usableFromInline let setAction: (inout Parent.State, Value) -> Void public func reduce(into state: inout Parent.State, action: Parent.Action) -> Effect { let baseEffects = parent.reduce(into: &state, action: action) if let value = receiveAction.extract(from: action) { setAction(&state, value) } return baseEffects } }