Skip to content

Commit 7c7969d

Browse files
committed
Add state for onEnter and onExit events
1 parent 318f1b0 commit 7c7969d

File tree

3 files changed

+33
-29
lines changed

3 files changed

+33
-29
lines changed

Swift/Sources/StateMachine/StateMachine.swift

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ open class StateMachine<State: StateMachineHashable, Event: StateMachineHashable
5656
private let states: States
5757
private var observers: [Observer] = []
5858

59-
private typealias EnterExitAction = () -> Void
59+
private typealias EnterExitAction = (State) throws -> Void
6060

6161
private var onEnterActions: [State.HashableIdentifier: EnterExitAction]
6262
private var onExitActions: [State.HashableIdentifier: EnterExitAction]
@@ -127,13 +127,15 @@ open class StateMachine<State: StateMachineHashable, Event: StateMachineHashable
127127
event: event,
128128
toState: action.toState ?? state,
129129
sideEffect: action.sideEffect)
130+
let fromState = state
130131
if let toState: State = action.toState {
131132
state = toState
132133
}
133134

134-
if stateIdentifier != state.hashableIdentifier {
135-
onExitActions[stateIdentifier]?()
136-
onEnterActions[state.hashableIdentifier]?()
135+
// if not `dontTransition`
136+
if action.toState != nil {
137+
try onExitActions[stateIdentifier]?(fromState)
138+
try onEnterActions[state.hashableIdentifier]?(state)
137139
}
138140

139141
result = .success(transition)
@@ -201,11 +203,11 @@ extension StateMachineBuilder {
201203
.state(state: state, events: build())
202204
}
203205

204-
public static func onEnter(_ perform: @escaping () -> Void) -> [EventHandler] {
206+
public static func onEnter(_ perform: @escaping (State) throws -> Void) -> [EventHandler] {
205207
[EventHandler(event: nil, action: nil, eventType: .onEnter(perform))]
206208
}
207209

208-
public static func onExit(_ perform: @escaping () -> Void) -> [EventHandler] {
210+
public static func onExit(_ perform: @escaping (State) throws -> Void) -> [EventHandler] {
209211
[EventHandler(event: nil, action: nil, eventType: .onExit(perform))]
210212
}
211213

@@ -312,15 +314,15 @@ public enum StateMachineTypes {
312314
}
313315
}
314316

315-
fileprivate enum EventType {
316-
case normal, onEnter(() -> Void), onExit(() -> Void)
317+
fileprivate enum EventType<State> {
318+
case normal, onEnter((State) throws -> Void), onExit((State) throws -> Void)
317319
}
318320

319321
public struct EventHandler<State: StateMachineHashable, Event: StateMachineHashable, SideEffect> {
320322

321323
fileprivate let event: Event.HashableIdentifier?
322324
fileprivate let action: Action<State, Event, SideEffect>.Factory?
323-
fileprivate var eventType = EventType.normal
325+
fileprivate var eventType = EventType<State>.normal
324326
}
325327

326328
public struct Action<State: StateMachineHashable, Event: StateMachineHashable, SideEffect> {

Swift/Tests/StateMachineTests/StateMachine_Matter_Tests.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,21 @@ final class StateMachine_Matter_Tests: XCTestCase, StateMachineBuilder {
4646
MatterStateMachine {
4747
initialState(_state)
4848
state(.solid) {
49-
onEnter {
49+
onEnter { _ in
5050
logger.log(Message.enteredSolid.rawValue)
5151
}
52-
onExit {
52+
onExit { _ in
5353
logger.log(Message.exitSolid.rawValue)
5454
}
5555
on(.melt) {
5656
transition(to: .liquid, emit: .logMelted)
5757
}
5858
}
5959
state(.liquid) {
60-
onEnter {
60+
onEnter { _ in
6161
logger.log(Message.enteredLiquid.rawValue)
6262
}
63-
onExit {
63+
onExit { _ in
6464
logger.log(Message.exitLiquid.rawValue)
6565
}
6666
on(.freeze) {
@@ -71,10 +71,10 @@ final class StateMachine_Matter_Tests: XCTestCase, StateMachineBuilder {
7171
}
7272
}
7373
state(.gas) {
74-
onEnter {
74+
onEnter { _ in
7575
logger.log(Message.enteredGas.rawValue)
7676
}
77-
onExit {
77+
onExit { _ in
7878
logger.log(Message.exitGas.rawValue)
7979
}
8080
on(.condense) {

Swift/Tests/StateMachineTests/StateMachine_Turnstile_Tests.swift

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ final class StateMachine_Turnstile_Tests: XCTestCase, StateMachineBuilder {
4545
TurnstileStateMachine {
4646
initialState(_state)
4747
state(.locked) {
48-
onEnter {
49-
logger.log(Message.enterLocked.rawValue)
48+
onEnter { state in
49+
let credit: Int = try state.credit()
50+
logger.log("\(Message.enterLocked.rawValue) \(credit)")
5051
}
51-
onExit {
52-
logger.log(Message.exitLocked.rawValue)
52+
onExit { state in
53+
let credit: Int = try state.credit()
54+
logger.log("\(Message.exitLocked.rawValue) \(credit)")
5355
}
5456
on(.insertCoin) { locked, insertCoin in
5557
let newCredit: Int = try locked.credit() + insertCoin.value()
@@ -67,21 +69,21 @@ final class StateMachine_Turnstile_Tests: XCTestCase, StateMachineBuilder {
6769
}
6870
}
6971
state(.unlocked) {
70-
onEnter {
72+
onEnter { _ in
7173
logger.log(Message.enterUnlocked.rawValue)
7274
}
73-
onExit {
75+
onExit { _ in
7476
logger.log(Message.exitUnlocked.rawValue)
7577
}
7678
on(.admitPerson) {
7779
transition(to: .locked(credit: 0), emit: .closeDoors)
7880
}
7981
}
8082
state(.broken) {
81-
onEnter {
83+
onEnter { _ in
8284
logger.log(Message.enterBroken.rawValue)
8385
}
84-
onExit {
86+
onExit { _ in
8587
logger.log(Message.exitBroken.rawValue)
8688
}
8789
on(.machineRepairDidComplete) { broken in
@@ -123,7 +125,7 @@ final class StateMachine_Turnstile_Tests: XCTestCase, StateMachineBuilder {
123125
event: .insertCoin(10),
124126
toState: .locked(credit: 10),
125127
sideEffect: nil)))
126-
expect(self.logger).to(noLog())
128+
expect(self.logger).to(log("\(Message.exitLocked) 0", "\(Message.enterLocked) 10"))
127129
}
128130

129131
func test_givenStateIsLocked_whenInsertCoin_andCreditEqualsFarePrice_shouldTransitionToUnlockedStateAndOpenDoors() throws {
@@ -140,7 +142,7 @@ final class StateMachine_Turnstile_Tests: XCTestCase, StateMachineBuilder {
140142
event: .insertCoin(15),
141143
toState: .unlocked,
142144
sideEffect: .openDoors)))
143-
expect(self.logger).to(log(Message.exitLocked.rawValue, Message.enterUnlocked.rawValue))
145+
expect(self.logger).to(log("\(Message.exitLocked) 35", Message.enterUnlocked.rawValue))
144146
}
145147

146148
func test_givenStateIsLocked_whenInsertCoin_andCreditMoreThanFarePrice_shouldTransitionToUnlockedStateAndOpenDoors() throws {
@@ -157,7 +159,7 @@ final class StateMachine_Turnstile_Tests: XCTestCase, StateMachineBuilder {
157159
event: .insertCoin(20),
158160
toState: .unlocked,
159161
sideEffect: .openDoors)))
160-
expect(self.logger).to(log(Message.exitLocked.rawValue, Message.enterUnlocked.rawValue))
162+
expect(self.logger).to(log("\(Message.exitLocked) 35", Message.enterUnlocked.rawValue))
161163
}
162164

163165
func test_givenStateIsLocked_whenAdmitPerson_shouldTransitionToLockedStateAndSoundAlarm() throws {
@@ -191,7 +193,7 @@ final class StateMachine_Turnstile_Tests: XCTestCase, StateMachineBuilder {
191193
event: .machineDidFail,
192194
toState: .broken(oldState: .locked(credit: 15)),
193195
sideEffect: .orderRepair)))
194-
expect(self.logger).to(log(Message.exitLocked.rawValue, Message.enterBroken.rawValue))
196+
expect(self.logger).to(log("\(Message.exitLocked.rawValue) 15", Message.enterBroken.rawValue))
195197
}
196198

197199
func test_givenStateIsUnlocked_whenAdmitPerson_shouldTransitionToLockedStateAndCloseDoors() throws {
@@ -208,7 +210,7 @@ final class StateMachine_Turnstile_Tests: XCTestCase, StateMachineBuilder {
208210
event: .admitPerson,
209211
toState: .locked(credit: 0),
210212
sideEffect: .closeDoors)))
211-
expect(self.logger).to(log(Message.exitUnlocked.rawValue, Message.enterLocked.rawValue))
213+
expect(self.logger).to(log(Message.exitUnlocked.rawValue, "\(Message.enterLocked) 0"))
212214
}
213215

214216
func test_givenStateIsBroken_whenMachineRepairDidComplete_shouldTransitionToLockedState() throws {
@@ -225,7 +227,7 @@ final class StateMachine_Turnstile_Tests: XCTestCase, StateMachineBuilder {
225227
event: .machineRepairDidComplete,
226228
toState: .locked(credit: 15),
227229
sideEffect: nil)))
228-
expect(self.logger).to(log(Message.exitBroken.rawValue, Message.enterLocked.rawValue))
230+
expect(self.logger).to(log(Message.exitBroken.rawValue, "\(Message.enterLocked) 15"))
229231
}
230232
}
231233

0 commit comments

Comments
 (0)