Add statemachine module

pull/13668/head
Mihai Galos 2022-03-06 16:02:36 +01:00
parent c8e33ad219
commit 1d40720bf6
2 changed files with 100 additions and 0 deletions

View File

@ -0,0 +1,66 @@
module statemachine
pub type EventHandlerFn = fn (receiver voidptr)
pub type ConditionFn = fn (receiver voidptr) bool
struct State {
mut:
entry_handler EventHandlerFn
run_handler EventHandlerFn
exit_handler EventHandlerFn
}
struct Transition {
mut:
to string
condition ConditionFn
}
struct StateMachine {
mut:
states map[string]State
transitions map[string]Transition
current_state string
}
pub fn new() &StateMachine {
return &StateMachine{}
}
pub fn (mut s StateMachine) add_state(name string, entry EventHandlerFn, run EventHandlerFn, exit EventHandlerFn) {
s.states [name] = State{
entry_handler: entry
run_handler: run
exit_handler: exit
}
if s.states.len == 1 {
s.current_state = name
}
}
pub fn (mut s StateMachine) add_transition(from string, to string, condition ConditionFn) {
s.transitions[from] = Transition{
to: to
condition: condition
}
}
pub fn (mut s StateMachine) run(receiver voidptr){
for from_state, transition in s.transitions{
if from_state in s.states {
if transition.condition(receiver){
s.change_state(receiver, s.transitions[from_state].to)
}
}
}
}
pub fn (mut s StateMachine) change_state(receiver voidptr, newstate string){
mut current_state := s.current_state
s.states[current_state].exit_handler(receiver)
current_state = newstate
s.states[current_state].run_handler(receiver)
s.states[current_state].entry_handler(receiver)
s.current_state = current_state
}

View File

@ -0,0 +1,34 @@
import statemachine
struct FakeReceiver {
mut:
data []string
}
fn test_statemachine_works_when_typical() {
mut receiver := &FakeReceiver{}
mut s := statemachine.new()
s.add_state("A",on_test_entry, on_test_run, on_test_exit)
s.add_state("B",on_test_entry, on_test_run, on_test_exit)
s.add_transition("A", "B", condition_a_b)
s.run(receiver)
assert receiver.data[0] == "on_test_exit"
assert receiver.data[1] == "on_test_run"
assert receiver.data[2] == "on_test_entry"
}
fn on_test_entry(mut receiver &FakeReceiver) {
receiver.data << "on_test_entry"
}
fn on_test_run(mut receiver &FakeReceiver) {
receiver.data << "on_test_run"
}
fn on_test_exit(mut receiver &FakeReceiver) {
receiver.data << "on_test_exit"
}
fn condition_a_b(receiver &FakeReceiver) bool {
return true
}