-
Notifications
You must be signed in to change notification settings - Fork 1
/
local.go
92 lines (72 loc) · 1.42 KB
/
local.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
88
89
90
91
92
package machine
import (
"sync"
"time"
"golang.org/x/net/context"
)
type localDone chan struct{}
func (l localDone) Wait(timeout int64) {
if timeout > 0 {
select {
case <-l:
case <-time.After(time.Duration(timeout)):
}
} else {
<-l
}
}
type localStateTransition chan State
func (ls localStateTransition) Next(state State) {
ls <- state
}
func (ls localStateTransition) Fork(ctx context.Context, states ...State) Joiner {
var wg sync.WaitGroup
wg.Add(len(states))
var done localDone
done = make(chan struct{})
for _, state := range states {
go func(initialState State) {
defer wg.Done()
NewLocalMachine().
Run(ctx, initialState).
Wait(0)
}(state)
}
go func() {
defer close(done)
wg.Wait()
}()
return done
}
func (ls localStateTransition) Done() {
close(ls)
}
type localMachine struct {
done localDone
transitioner localStateTransition
}
func (lm *localMachine) Run(ctx context.Context, state State) Joiner {
go func() {
ok := true
for ok {
select {
case state, ok = <-lm.transitioner:
if ok {
state(ctx, lm.transitioner)
}
case _, ok = <-ctx.Done():
}
}
defer close(lm.done)
}()
state(ctx, lm.transitioner)
return lm.done
}
//NewLocalMachine is a simple implemenation of state machine which uses go
//channel
func NewLocalMachine() Machine {
return &localMachine{
done: make(chan struct{}),
transitioner: make(chan State, 1),
}
}