stateforward-sml 1.2.0

sml.rs: a no-std Rust implementation of the sml.cpp transition-table DSL
Documentation
use sml::sml;

sml! {
    Inspectable[states_attr: #[derive(Debug)]] {
        *Idle + Start = Running,
        Running + Stop = X,
    }
}

#[derive(Default)]
struct Context {
    entries: usize,
}

impl InspectableStateMachineContext for Context {
    fn on_entry_idle(&mut self) {
        self.entries += 1;
    }
}

#[test]
fn state_can_be_injected_for_focused_transition_testing() {
    let mut sm = InspectableStateMachine::new(Context::default());

    let previous = sm.set_state(InspectableStates::Running);
    assert!(matches!(previous, InspectableStates::Idle));

    sm.process_event(InspectableEvents::Stop).unwrap();
    assert!(sm.is_terminated());
    assert!(sml::Terminated::is_terminated(&sm));
}

#[test]
fn current_state_can_be_visited_without_exposing_machine_internals() {
    let sm = InspectableStateMachine::new(Context::default());
    let name = sm.visit_current_state(|state| match state {
        InspectableStates::Idle => "idle",
        InspectableStates::Running => "running",
        InspectableStates::X => "terminal",
    });

    assert_eq!(name, "idle");
    assert!(!sm.is_terminated());
}

#[test]
fn initialize_runs_the_initial_entry_hook() {
    let mut sm = InspectableStateMachine::new(Context::default());

    assert!(matches!(sm.initialize().unwrap(), InspectableStates::Idle));
    assert_eq!(sm.context().entries, 1);
}

sml! {
    InitializeInjected {
        *Idle + Start = Ready,
         Ready + on_entry<_> / record_ready,
    }
}

#[derive(Default)]
struct InitializeInjectedContext {
    ready_entries: usize,
}

impl InitializeInjectedStateMachineContext for InitializeInjectedContext {
    fn record_ready(&mut self) -> Result<(), ()> {
        self.ready_entries += 1;
        Ok(())
    }
}

#[test]
fn initialize_runs_configured_entry_action_for_injected_state() {
    let mut sm = InitializeInjectedStateMachine::new(InitializeInjectedContext::default());

    sm.set_state(InitializeInjectedStates::Ready);
    sm.initialize().unwrap();

    assert_eq!(sm.context().ready_entries, 1);
}