@@ -54,16 +54,33 @@ open class StateMachine<State: StateMachineHashable, Event: StateMachineHashable
5454 private let states : States
5555 private var observers : [ Observer ] = [ ]
5656
57+ private typealias EnterExitAction = ( State ) throws -> Void
58+
59+ private var onEnterActions : [ State . HashableIdentifier : EnterExitAction ]
60+ private var onExitActions : [ State . HashableIdentifier : EnterExitAction ]
61+
5762 private var isNotifying : Bool = false
5863
5964 public init ( @DefinitionBuilder build: ( ) -> Definition ) {
6065 let definition : Definition = build ( )
6166 state = definition. initialState. state
62- states = definition. states. reduce ( into: States ( ) ) {
63- $0 [ $1. state] = $1. events. reduce ( into: Events ( ) ) {
64- $0 [ $1. event] = $1. action
67+ var enterActions : [ State . HashableIdentifier : EnterExitAction ] = [ : ]
68+ var exitActions : [ State . HashableIdentifier : EnterExitAction ] = [ : ]
69+ states = definition. states. reduce ( into: States ( ) ) { result, tuple in
70+ let ( state, events) = tuple
71+ result [ state] = events. reduce ( into: Events ( ) ) {
72+ switch $1. eventType {
73+ case . onEnter( let action) :
74+ enterActions [ state] = action
75+ case . onExit( let action) :
76+ exitActions [ state] = action
77+ case . normal( let event, let action) :
78+ $0 [ event] = action
79+ }
6580 }
6681 }
82+ onEnterActions = enterActions
83+ onExitActions = exitActions
6784 observers = definition. callbacks. map {
6885 Observer ( object: self , callback: $0)
6986 }
@@ -104,10 +121,18 @@ open class StateMachine<State: StateMachineHashable, Event: StateMachineHashable
104121 event: event,
105122 toState: action. toState ?? state,
106123 sideEffects: action. sideEffects)
124+ let fromState = state
107125 if let toState: State = action. toState {
108126 state = toState
109127 }
128+
110129 result = . success( transition)
130+
131+ // if not `dontTransition`
132+ if action. toState != nil {
133+ try ? onExitActions [ stateIdentifier] ? ( fromState)
134+ try ? onEnterActions [ state. hashableIdentifier] ? ( state)
135+ }
111136 } else {
112137 result = . failure( Transition . Invalid ( ) )
113138 }
@@ -172,25 +197,41 @@ extension StateMachineBuilder {
172197 . state( state: state, events: build ( ) )
173198 }
174199
200+ public static func onEnter( _ perform: @escaping ( State ) throws -> Void ) -> [ EventHandler ] {
201+ [ EventHandler ( eventType: . onEnter( perform) ) ]
202+ }
203+
204+ public static func onExit( _ perform: @escaping ( State ) throws -> Void ) -> [ EventHandler ] {
205+ [ EventHandler ( eventType: . onExit( perform) ) ]
206+ }
207+
208+ public static func onEnter( _ perform: @escaping ( ) throws -> Void ) -> [ EventHandler ] {
209+ [ EventHandler ( eventType: . onEnter( { _ in try perform ( ) } ) ) ]
210+ }
211+
212+ public static func onExit( _ perform: @escaping ( ) throws -> Void ) -> [ EventHandler ] {
213+ [ EventHandler ( eventType: . onExit( { _ in try perform ( ) } ) ) ]
214+ }
215+
175216 public static func on(
176217 _ event: Event . HashableIdentifier ,
177218 perform: @escaping ( State , Event ) throws -> Action
178219 ) -> [ EventHandler ] {
179- [ EventHandler ( event : event, action : perform) ]
220+ [ EventHandler ( eventType : . normal ( event, perform) ) ]
180221 }
181222
182223 public static func on(
183224 _ event: Event . HashableIdentifier ,
184225 perform: @escaping ( State ) throws -> Action
185226 ) -> [ EventHandler ] {
186- [ EventHandler ( event : event) { state, _ in try perform ( state) } ]
227+ [ EventHandler ( eventType : . normal ( event, { state, _ in try perform ( state) } ) ) ]
187228 }
188229
189230 public static func on(
190231 _ event: Event . HashableIdentifier ,
191232 perform: @escaping ( ) throws -> Action
192233 ) -> [ EventHandler ] {
193- [ EventHandler ( event : event) { _, _ in try perform ( ) } ]
234+ [ EventHandler ( eventType : . normal ( event, { _, _ in try perform ( ) } ) ) ]
194235 }
195236
196237 public static func transition(
@@ -277,8 +318,14 @@ public enum StateMachineTypes {
277318
278319 public struct EventHandler < State: StateMachineHashable , Event: StateMachineHashable , SideEffect> {
279320
280- fileprivate let event : Event . HashableIdentifier
281- fileprivate let action : Action < State , Event , SideEffect > . Factory
321+ fileprivate var eventType : EventType < State , Event , SideEffect >
322+
323+ fileprivate enum EventType < State: StateMachineHashable , Event: StateMachineHashable , SideEffect> {
324+
325+ case normal( Event . HashableIdentifier , Action < State , Event , SideEffect > . Factory )
326+ case onEnter( ( State ) throws -> Void )
327+ case onExit( ( State ) throws -> Void )
328+ }
282329 }
283330
284331 public struct Action < State: StateMachineHashable , Event: StateMachineHashable , SideEffect> {
0 commit comments