rust_sfsm

Attribute Macro rust_sfsm 

Source
#[rust_sfsm]
Expand description

§Rust-SFSM Attribute Macro.

SFSM stands for Static Finite State Machine.

This macro must be used on struct’s and implements the boilerplate for any type that has a state-like behavior.

§Example

use rust_sfsm::{StateBehavior, StateMachine, rust_sfsm};

/// List of protocol states.
#[derive(Clone, Copy, Default, PartialEq)]
enum States {
    #[default]
    Init,
    Opened,
    Closed,
    Locked,
}

/// List of protocol events.
enum Events {
    Create,
    Open,
    Close,
    Lock,
    Unlock,
}

/// Protocol state machine context (data shared between states).
#[derive(Default)]
struct Context {
    lock_counter: u16,
}

impl StateBehavior for States {
    type State = Self;
    type Event<'a> = Events;
    type Context = Context;

    fn enter(&self, _context: &mut Self::Context) {
        if self == &States::Locked {
            _context.lock_counter += 1
        }
    }

    fn handle_event(
        &self,
        event: &Self::Event<'_>,
        _context: &mut Self::Context,
    ) -> Option<Self::State> {
        match (self, event) {
            (&States::Init, &Events::Create) => Some(States::Opened),
            (&States::Opened, &Events::Close) => Some(States::Closed),
            (&States::Closed, &Events::Open) => Some(States::Opened),
            (&States::Closed, &Events::Lock) => Some(States::Locked),
            (&States::Locked, &Events::Unlock) => Some(States::Closed),
            _ => None,
        }
    }
}

#[rust_sfsm(states = States, context = Context)]
struct Protocol {}

impl Protocol {
    fn new() -> Self {
        Self {
            current_state: Default::default(),
            context: Default::default(),
        }
    }
}

§Macro Expansion

The rust_sfsm macro expands to this:

struct Protocol {
    current_state: States,
    context: Context,
}

impl ::rust_sfsm::StateMachine<States> for Protocol {
    fn current_state(&self) -> <States as ::rust_sfsm::StateBehavior>::State {
        self.current_state
    }

    fn handle_event(
        &mut self,
        event: &<States as ::rust_sfsm::StateBehavior>::Event<'_>,
    ) {
        if let Some(next_state) = self
            .current_state
            .handle_event(event, &mut self.context)
        {
            self.transit(next_state)
        }
    }

    fn transit(&mut self, new_state: <States as ::rust_sfsm::StateBehavior>::State) {
        self.current_state.exit(&mut self.context);
        self.current_state = new_state;
        self.current_state.enter(&mut self.context);
    }

    fn force_state(&mut self, new_state: <States as ::rust_sfsm::StateBehavior>::State) {
        self.current_state = new_state;
    }
}