smlang 0.8.0

A no-std state machine language DSL
Documentation
//! Pattern Matching State Machine
//!
//! This demonstrates the use of input state pattern matching so that states that share a common
//! transition to the same output state can be described more succinctly
#![deny(missing_docs)]

use smlang::statemachine;

// statemachine! {
//     transitions: {
//         *Idle + Charge = Charging,
//         Idle + Discharge = Discharging,
//         Charging + ChargeComplete = Charged,
//         Discharging + DischargeComplete = Discharged,
//         Charged + Discharge = Discharging,
//         Dischaged + Charge = Charging,
//         Charging + Discharge = Discharging,
//         Discharging + Charge = Charging,
//         Idle + FaultDetected = Fault,
//         Charging + FaultDetected = Fault,
//         Discharging + FaultDetected = Fault,
//         Charged + FaultDetected = Fault,
//         Discharged + FaultDetected = Fault,
//         Fault + FaultCleard = Idle,
//     },
// }

// A simple charge/discharge state machine that has a dedicated "Fault" state
statemachine! {
    name: Battery,
    transitions: {
        *Idle | Discharging | Discharged + Charge = Charging,
        Idle | Charging | Charged + Discharge = Discharging,
        Charging + ChargeComplete = Charged,
        Discharging + DischargeComplete = Discharged,
        _ + FaultDetected = Fault,
        Fault + FaultCleard = Idle,
    },
}

/// Context
pub struct Context;

impl BatteryStateMachineContext for Context {}

fn main() {
    let mut sm = BatteryStateMachine::new(Context);

    assert!(matches!(sm.state(), &BatteryStates::Idle));

    let r = sm.process_event(BatteryEvents::Charge);
    assert!(matches!(r, Ok(&BatteryStates::Charging)));

    let r = sm.process_event(BatteryEvents::Discharge);
    assert!(matches!(r, Ok(&BatteryStates::Discharging)));

    let r = sm.process_event(BatteryEvents::Charge);
    assert!(matches!(r, Ok(&BatteryStates::Charging)));

    let r = sm.process_event(BatteryEvents::ChargeComplete);
    assert!(matches!(r, Ok(&BatteryStates::Charged)));

    let r = sm.process_event(BatteryEvents::Charge);
    assert!(matches!(r, Err(BatteryError::InvalidEvent)));
    assert!(matches!(sm.state(), &BatteryStates::Charged));

    let r = sm.process_event(BatteryEvents::Discharge);
    assert!(matches!(r, Ok(&BatteryStates::Discharging)));

    let r = sm.process_event(BatteryEvents::DischargeComplete);
    assert!(matches!(r, Ok(&BatteryStates::Discharged)));

    let r = sm.process_event(BatteryEvents::Discharge);
    assert!(matches!(r, Err(BatteryError::InvalidEvent)));
    assert!(matches!(sm.state(), &BatteryStates::Discharged));

    sm = BatteryStateMachine::new_with_state(Context, BatteryStates::Idle);
    let r = sm.process_event(BatteryEvents::FaultDetected);
    assert!(matches!(r, Ok(&BatteryStates::Fault)));

    sm = BatteryStateMachine::new_with_state(Context, BatteryStates::Charging);
    let r = sm.process_event(BatteryEvents::FaultDetected);
    assert!(matches!(r, Ok(&BatteryStates::Fault)));

    sm = BatteryStateMachine::new_with_state(Context, BatteryStates::Charged);
    let r = sm.process_event(BatteryEvents::FaultDetected);
    assert!(matches!(r, Ok(&BatteryStates::Fault)));

    sm = BatteryStateMachine::new_with_state(Context, BatteryStates::Discharging);
    let r = sm.process_event(BatteryEvents::FaultDetected);
    assert!(matches!(r, Ok(&BatteryStates::Fault)));

    sm = BatteryStateMachine::new_with_state(Context, BatteryStates::Discharged);
    let r = sm.process_event(BatteryEvents::FaultDetected);
    assert!(matches!(r, Ok(&BatteryStates::Fault)));

    let r = sm.process_event(BatteryEvents::Charge);
    assert!(matches!(r, Err(BatteryError::InvalidEvent)));
    assert!(matches!(sm.state(), &BatteryStates::Fault));

    let r = sm.process_event(BatteryEvents::Discharge);
    assert!(matches!(r, Err(BatteryError::InvalidEvent)));
    assert!(matches!(sm.state(), &BatteryStates::Fault));

    let r = sm.process_event(BatteryEvents::ChargeComplete);
    assert!(matches!(r, Err(BatteryError::InvalidEvent)));
    assert!(matches!(sm.state(), &BatteryStates::Fault));

    let r = sm.process_event(BatteryEvents::DischargeComplete);
    assert!(matches!(r, Err(BatteryError::InvalidEvent)));
    assert!(matches!(sm.state(), &BatteryStates::Fault));
}