Skip to content

Commit 9fd1942

Browse files
committed
wip
1 parent 73cde08 commit 9fd1942

File tree

9 files changed

+120
-15
lines changed

9 files changed

+120
-15
lines changed

Sources/SimplexArchitecture/Effect/CombineAction.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public extension CombineAction {
2828
.init(kind: .viewAction(action: action))
2929
}
3030

31+
@_disfavoredOverload
3132
@inlinable
3233
static func action(
3334
_ action: Reducer.ReducerAction

Sources/SimplexArchitecture/Effect/SideEffect.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public struct SideEffect<Reducer: ReducerProtocol>: Sendable {
1717
case concurrentReducerAction([Reducer.ReducerAction])
1818
case serialCombineAction([CombineAction<Reducer>])
1919
case concurrentCombineAction([CombineAction<Reducer>])
20+
case runEffects([SideEffect<Reducer>])
2021
}
2122

2223
let kind: EffectKind
@@ -86,4 +87,9 @@ public extension SideEffect {
8687
static func serial(_ actions: CombineAction<Reducer>...) -> Self {
8788
.init(effectKind: .serialCombineAction(actions))
8889
}
90+
91+
@inlinable
92+
static func runEffects(_ effects: [SideEffect<Reducer>]) -> Self {
93+
.init(effectKind: .runEffects(effects))
94+
}
8995
}

Sources/SimplexArchitecture/Reducer/DependenciesOverrideModifier.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
11
import Dependencies
22

3-
public struct _DependenciesOverrideModifier<Base: ReducerProtocol>: _ReducerModifier {
3+
public struct _DependenciesOverrideModifier<Base: ReducerProtocol>: ReducerModifier {
44
public let base: Base
55
public let override: (inout DependencyValues) -> Void
66

7+
@usableFromInline
8+
init(base: Base, override: @escaping (inout DependencyValues) -> Void) {
9+
self.base = base
10+
self.override = override
11+
}
12+
13+
@inlinable
714
public func reduce(into state: StateContainer<Base.Target>, action: Base.Action) -> SideEffect<Base> {
815
withDependencies(override) {
916
base.reduce(into: state, action: action)
1017
}
1118
}
1219

20+
@inlinable
1321
public func reduce(into state: StateContainer<Base.Target>, action: Base.ReducerAction) -> SideEffect<Base> {
1422
withDependencies(override) {
1523
base.reduce(into: state, action: action)
1624
}
1725
}
1826

27+
@inlinable
1928
public func dependency<Value>(
2029
_ keyPath: WritableKeyPath<DependencyValues, Value>,
2130
value: Value
@@ -28,6 +37,7 @@ public struct _DependenciesOverrideModifier<Base: ReducerProtocol>: _ReducerModi
2837
}
2938

3039
public extension ReducerProtocol {
40+
@inlinable
3141
func dependency<Value>(
3242
_ keyPath: WritableKeyPath<DependencyValues, Value>,
3343
value: Value

Sources/SimplexArchitecture/Reducer/ReducerModifier.swift

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
import Foundation
22
import Dependencies
33

4-
public protocol _ReducerModifier<Base> {
4+
public protocol ReducerModifier<Base> {
55
associatedtype Base: ReducerProtocol
6-
var base: Base { get }
76
func reduce(into state: StateContainer<Base.Target>, action: Base.Action) -> SideEffect<Base>
8-
/// Evolve the current state of ActionSendable to the next state.
9-
///
10-
/// - Parameters:
11-
/// - state: Current state of ActionSendable and ReducerState. ReducerState can be accessed from the `reducerState` property of State..
12-
/// - action: A ReducerAction that can change the state of View and ReducerState.
13-
/// - Returns: An `SideEffect` representing the side effects generated by the reducer.
147
func reduce(into state: StateContainer<Base.Target>, action: Base.ReducerAction) -> SideEffect<Base>
158
}
169

17-
public extension _ReducerModifier {
10+
public extension ReducerModifier {
1811
@inlinable
1912
func reduce(
2013
into state: StateContainer<Base.Target>,

Sources/SimplexArchitecture/Reducer/ReducerProtocol.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ public protocol ReducerProtocol<Target> {
114114
/// - action: A ReducerAction that can change the state of View and ReducerState.
115115
/// - Returns: An `SideEffect` representing the side effects generated by the reducer.
116116
func reduce(into state: StateContainer<Target>, action: ReducerAction) -> SideEffect<Self>
117+
118+
associatedtype Children = Never
117119
}
118120

119121
public extension ReducerProtocol where ReducerAction == Never {

Sources/SimplexArchitecture/Store/Store.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ public final class Store<Reducer: ReducerProtocol> {
3737
self.initialReducerState = initialReducerState
3838
}
3939

40-
public init<R: _ReducerModifier<Reducer>>(
40+
public init<R: ReducerModifier<Reducer>>(
4141
reducer: R
4242
) where Reducer.ReducerState == Never {
4343
self.reduce = reducer.reduce
4444
}
4545

4646
/// Initialize `Store` with the given `Reducer` and initial `ReducerState`.
47-
public init<R: _ReducerModifier<Reducer>>(
47+
public init<R: ReducerModifier<Reducer>>(
4848
reducer: R,
4949
initialReducerState: @autoclosure @escaping () -> Reducer.ReducerState
5050
) {
@@ -213,6 +213,11 @@ extension Store {
213213
}
214214
return [SendTask(task: task)]
215215

216+
case let .runEffects(effects):
217+
return effects.reduce(into: [SendTask]()) { partialResult, effect in
218+
partialResult += runEffect(effect, send: send)
219+
}
220+
216221
case .none:
217222
return []
218223
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
@testable import SimplexArchitecture
2+
import SwiftUI
3+
import Dependencies
4+
import XCTest
5+
6+
final class DependenciesOverrideModifierTests: XCTestCase {
7+
func testModifier() async {
8+
let base = BaseView(
9+
store: Store(
10+
reducer: _DependenciesOverrideModifier(base: BaseReducer()) {
11+
$0.test = .init(asyncThrows: {})
12+
}
13+
)
14+
)
15+
let container = base.store.setContainerIfNeeded(for: base, states: .init())
16+
await base.send(.test).wait()
17+
XCTAssertEqual(container.count, 1)
18+
}
19+
}
20+
21+
struct BaseReducer: ReducerProtocol {
22+
enum Action {
23+
case test
24+
case callback
25+
}
26+
27+
@Dependency(\.test) var test
28+
29+
func reduce(into state: StateContainer<BaseView>, action: Action) -> SideEffect<BaseReducer> {
30+
switch action {
31+
case .test:
32+
return .run { send in
33+
try await test.asyncThrows()
34+
await send(.callback)
35+
}
36+
case .callback:
37+
state.count += 1
38+
return .none
39+
}
40+
}
41+
}
42+
43+
@ScopeState
44+
struct BaseView: View {
45+
@State var count: Int = 0
46+
let store: Store<BaseReducer>
47+
48+
init(store: Store<BaseReducer> = .init(reducer: BaseReducer())) {
49+
self.store = store
50+
}
51+
52+
var body: some View { EmptyView() }
53+
}

Tests/SimplexArchitectureTests/ReducerTests.swift

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,7 @@ final class ReducerTests: XCTestCase {
9999
func testDependencies() async {
100100
let testStore = TestView(
101101
store: .init(
102-
reducer: TestReducer()
103-
.dependency(\.test, value: .init {})
104-
,
102+
reducer: TestReducer().dependency(\.test, value: .init {}),
105103
initialReducerState: .init()
106104
)
107105
).testStore(states: .init())
@@ -231,3 +229,27 @@ private struct TestView: View {
231229
EmptyView()
232230
}
233231
}
232+
233+
private struct MyReducer: ReducerProtocol {
234+
enum Action {
235+
case hoge
236+
}
237+
238+
func reduce(into state: StateContainer<MyView>, action: Action) -> SideEffect<MyReducer> {
239+
.none
240+
}
241+
}
242+
243+
@ScopeState
244+
private struct MyView: View {
245+
@State var count = 0
246+
let store: Store<MyReducer>
247+
248+
init(store: Store<MyReducer> = Store(reducer: MyReducer())) {
249+
self.store = store
250+
}
251+
252+
var body: some View {
253+
EmptyView()
254+
}
255+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Foundation
2+
3+
typealias Original = @convention(thin) (UnownedJob) -> Void
4+
typealias Hook = @convention(thin) (UnownedJob, Original) -> Void
5+
6+
private let _swift_task_enqueueGlobal_hook = dlsym(
7+
dlopen(nil, 0), "swift_task_enqueueGlobal_hook"
8+
).assumingMemoryBound(to: Hook?.self)
9+
10+
var swift_task_enqueueGlobal_hook: Hook? {
11+
get { _swift_task_enqueueGlobal_hook.pointee }
12+
set { _swift_task_enqueueGlobal_hook.pointee = newValue }
13+
}

0 commit comments

Comments
 (0)