@@ -15,9 +15,46 @@ public protocol Event {}
15
15
16
16
// MARK: - Commands
17
17
18
- public protocol Command {
18
+ public protocol AnyCommand {
19
+ func _execute( state: Any , core: Any )
20
+ func _canExecute( state: Any ) -> Bool
21
+ var expiresAfter : TimeInterval { get }
22
+ }
23
+
24
+ extension AnyCommand {
25
+ var expiresAfter : TimeInterval { return 10.0 }
26
+ }
27
+
28
+ public protocol Command : AnyCommand {
19
29
associatedtype StateType : State
20
30
func execute( state: StateType , core: Core < StateType > )
31
+ func canExecute( state: StateType ) -> Bool
32
+ }
33
+
34
+ extension Command {
35
+
36
+ public func canExecute( state: StateType ) -> Bool {
37
+ return true
38
+ }
39
+
40
+ public func _canExecute( state: Any ) -> Bool {
41
+ if let state = state as? StateType {
42
+ return canExecute ( state: state)
43
+ } else {
44
+ return false
45
+ }
46
+ }
47
+
48
+ public func _execute( state: Any , core: Any ) {
49
+ if let state = state as? StateType , let core = core as? Core < StateType > {
50
+ execute ( state: state, core: core)
51
+ }
52
+ }
53
+ }
54
+
55
+ public struct Commands < StateType: State > {
56
+ private( set) var expiresAt : Date
57
+ private( set) var command : AnyCommand
21
58
}
22
59
23
60
@@ -88,20 +125,33 @@ public class Core<StateType: State> {
88
125
89
126
private let jobQueue : DispatchQueue = DispatchQueue ( label: " reactor.core.queue " , qos: . userInitiated, attributes: [ ] )
90
127
91
- private let subscriptionsSyncQueue = DispatchQueue ( label: " reactor.core.subscription .sync " )
128
+ private let internalSyncQueue = DispatchQueue ( label: " reactor.core.internal .sync " )
92
129
private var _subscriptions = [ Subscription < StateType > ] ( )
93
130
private var subscriptions : [ Subscription < StateType > ] {
94
131
get {
95
- return subscriptionsSyncQueue . sync {
132
+ return internalSyncQueue . sync {
96
133
return self . _subscriptions
97
134
}
98
135
}
99
136
set {
100
- subscriptionsSyncQueue . sync {
137
+ internalSyncQueue . sync {
101
138
self . _subscriptions = newValue
102
139
}
103
140
}
104
141
}
142
+ private var _commands = [ Commands < StateType > ] ( )
143
+ private var commands : [ Commands < StateType > ] {
144
+ get {
145
+ return internalSyncQueue. sync {
146
+ return self . _commands
147
+ }
148
+ }
149
+ set {
150
+ internalSyncQueue. sync {
151
+ self . _commands = newValue
152
+ }
153
+ }
154
+ }
105
155
106
156
private let middlewares : [ Middlewares < StateType > ]
107
157
public private ( set) var state : StateType {
@@ -140,13 +190,25 @@ public class Core<StateType: State> {
140
190
jobQueue. async {
141
191
self . state. react ( to: event)
142
192
let state = self . state
193
+ let executable = self . commands. enumerated ( ) . filter { $1. command. _canExecute ( state: state) }
194
+ executable. forEach {
195
+ self . commands. remove ( at: $0)
196
+ $1. command. _execute ( state: state, core: self )
197
+ }
198
+ let now = Date ( )
199
+ let expired = self . commands. enumerated ( ) . filter { $1. expiresAt < now }
200
+ expired. forEach { self . commands. remove ( at: $0. offset) }
143
201
self . middlewares. forEach { $0. middleware. _process ( event: event, state: state) }
144
202
}
145
203
}
146
204
147
205
public func fire< C: Command > ( command: C ) where C. StateType == StateType {
148
- jobQueue. async {
149
- command. execute ( state: self . state, core: self )
206
+ if command. canExecute ( state: state) {
207
+ jobQueue. async {
208
+ command. execute ( state: self . state, core: self )
209
+ }
210
+ } else {
211
+ commands. append ( Commands ( expiresAt: Date ( ) . addingTimeInterval ( command. expiresAfter) , command: command) )
150
212
}
151
213
}
152
214
0 commit comments