Skip to content

Commit 6a70166

Browse files
committed
fsm: add generic fsm
This commit adds a generic fsm which will help with threadsafe access for fsm values
1 parent ea6dd78 commit 6a70166

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

fsm/generic_fsm.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package fsm
2+
3+
import "sync"
4+
5+
type GenericFSM[T any] struct {
6+
*StateMachine
7+
8+
Val *T
9+
ValLock sync.RWMutex
10+
}
11+
12+
// NewGenericFSM creates a new generic FSM with the given initial state and
13+
// value.
14+
func NewGenericFSM[T any](fsm *StateMachine, val *T) *GenericFSM[T] {
15+
return &GenericFSM[T]{
16+
StateMachine: fsm,
17+
Val: val,
18+
}
19+
}
20+
21+
type callOptions struct {
22+
withMainMutex bool
23+
}
24+
25+
// CallOption is a functional option that can be used to modify the runFuncs.
26+
type CallOption func(*callOptions)
27+
28+
// WithMainMutex is an option that can be used to run the function with the main
29+
// mutex locked. This requires the FSM to not be currently running an action.
30+
func WithMainMutex() CallOption {
31+
return func(o *callOptions) {
32+
o.withMainMutex = true
33+
}
34+
}
35+
36+
// RunFunc runs the given function in the FSM. It locks the FSM value lock
37+
// before running the function and unlocks it after the function is done.
38+
func (fsm *GenericFSM[T]) RunFunc(fn func(val *T) error, options ...CallOption,
39+
) error {
40+
41+
opts := &callOptions{}
42+
for _, option := range options {
43+
option(opts)
44+
}
45+
46+
fsm.ValLock.Lock()
47+
defer fsm.ValLock.Unlock()
48+
if opts.withMainMutex {
49+
fsm.mutex.Lock()
50+
defer fsm.mutex.Unlock()
51+
}
52+
53+
return fn(fsm.Val)
54+
}
55+
56+
// GetVal returns the value of the FSM.
57+
func (fsm *GenericFSM[T]) GetVal(options ...CallOption) *T {
58+
opts := &callOptions{}
59+
for _, option := range options {
60+
option(opts)
61+
}
62+
63+
fsm.ValLock.RLock()
64+
defer fsm.ValLock.RUnlock()
65+
66+
if opts.withMainMutex {
67+
fsm.mutex.Lock()
68+
defer fsm.mutex.Unlock()
69+
}
70+
71+
return fsm.Val
72+
}

0 commit comments

Comments
 (0)