-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfsm_safe.go
82 lines (77 loc) · 2.08 KB
/
fsm_safe.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
package fsm
import (
"sync"
"golang.org/x/exp/constraints"
)
var _ IFsm[string, string] = (*SafeFsm[string, string])(nil)
var _ IFsm[int, string] = (*SafeFsm[int, string])(nil)
// SafeFsm is the state machine that holds the current state and mutex.
// E is the event
// S is the state
type SafeFsm[E constraints.Ordered, S constraints.Ordered] struct {
// Transition contain events and source states to destination states.
// This is immutable
ITransition[E, S]
// mu guards access to the current state.
mu sync.RWMutex
// current is the state that the Fsm is currently in.
current S
}
// NewSafeFsm constructs a generic Fsm with an initial state S and a transition.
// E is the event type
// S is the state type.
func NewSafeFsm[E constraints.Ordered, S constraints.Ordered](initState S, ts ITransition[E, S]) IFsm[E, S] {
return &SafeFsm[E, S]{
current: initState,
ITransition: ts,
}
}
func (f *SafeFsm[E, S]) Clone() IFsm[E, S] {
return &SafeFsm[E, S]{
current: f.current,
ITransition: f.ITransition,
}
}
func (f *SafeFsm[E, S]) CloneNewState(newState S) IFsm[E, S] {
return &SafeFsm[E, S]{
current: newState,
ITransition: f.ITransition,
}
}
func (f *SafeFsm[E, S]) Current() S {
f.mu.RLock()
defer f.mu.RUnlock()
return f.current
}
func (f *SafeFsm[E, S]) SetCurrent(newState S) {
f.mu.Lock()
defer f.mu.Unlock()
f.current = newState
}
func (f *SafeFsm[E, S]) Is(state S) bool {
f.mu.RLock()
defer f.mu.RUnlock()
return state == f.current
}
func (f *SafeFsm[E, S]) Trigger(event E) error {
f.mu.Lock()
defer f.mu.Unlock()
dst, err := f.ITransition.Transform(f.current, event)
if err != nil {
return err
}
f.current = dst
return nil
}
func (f *SafeFsm[E, S]) MatchCurrentOccur(event E) bool {
return f.ITransition.MatchOccur(f.current, event)
}
func (f *SafeFsm[E, S]) MatchCurrentAllOccur(event ...E) bool {
return f.ITransition.MatchAllOccur(f.current, event...)
}
func (f *SafeFsm[E, S]) CurrentAvailEvents() []E {
return f.ITransition.AvailEvents(f.current)
}
func (f *SafeFsm[E, S]) Visualize(t VisualizeType) (string, error) {
return Visualize[E, S](t, f)
}