Skip to content

Instantly share code, notes, and snippets.

@spytheman
Last active August 27, 2020 14:22
Show Gist options
  • Select an option

  • Save spytheman/a8a9c2deaaaa2c168328535242a5ef91 to your computer and use it in GitHub Desktop.

Select an option

Save spytheman/a8a9c2deaaaa2c168328535242a5ef91 to your computer and use it in GitHub Desktop.
import sync
enum FSMState {
init = 0
state_a
state_b
state_c
exit
}
enum FSMEvent {
ev1 = 0
ev2
ev3
ev4
ev5
}
[ref_only]
struct FSM {
mut:
prev_state FSMState
current_state FSMState
last_event FSMEvent
current_event FSMEvent
}
// define functions to handle transition from state x to state y
fn fsm_init() &FSM {
// place the structure on heap
return &FSM{
prev_state: .init
current_state: .init
last_event: .ev1
current_event: .ev1
}
}
fn (fsm &FSM) get_state() FSMState {
return fsm.current_state
}
fn (mut fsm FSM) set_state(new_state FSMState) {
fsm.prev_state = fsm.current_state
fsm.current_state = new_state
}
fn (fsm &FSM) get_event() FSMEvent {
return fsm.current_event
}
fn (mut fsm FSM) set_event(new_event FSMEvent) {
fsm.last_event = fsm.current_event
fsm.current_event = new_event
}
//
type FnTransitionCb = fn(fsm &FSM, new FSMState)
fn nop_transition(mut fsm FSM, new FSMState) {}
fn print_transition(mut fsm FSM, new FSMState) {
println('move from current: $fsm.current_state to new: $new')
}
struct FSMTransition {
old FSMState
evt FSMEvent
new FSMState
cb FnTransitionCb
}
const (
/* transition table
* state X event -> new state
* --------------------------
* init X ev1 -> state_a
* init X ev2 -> state_c
* state_a X ev3 -> state_b
* state_b X ev4 -> state_c
* state_c X ev5 -> state_a
* state_c X ev1 -> exit
*/
transitions = [
FSMTransition{.init, .ev1, .state_a, print_transition}
FSMTransition{.init, .ev2, .state_c, print_transition}
FSMTransition{.state_a, .ev3, .state_b, print_transition}
FSMTransition{.state_b, .ev4, .state_c, print_transition}
FSMTransition{.state_c, .ev5, .state_a, print_transition}
FSMTransition{.state_c, .ev1, .exit, print_transition}
]
)
fn (mut fsm FSM) next() (FSMState, FnTransitionCb) {
cs := fsm.current_state
ce := fsm.current_event
for t in transitions {
if cs == t.old && ce == t.evt {
return t.new, t.cb
}
}
println('undefined FSM State X FSM Event combination: ${cs}/${ce}')
return cs, nop_transition
}
fn (mut fsm FSM) run(events chan FSMEvent) {
for {
mut working_event := <- events // this blocks until there is an event
fsm.set_event(working_event)
next_state, fn_call := fsm.next()
fn_call(fsm, next_state)
fsm.set_state(next_state)
if next_state == .exit {
break
}
}
}
//
fn produce_events(ch chan FSMEvent) {
// place few events on queue
ch <- FSMEvent.ev1
ch <- FSMEvent.ev3
ch <- FSMEvent.ev4
ch <- FSMEvent.ev5
ch <- FSMEvent.ev3
ch <- FSMEvent.ev4
ch <- FSMEvent.ev3 // junk event here / should be filtered out, we are in state_c
ch <- FSMEvent.ev4 // junk event here / should be filtered out, we are in state_c
ch <- FSMEvent.ev1
}
fn main() {
println('start main()')
mut fsm := fsm_init()
ch_fsm_events := chan FSMEvent{cap: 1000}
go produce_events(ch_fsm_events)
fsm.run(ch_fsm_events)
current_state := fsm.get_state()
println('last FSMState: $current_state')
println('end main()')
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment