v2 / vlib / datatypes / fsm / fsm.v
103 lines · 89 sloc · 2.89 KB · c6995239499efc8f0e5c0ebf370676e74c736d01
Raw
1module fsm
2
3pub type EventHandlerFn = fn (receiver voidptr, from string, to string)
4
5pub type ConditionFn = fn (receiver voidptr, from string, to string) bool
6
7fn dummy_event_handler_fn(_ voidptr, _ string, _ string) {
8}
9
10fn dummy_condition_fn(_ voidptr, _ string, _ string) bool {
11 return true
12}
13
14struct State {
15mut:
16 entry_handler EventHandlerFn = dummy_event_handler_fn
17 run_handler EventHandlerFn = dummy_event_handler_fn
18 exit_handler EventHandlerFn = dummy_event_handler_fn
19}
20
21struct Transition {
22mut:
23 to string
24 condition_handler ConditionFn = dummy_condition_fn
25}
26
27pub struct StateMachine {
28mut:
29 states map[string]State
30 transitions map[string][]Transition
31 current_state string
32}
33
34// StateMachine static method returns a new StateMachine instance.
35pub fn new() StateMachine {
36 return StateMachine{}
37}
38
39// set_state sets the current state of the state machine to the given state by `name`.
40pub fn (mut s StateMachine) set_state(name string) ! {
41 if name in s.states {
42 s.current_state = name
43 } else {
44 return error('unknown state: ${name}')
45 }
46}
47
48// get_state returns the current state of the state machine.
49pub fn (mut s StateMachine) get_state() string {
50 return s.current_state
51}
52
53// add_state adds a new state to the state machine.
54// It takes the `name` of the state, and three event handlers: `entry`, `run`, and `exit`.
55pub fn (mut s StateMachine) add_state(name string, entry EventHandlerFn, run EventHandlerFn, exit EventHandlerFn) {
56 s.states[name] = State{
57 entry_handler: entry
58 run_handler: run
59 exit_handler: exit
60 }
61 if s.states.len == 1 {
62 s.current_state = name
63 }
64}
65
66// add_transition adds a new transition to the state machine.
67// It takes the `from` and `to` states, and a condition handler.
68pub fn (mut s StateMachine) add_transition(from string, to string, condition_handler ConditionFn) {
69 t := Transition{
70 to: to
71 condition_handler: condition_handler
72 }
73 if from in s.transitions {
74 s.transitions[from] << t
75 return
76 }
77 s.transitions[from] = [t]
78}
79
80// run runs the state machine. It takes a `receiver` argument that is passed to the event handlers.
81pub fn (mut s StateMachine) run(receiver voidptr) ! {
82 from_state := s.current_state
83 mut to_state := s.current_state
84 if transitions := s.transitions[s.current_state] {
85 for transition in transitions {
86 if transition.condition_handler(receiver, from_state, transition.to) {
87 s.change_state(receiver, transition.to)
88 to_state = transition.to
89 break
90 }
91 }
92 } else {
93 s.states[s.current_state].run_handler(receiver, from_state, to_state)
94 return error('no more transitions')
95 }
96 s.states[s.current_state].run_handler(receiver, from_state, to_state)
97}
98
99fn (mut s StateMachine) change_state(receiver voidptr, newstate string) {
100 s.states[s.current_state].exit_handler(receiver, s.current_state, newstate)
101 s.states[newstate].entry_handler(receiver, s.current_state, newstate)
102 s.current_state = newstate
103}
104