Crate macro_machines

source ·
Expand description

State machine macros with logging and graphviz DOT file generation.


An example that shows a number of features of the macro syntax is a Door state machine with:

  • two states: Closed (with state-local variable knock_count and an exit action) and a simple state Open (with no state variables or actions)
  • three events: one internal event Knock (with action on the Closed state) and two external events Open (with associated action) and Close (without any action)
  • an extended state variable open_count – this variable is initialized once and is independent of the current machine state
def_machine_debug! {
  Door (open_count : u64) @ door {
    STATES [
      state Closed (knock_count : u64) {
        exit {
          println!("knock count: {}", knock_count);
          println!("open count: {}", open_count);
      state Opened ()
    EVENTS [
      event Knock <Closed> () { knock_count } => { *knock_count += 1; }
      event Open  <Closed> => <Opened> ()  {} => { *open_count += 1; }
      event Close <Opened> => <Closed> ()
    initial_state:  Closed {
      initial_action: {
        println!("open_count: {:?}", door.as_ref().open_count);
    terminal_state: Closed {
      terminate_success: {
        println!("open_count: {:?}", door.as_ref().open_count);
      terminate_failure: {
        panic!("door was left: {:?}", door.state())

Within state entry and exit action blocks all extended state and local state variables are in scope.

In event actions, mutable references to extended state variables will implicitly be brought into scope of the associated action block, however local state variables need to be explicitly listed in the LHS brace of the action construct to be accessible (e.g. the knock_count local state variable in the Knock event action of the current example).

When making a universal or external transition, first state exit actions are performed, followed by event actions, and then after initializing the new state, state entry actions.

To make the state machine accessible in initial and terminal action blocks, the macro implementation requires an identifier be introduced, door, following the @ symbol. This variable is then brought into scope as an alias for a mutable self-reference in initial and terminal action blocks.

Initial and terminal actions are always before and after any state entry and exit actions, respectively.

The Door::dotfile() function will generate a ‘.dot’ file string that can be saved and rendered as a PNG with layout generated by graphviz dot tool:

$ dot -Tpng > door.png


  • pub extern crate log;


  • Example generated state machine




Derive Macros