Crate macro_machine [−] [src]
State machine generator
State machine consists of: Name, initial state, List of States, List of Commands, list of States Nodes. Each State Node contain: Name, State Context (optional), list of Command Reactions. Each Command Reaction contain: Command to react on, user-defined code of reaction (optional) and next State of machine (optional).
Simplest state machine example:
#[macro_use] extern crate macro_machine; declare_machine!( Simple(A) // Name and initial State states[A,B] // list of States commands[Next] // list of Commands (A: // State Node Next => B; // Command Reaction. Just change state to B ) (B: Next => A; ) ); use Simple::*; let mut machine = Simple::new(); assert!(match machine.state(){States::A{..}=>true,_=>false}); machine.execute(&Simple::Commands::Next).unwrap(); assert!(match machine.state(){States::B{..}=>true,_=>false}); machine.execute(&Simple::Commands::Next).unwrap(); assert!(match machine.state(){States::A{..}=>true,_=>false});
You can add some intelligence to machine:
#[macro_use] extern crate macro_machine; declare_machine!( Simple(A{counter:0}) // Name and initial State with initial value states[A,B] // list of States commands[Next] // list of Commands (A context{counter:i16}: // State Node and this state context description with binding name Next {context.counter=context.counter+1}=> B{counter:context.counter}; // Command Reaction. Now on command Next we add 1 to our context. Also we change state to B and init it with our x value. ) (B context{counter:i16}: Next {context.counter=context.counter+1}=> A{counter:context.counter}; ) ); use Simple::*; let mut machine = Simple::new(); assert!(match machine.state(){ States::A{context}=> if context.counter == 0 {true} else {false}, // We are in state A and have our initial value 0 _=>false }); machine.execute(&Simple::Commands::Next).unwrap(); assert!(match machine.state(){ States::B{context}=> if context.counter == 1 {true} else {false}, // We are in state B and have counter == 1 _=>false }); machine.execute(&Simple::Commands::Next).unwrap(); assert!(match machine.state(){ States::A{context}=> if context.counter == 2 {true} else {false}, // Again in state A and have counter == 2 _=>false });
#[macro_use] extern crate macro_machine; declare_machine!( Simple(A{counter:0}) // Name and initial State with initial value states[A,B] // list of States commands[Next] // list of Commands (A context{counter:i16}: // State Node and this state context description with binding name >> {context.counter = context.counter+1;} // Execute when enter state A << {context.counter = context.counter+1;} // Execute when leave state A Next {context.counter=context.counter+1;} => B{counter:context.counter}; // Command Reaction. Now on command Next we add 1 to our context. Also we change state to B and init it with our x value. ) (B context{counter:i16}: Next {context.counter=context.counter+1} => A{counter:context.counter}; ) ); use Simple::*; let mut machine = Simple::new(); assert!(match machine.state(){ // We are in state A and have value 1. Because Enter State callback executed. States::A{context}=> if context.counter == 1 {true} else {false}, _=>false }); machine.execute(&Simple::Commands::Next).unwrap(); assert!(match machine.state(){ // We are in state B and have counter == 2. Increment happen on User Code execution. Execution of Leave state callback happen after we transfer data to the next state. States::B{context}=> {println!("context counter: {}", context.counter);if context.counter == 2 {true} else {false}}, _=>false }); machine.execute(&Simple::Commands::Next).unwrap(); assert!(match machine.state(){ // Again in state A and have counter == 4. Increment happen on User Code execution and on state A enter. States::A{context}=> if context.counter == 4 {true} else {false}, _=>false });
Macros
declare_machine |