-
Notifications
You must be signed in to change notification settings - Fork 0
/
sm_builder.go
87 lines (71 loc) · 3.24 KB
/
sm_builder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package gfsm
import "fmt"
// StateMachineBuilder interface provides access to a builder that simplifies state machine creation. Builder usage is optional,
// and state machine object can be created manually if needed.
// Refer to newSmManual test for manual state machine creation or newSmWithBuilder as the alternative approach with builder.
type StateMachineBuilder[StateIdentifier comparable] interface {
// RegisterState call register one more state referenced by stateID with list of all valid transactions listed in transitions
// and handler (action) into the state machine.
RegisterState(stateID StateIdentifier, action StateAction[StateIdentifier], transitions []StateIdentifier) StateMachineBuilder[StateIdentifier]
// SetDefaultState tells which state is the default for the state machine. Each state machine must have a default state.
// On StateMachineHandler.Start() call, state machine will switch to the defined default state.
SetDefaultState(stateID StateIdentifier) StateMachineBuilder[StateIdentifier]
// SetSmContext is an optional call that allow to pass any context that is unique and persistent (but mutable) for each state machine.
SetSmContext(ctx StateMachineContext) StateMachineBuilder[StateIdentifier]
// Build is the final call that aggregates all the data from previous calls and creates new state machine.
Build() StateMachineHandler[StateIdentifier]
}
// NewBuilder function generates StateMachineBuilder which simplifies state machine creation process.
func NewBuilder[StateIdentifier comparable]() StateMachineBuilder[StateIdentifier] {
return &stateMachineBuilder[StateIdentifier]{
hasState: false,
sm: &stateMachine[StateIdentifier]{
states: StatesMap[StateIdentifier]{},
},
}
}
// stateMachineBuilder[StateIdentifier comparable] is an implementation for
// the StateMachineBuilder[StateIdentifier comparable] interface
type stateMachineBuilder[StateIdentifier comparable] struct {
hasState bool
hasDefaultState bool
sm *stateMachine[StateIdentifier]
}
func (s *stateMachineBuilder[StateIdentifier]) Build() StateMachineHandler[StateIdentifier] {
if !s.hasState || !s.hasDefaultState {
panic("state machine is not properly initialised yet")
}
return s.sm
}
func (s *stateMachineBuilder[StateIdentifier]) RegisterState(
stateID StateIdentifier,
action StateAction[StateIdentifier],
transitions []StateIdentifier) StateMachineBuilder[StateIdentifier] {
_, ok := s.sm.states[stateID]
if ok {
panic(fmt.Sprintf("state %v is already registered", stateID))
}
s.sm.states[stateID] = state[StateIdentifier]{
action: action,
transitions: makeTransitions(transitions),
}
s.hasState = true
return s
}
func makeTransitions[StateIdentifier comparable](transitions []StateIdentifier) Transitions[StateIdentifier] {
trs := Transitions[StateIdentifier]{}
for _, transition := range transitions {
trs[transition] = struct{}{}
}
return trs
}
func (s *stateMachineBuilder[StateIdentifier]) SetDefaultState(stateID StateIdentifier) StateMachineBuilder[StateIdentifier] {
s.sm.currentStateID = stateID
s.sm.defaultStateID = stateID
s.hasDefaultState = true
return s
}
func (s *stateMachineBuilder[StateIdentifier]) SetSmContext(ctx StateMachineContext) StateMachineBuilder[StateIdentifier] {
s.sm.smCtx = ctx
return s
}