File tree Expand file tree Collapse file tree
Examples/DripperDemo/DripperDemo Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -40,17 +40,18 @@ struct Counter: Dripper {
4040 case . resetCounter:
4141 state. counter = . zero
4242 case . randomNumber:
43- return . init { _ in
43+ return . run { pour in
4444 func randomNumber( ) async throws -> Int {
45- try await Task . sleep ( for: . seconds( 2 ) )
45+ try await Task . sleep ( for: . seconds( 1 ) )
4646 return Int . random ( in: 0 ... 10 )
4747 }
4848 let randomNumber = try await randomNumber ( )
49+ await pour ( . decreaseCounter)
4950 state. counter = randomNumber
5051 }
5152 }
5253
53- return . init { _ in }
54+ return . none
5455 }
5556 }
5657}
Original file line number Diff line number Diff line change @@ -11,7 +11,7 @@ public struct Drip<State: Observable, Action>: Dripper {
1111
1212 // MARK: Properties
1313
14- @usableFromInline let drip : ( State , Action ) -> Effect < Action >
14+ @usableFromInline let drip : ( State , Action ) -> Effect < Action > ?
1515
1616 // MARK: Lifecycle
1717
@@ -25,14 +25,14 @@ public struct Drip<State: Observable, Action>: Dripper {
2525 }
2626
2727 @usableFromInline
28- init ( internal drip: @escaping ( _ state: State , _ action: Action ) -> Effect < Action > ) {
28+ init ( internal drip: @escaping ( _ state: State , _ action: Action ) -> Effect < Action > ? ) {
2929 self . drip = drip
3030 }
3131
3232 // MARK: Functions
3333
3434 @inlinable
35- public func drip( _ state: State , _ action: Action ) -> Effect < Action > {
35+ public func drip( _ state: State , _ action: Action ) -> Effect < Action > ? {
3636 drip ( state, action)
3737 }
3838}
Original file line number Diff line number Diff line change @@ -16,7 +16,7 @@ public protocol Dripper<State, Action> {
1616 associatedtype Action
1717 associatedtype Body
1818
19- func drip( _ state: State , _ action: Action ) -> Effect < Action >
19+ func drip( _ state: State , _ action: Action ) -> Effect < Action > ?
2020
2121 @DripperBuilder < State , Action >
2222 var body : Body { get }
@@ -30,7 +30,7 @@ extension Dripper where Body == Never {
3030
3131extension Dripper where Body: Dripper < State , Action > {
3232 @inlinable
33- public func drip( _ state: Body . State , _ action: Body . Action ) -> Effect < Action > {
33+ public func drip( _ state: Body . State , _ action: Body . Action ) -> Effect < Action > ? {
3434 body. drip ( state, action)
3535 }
3636}
Original file line number Diff line number Diff line change 66//
77
88import Foundation
9+ import OSLog
10+
11+ // MARK: - Effect
912
1013public struct Effect < Action> {
11- public typealias ActionHandler = @MainActor @Sendable ( Action ) -> Void
14+ public typealias Kettle = @Sendable ( _ blend: Pour < Action > ) async -> Void
15+
16+ @usableFromInline let kettle : Kettle
17+
18+ @usableFromInline
19+ init ( kettle: @escaping Kettle ) {
20+ self . kettle = kettle
21+ }
22+ }
23+
24+ // MARK: - Pour
25+
26+ @MainActor
27+ public struct Pour < Action> : Sendable {
28+ let pour : @MainActor @Sendable ( Action ) -> Void
29+
30+ init ( pour: @escaping @MainActor @Sendable ( Action ) -> Void ) {
31+ self . pour = pour
32+ }
33+
34+ public func callAsFunction( _ action: Action ) {
35+ pour ( action)
36+ }
37+ }
38+
39+ extension Effect {
40+
41+ // MARK: Static Computed Properties
42+
43+ public static var none : Self {
44+ Self { _ in }
45+ }
1246
13- public let run : ( _ action : ActionHandler ) async throws -> Void
47+ // MARK: Static Functions
1448
15- public init ( run: @escaping ( _ action: ActionHandler ) async throws -> Void ) {
16- self . run = run
49+ public static func run(
50+ kettle: @escaping @Sendable ( _ pour: Pour < Action > ) async throws -> Void ,
51+ catch errorHandler: ( @Sendable ( _ error: any Error , _ pour: Pour < Action > ) async -> Void ) ? = nil ,
52+ fileID: StaticString = #fileID,
53+ line: UInt = #line
54+ ) -> Self {
55+ Self { pour in
56+ do {
57+ try await kettle ( pour)
58+ } catch {
59+ guard let errorHandler else {
60+ os_log (
61+ . fault,
62+ """
63+ An " Effect.run " returned from " \( fileID) : \( line) " threw an unhandled error.
64+ This error must be handled via the `catch` parameter.
65+ """
66+ )
67+ return
68+ }
69+ await errorHandler ( error, pour)
70+ }
71+ }
1772 }
1873}
Original file line number Diff line number Diff line change @@ -49,10 +49,12 @@ public final class Station<State: Observable, Action> {
4949
5050 public func pour( _ action: Action ) {
5151 let effect = dripper. drip ( state, action)
52- // FIXME: Currently, side effect is called no matter it's empty or not.
53- Task {
54- try await effect. run { action in
55- pour ( action)
52+
53+ if let effect {
54+ Task {
55+ await effect. kettle (
56+ Pour { self . pour ( $0) }
57+ )
5658 }
5759 }
5860 }
You can’t perform that action at this time.
0 commit comments