@@ -15,9 +15,46 @@ public protocol Event {}
1515
1616// MARK: - Commands
1717
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 {
1929 associatedtype StateType : State
2030 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
2158}
2259
2360
@@ -88,20 +125,33 @@ public class Core<StateType: State> {
88125
89126 private let jobQueue : DispatchQueue = DispatchQueue ( label: " reactor.core.queue " , qos: . userInitiated, attributes: [ ] )
90127
91- private let subscriptionsSyncQueue = DispatchQueue ( label: " reactor.core.subscription .sync " )
128+ private let internalSyncQueue = DispatchQueue ( label: " reactor.core.internal .sync " )
92129 private var _subscriptions = [ Subscription < StateType > ] ( )
93130 private var subscriptions : [ Subscription < StateType > ] {
94131 get {
95- return subscriptionsSyncQueue . sync {
132+ return internalSyncQueue . sync {
96133 return self . _subscriptions
97134 }
98135 }
99136 set {
100- subscriptionsSyncQueue . sync {
137+ internalSyncQueue . sync {
101138 self . _subscriptions = newValue
102139 }
103140 }
104141 }
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+ }
105155
106156 private let middlewares : [ Middlewares < StateType > ]
107157 public private ( set) var state : StateType {
@@ -140,13 +190,25 @@ public class Core<StateType: State> {
140190 jobQueue. async {
141191 self . state. react ( to: event)
142192 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) }
143201 self . middlewares. forEach { $0. middleware. _process ( event: event, state: state) }
144202 }
145203 }
146204
147205 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) )
150212 }
151213 }
152214
0 commit comments