use std::fmt::Display; use bicoro::*; use do_notation::m; // Encoding of https://en.wikipedia.org/wiki/Finite-state_machine#Example:_coin-operated_turnstile /// FSM need a set of inputs pub enum Input { Coin, Push, } /// And a set of outputs pub enum Output { Unlocked, NoChange, Locked, } /// This is internal, so we can track what is happening enum State { Locked, Unlocked, } /// Should be !, but not stable yet pub enum Never {} /// Creates a new turnstile, in the locked state pub fn create<'a>() -> Coroutine<'a, Input, Output, Never> { // recursive function. that takes the current state, input and // gives a co-routine. fn on_input<'a>(state: State, input: Input) -> Coroutine<'a, Input, Output, Never> { // coroutine section that sends the output, and sets the next state let next = match (state, input) { (State::Locked, Input::Coin) => m! { send(Output::Unlocked); result(State::Unlocked) }, (State::Locked, Input::Push) => m! { send(Output::NoChange); result(State::Locked) }, (State::Unlocked, Input::Coin) => m! { send(Output::NoChange); result(State::Unlocked) }, (State::Unlocked, Input::Push) => m! { send(Output::Locked); result(State::Locked) }, }; // read an input, and call on_input again m! { state <- next; input <- receive(); on_input(state, input) } } let initial_state = State::Locked; m! { input <- receive(); on_input(initial_state, input) } } impl Display for Output { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Output::Unlocked => f.write_str("Unlocked"), Output::Locked => f.write_str("Locked"), Output::NoChange => f.write_str("NoChange"), } } }