@@ -2,6 +2,7 @@ package statemachine
2
2
3
3
import (
4
4
"context"
5
+ "errors"
5
6
"fmt"
6
7
"reflect"
7
8
"sync"
@@ -62,7 +63,9 @@ func (m *machineImpl) SetMachineDef(def *MachineDef) {
62
63
// fmt.Printf("machine def = %s\n", string(b))
63
64
64
65
m .def = def
65
- m .setCurrentState (m .def .InitialState )
66
+ if err := m .setCurrentState (m .def .InitialState ); err != nil {
67
+ panic (err )
68
+ }
66
69
m .restartTimedEventsLoops ()
67
70
}
68
71
@@ -86,17 +89,34 @@ func (m *machineImpl) restartTimedEventsLoops() {
86
89
}
87
90
}
88
91
92
+ // GetStateMap implements Machine.
93
+ func (m * machineImpl ) GetStateMap () StateMap {
94
+ substate := StateMap {}
95
+ if submachines , ok := m .submachines [m .currentState ]; ok {
96
+ for _ , submachine := range submachines {
97
+ if _ , ok := submachine .submachines [submachine .currentState ]; ok {
98
+ substate [submachine .def .ID ] = submachine .GetStateMap ()
99
+ } else {
100
+ substate [submachine .def .ID ] = submachine .currentState
101
+ }
102
+ }
103
+ }
104
+ return StateMap {
105
+ m .currentState : substate ,
106
+ }
107
+ }
108
+
89
109
// GetState implements Machine.
90
110
func (m * machineImpl ) GetState () string {
91
111
return m .currentState
92
112
}
93
113
94
114
// SetCurrentState implements Machine.
95
- func (m * machineImpl ) SetCurrentState (state string ) {
115
+ func (m * machineImpl ) SetCurrentState (state interface {}) error {
96
116
m .mutex .Lock ()
97
117
defer m .mutex .Unlock ()
98
118
99
- m .setCurrentState (state )
119
+ return m .setCurrentState (state )
100
120
}
101
121
102
122
// IsState implements Machine.
@@ -142,7 +162,7 @@ func (m *machineImpl) Fire(event string) (err error) {
142
162
}()
143
163
144
164
if m .IsState ("" ) {
145
- err = ErrNotInitialized
165
+ err = errors . New ( "state machine not initialized" )
146
166
return
147
167
}
148
168
@@ -164,7 +184,7 @@ func (m *machineImpl) Fire(event string) (err error) {
164
184
func (m * machineImpl ) findTransition (event string , fromState string ) (transition Transition , err error ) {
165
185
eventDef , ok := m .def .Events [event ]
166
186
if ! ok {
167
- err = ErrNoSuchEvent
187
+ err = errors . New ( "no such event" )
168
188
return
169
189
}
170
190
@@ -228,48 +248,105 @@ func (m *machineImpl) matchTransition(transitions []*TransitionDef, fromState st
228
248
return
229
249
}
230
250
231
- // TODO: get submachine by its id.
232
- func (m * machineImpl ) Submachine (state string ) (Machine , error ) {
233
- // func (m *machineImpl) Submachine(state, id string) (Machine, error) {
234
- if m .currentState != state {
235
- return nil , ErrStateNotCurrent
251
+ func (m * machineImpl ) Submachine (idPath ... string ) (Machine , error ) {
252
+ for _ , submachine := range m .submachines [m .currentState ] {
253
+ if submachine .def .ID == idPath [0 ] {
254
+ if len (idPath ) > 1 {
255
+ return submachine .Submachine (idPath [1 :]... )
256
+ }
257
+ return submachine , nil
258
+ }
236
259
}
237
260
238
- // for _, submachine := range m.submachines[state] {
239
- // if submachine.def.ID == id {
240
- // return submachine, nil
241
- // }
242
- // }
261
+ return nil , errors .New ("submachine not active" )
262
+ }
263
+
264
+ func (m * machineImpl ) setCurrentStateMap (state StateMap ) error {
265
+ for rootState , subStates := range state {
266
+ switch subStates .(type ) {
267
+ case nil :
268
+ // fmt.Printf("setting state to '%s'\n", rootState)
269
+ return m .setCurrentState (rootState )
270
+
271
+ case StateMap :
272
+ // fmt.Printf("setting state to '%s'\n", rootState)
273
+ if err := m .setCurrentState (rootState ); err != nil {
274
+ return err
275
+ }
276
+
277
+ for id , state := range subStates .(StateMap ) {
278
+ for _ , submachine := range m .submachines [rootState ] {
279
+ if submachine .def .ID == id {
280
+ switch state .(type ) {
281
+ case StateMap :
282
+ // fmt.Printf("nesting into submachine '%s'\n", id)
283
+ if err := submachine .setCurrentStateMap (state .(StateMap )); err != nil {
284
+ return err
285
+ }
286
+ case string :
287
+ // fmt.Printf("setting submachine '%s' to '%s'\n", id, state)
288
+ if err := submachine .SetCurrentState (state ); err != nil {
289
+ return err
290
+ }
291
+ default :
292
+ return ErrStateTypeNotSupported
293
+ }
294
+ }
295
+ }
296
+ }
243
297
244
- return m .submachines [state ][0 ], nil
298
+ default :
299
+ if err := m .setCurrentState (rootState ); err != nil {
300
+ return err
301
+ }
302
+
303
+ return ErrStateTypeNotSupported
304
+ }
305
+
306
+ // there is only one kv in any given StateMap
307
+ break
308
+ }
309
+
310
+ return nil
245
311
}
246
312
247
- func (m * machineImpl ) setCurrentState (state string ) {
248
- for _ , s := range m .def .States {
249
- if s == state {
250
- m .previousState = m .currentState
251
- m .currentState = state
252
- return
313
+ func (m * machineImpl ) setCurrentState (state interface {}) error {
314
+ if state , ok := state .(StateMap ); ok {
315
+ if err := m .setCurrentStateMap (state ); err != nil {
316
+ return err
253
317
}
318
+ return nil
254
319
}
255
320
256
- for s , submachineDefs := range m .def .Submachines {
257
- if s == state {
258
- m .submachines [state ] = []* machineImpl {}
259
- for _ , submachineDef := range submachineDefs {
260
- submachine := & machineImpl {
261
- supermachine : m ,
262
- submachines : map [string ][]* machineImpl {},
263
- }
264
- submachine .SetMachineDef (submachineDef )
265
- m .submachines [state ] = append (m .submachines [state ], submachine )
321
+ if state , ok := state .(string ); ok {
322
+ for _ , s := range m .def .States {
323
+ if s == state {
324
+ m .previousState = m .currentState
325
+ m .currentState = state
326
+ return nil
266
327
}
328
+ }
267
329
268
- m .previousState = m .currentState
269
- m .currentState = state
270
- return
330
+ for s , submachineDefs := range m .def .Submachines {
331
+ if s == state {
332
+ m .submachines [state ] = []* machineImpl {}
333
+ for _ , submachineDef := range submachineDefs {
334
+ submachine := & machineImpl {
335
+ supermachine : m ,
336
+ submachines : map [string ][]* machineImpl {},
337
+ }
338
+ submachine .SetMachineDef (submachineDef )
339
+ m .submachines [state ] = append (m .submachines [state ], submachine )
340
+ }
341
+
342
+ m .previousState = m .currentState
343
+ m .currentState = state
344
+ return nil
345
+ }
271
346
}
272
347
}
348
+
349
+ return ErrStateTypeNotSupported
273
350
}
274
351
275
352
func (m * machineImpl ) applyTransition (transition Transition ) error {
0 commit comments