-
-
Notifications
You must be signed in to change notification settings - Fork 53
/
triggers.go
151 lines (128 loc) · 3.55 KB
/
triggers.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package stateless
import (
"context"
"fmt"
"reflect"
"runtime"
"strings"
)
type invocationInfo struct {
Method string
}
func newinvocationInfo(method any) invocationInfo {
funcName := runtime.FuncForPC(reflect.ValueOf(method).Pointer()).Name()
nameParts := strings.Split(funcName, ".")
var name string
if len(nameParts) != 0 {
name = nameParts[len(nameParts)-1]
}
return invocationInfo{
Method: name,
}
}
func (inv invocationInfo) String() string {
if inv.Method != "" {
return inv.Method
}
return "<nil>"
}
type guardCondition struct {
Guard GuardFunc
Description invocationInfo
}
type transitionGuard struct {
Guards []guardCondition
}
func newtransitionGuard(guards ...GuardFunc) transitionGuard {
tg := transitionGuard{Guards: make([]guardCondition, len(guards))}
for i, guard := range guards {
tg.Guards[i] = guardCondition{
Guard: guard,
Description: newinvocationInfo(guard),
}
}
return tg
}
// GuardConditionsMet is true if all of the guard functions return true.
func (t transitionGuard) GuardConditionMet(ctx context.Context, args ...any) bool {
for _, guard := range t.Guards {
if !guard.Guard(ctx, args...) {
return false
}
}
return true
}
func (t transitionGuard) UnmetGuardConditions(ctx context.Context, buf []string, args ...any) []string {
if cap(buf) < len(t.Guards) {
buf = make([]string, 0, len(t.Guards))
}
buf = buf[:0]
for _, guard := range t.Guards {
if !guard.Guard(ctx, args...) {
buf = append(buf, guard.Description.String())
}
}
return buf
}
type triggerBehaviour interface {
GuardConditionMet(context.Context, ...any) bool
UnmetGuardConditions(context.Context, []string, ...any) []string
GetTrigger() Trigger
}
type baseTriggerBehaviour struct {
Guard transitionGuard
Trigger Trigger
}
func (t *baseTriggerBehaviour) GetTrigger() Trigger {
return t.Trigger
}
func (t *baseTriggerBehaviour) GuardConditionMet(ctx context.Context, args ...any) bool {
return t.Guard.GuardConditionMet(ctx, args...)
}
func (t *baseTriggerBehaviour) UnmetGuardConditions(ctx context.Context, buf []string, args ...any) []string {
return t.Guard.UnmetGuardConditions(ctx, buf, args...)
}
type ignoredTriggerBehaviour struct {
baseTriggerBehaviour
}
type reentryTriggerBehaviour struct {
baseTriggerBehaviour
Destination State
}
type transitioningTriggerBehaviour struct {
baseTriggerBehaviour
Destination State
}
type dynamicTriggerBehaviour struct {
baseTriggerBehaviour
Destination func(context.Context, ...any) (State, error)
}
type internalTriggerBehaviour struct {
baseTriggerBehaviour
Action ActionFunc
}
func (t *internalTriggerBehaviour) Execute(ctx context.Context, transition Transition, args ...any) error {
ctx = withTransition(ctx, transition)
return t.Action(ctx, args...)
}
type triggerBehaviourResult struct {
Handler triggerBehaviour
UnmetGuardConditions []string
}
// triggerWithParameters associates configured parameters with an underlying trigger value.
type triggerWithParameters struct {
Trigger Trigger
ArgumentTypes []reflect.Type
}
func (t triggerWithParameters) validateParameters(args ...any) {
if len(args) != len(t.ArgumentTypes) {
panic(fmt.Sprintf("stateless: An unexpected amount of parameters have been supplied. Expecting '%d' but got '%d'.", len(t.ArgumentTypes), len(args)))
}
for i := range t.ArgumentTypes {
tp := reflect.TypeOf(args[i])
want := t.ArgumentTypes[i]
if !tp.ConvertibleTo(want) {
panic(fmt.Sprintf("stateless: The argument in position '%d' is of type '%v' but must be convertible to '%v'.", i, tp, want))
}
}
}