statig 0.4.1

Hierarchical state machines for designing event-driven systems
Documentation
#[cfg(test)]
mod tests {
    use statig::prelude::*;

    #[derive(Default)]
    struct Counter;

    #[allow(dead_code)]
    struct ExternalContext<'a, 'b>(&'a mut usize, &'b mut usize);

    enum Event {
        ButtonPressed,
        TimerElapsed,
    }

    #[state_machine(initial = "State::up()")]
    impl Counter {
        #[state]
        fn up(context: &mut ExternalContext<'_, '_>, event: &Event) -> Outcome<State> {
            match event {
                Event::ButtonPressed => {
                    *context.0 = context.0.saturating_add(1);
                    Handled
                }
                Event::TimerElapsed => Transition(State::down()),
            }
        }

        #[state]
        fn down(context: &mut ExternalContext<'_, '_>, event: &Event) -> Outcome<State> {
            match event {
                Event::ButtonPressed => {
                    *context.0 = context.0.saturating_sub(1);
                    Handled
                }
                Event::TimerElapsed => Transition(State::up()),
            }
        }
    }

    #[test]
    fn main() {
        let mut a = 0;
        let mut b = 0;
        let mut external_context = ExternalContext(&mut a, &mut b);

        let mut blinky = Counter
            .uninitialized_state_machine()
            .init_with_context(&mut external_context);

        let events = [
            Event::ButtonPressed,
            Event::ButtonPressed,
            Event::ButtonPressed,
        ];

        for event in &events {
            blinky.handle_with_context(event, &mut external_context);
        }

        assert_eq!(*external_context.0, 3);

        let events = [
            Event::TimerElapsed,
            Event::ButtonPressed,
            Event::ButtonPressed,
            Event::ButtonPressed,
        ];

        for event in &events {
            blinky.handle_with_context(event, &mut external_context);
        }

        assert_eq!(*external_context.0, 0);
    }
}