[−][src]Macro statemachine_macro::statemachine
statemachine!() { /* proc-macro */ }
Creates a state machine.
The Statemachine Struct
The statemachine struct that is generated (the first item in the macro body) has methods with the following signatures.
use statemachine_macro::*; statemachine! { struct Foo; enum FooState consumes [char] from Start; } /*impl Foo { /// Changes the statemachine to the given state. fn reset(&mut self, state: FooState) { ... } /// Returns true if the statemachine is in an accepting state. fn is_accepting(&self) -> bool { ... } /// Performs a transition for the given input symbol. fn consume<T: ...>(&mut self, val: T) { ... } }*/
These methods are currently not provided as a trait implementation. This may change in a future major version.
Examples
Basic consuming:
use statemachine_macro::*; statemachine! { pub struct Foo; enum FooState consumes [char] from Even accepts [Odd]; Even => { _ => Odd }, Odd => { _ => Even } } let mut foo = statemachine_new!(Foo{}); assert!(!foo.is_accepting()); foo.consume(' '); assert!(foo.is_accepting()); foo.consume(' '); assert!(!foo.is_accepting()); foo.consume(' '); assert!(foo.is_accepting());
Resetting the state machine:
use statemachine_macro::*; #[derive(Debug)] struct Money; statemachine! { pub struct Foo; enum FooState consumes [Money] from Unpaid accepts [Paid]; } let mut foo = statemachine_new!(Foo{}); assert!(!foo.is_accepting()); foo.reset(FooState::Paid); // mwahahaha free real estate assert!(foo.is_accepting());
Advanced consuming with multiple types:
use statemachine_macro::*; statemachine! { pub struct Foo { cheater: bool } enum FooState consumes [u32, i32] from Even accepts [Odd]; Even => { u32 match x => { if x % 2 == 0 { Even } else { Odd } }, i32 match v => if *v < 0 { self.cheater = true; Even }, i32 match x => panic!("Hey! Are you trying to cheat?") }, Odd => { u32 match x => { if x % 2 == 0 { Even } else { Odd } }, i32 match v => if *v < 0 { self.cheater = true; Odd }, i32 match x => panic!("Hey! Are you trying to cheat?") } } let mut foo = statemachine_new!(Foo{ cheater: false }); assert!(!foo.cheater); assert!(!foo.is_accepting()); foo.consume(5u32); assert!(!foo.cheater); assert!(foo.is_accepting()); foo.consume(4u32); assert!(!foo.cheater); assert!(!foo.is_accepting()); foo.consume(4u32); assert!(!foo.cheater); assert!(!foo.is_accepting()); foo.consume(-3i32); assert!(foo.cheater); assert!(!foo.is_accepting());
Syntax
The following is the syntax of the macro contents. The starting nonterminal is 'statemachine'.
statemachine ::= struct-item state-description ( state-behaviors )?
state-description ::=
"enum" ident "consumes" "[" type ( "," type )* "]"
( "accepts" "[" ident ( "," ident )* "]" )? ";"
state-behaviors ::= state-behavior ( "," state-behavior )*
state-behavior ::= ident "=>" "{" ( state-transitions )? "}"
state-transitions ::= state-transition ( "," state-transition )*
state-transition ::= transition-trigger | transition-pattern | transition-catchall
transition-pattern ::= type "match" pattern "=>" ( transition-guard )? expr
transition-guard ::= "if" expr
transition-catchall ::= "_" "=>" expr
transition-trigger ::= "@" ( enter-trigger | leave-trigger | loop-trigger )
enter-trigger ::= "enter" "=>" expr
leave-trigger ::= "leave" "=>" expr
loop-trigger ::= "loop" "=>" expr