[][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