statig
Hierarchical state machines for designing event-driven systems.
Features
- Hierachical state machines
- State-local storage
- Compatible with
#![no_std], no dynamic memory allocation - (Optional) macro's for reducing boilerplate.
statig in action
;
(See the macro/basic example for the full code with comments. Or see no_macro/basic for a version without using macro's).
Concepts
States
States are defined by writing methods inside the impl block and adding the #[state] attribute to them. By default the event argument will map to the event handled by the state machine.
Every state must return a Response. A Response can be one of three things:
Handled: The event has been handled.Transition: Transition to another state.Super: Defer the event to the next superstate.
Superstates
Superstates allow you to create a hierarchy of states. States can defer an event to their superstate by returning the Super response.
Superstates can themselves also have superstates.
Actions
Actions run when entering or leaving states during a transition.
Context
If the type on which your state machine is implemented has any fields, you can access them inside all states, superstates or actions.
Or alternatively, set led inside the entry action.
State-local storage
Sometimes you have data that only exists in a certain state. Instead of adding this data to the context and potentially having to unwrap an Option<T>, you can add it as an input to your state handler.
counter is only available in the on state but can also be accessed in its superstates and actions.
FAQ
What is this #[state_machine] proc-macro doing to my code? 🤨
Short answer: nothing. #[state_machine] simply parses the underlying impl block and derives some code based on its content and adds it to your source file. Your code will still be there, unchanged. In fact #[state_machine] could have been a derive macro, but at the moment Rust only allows derive macros to be used on enums and structs. If you'd like to see what the generated code looks like take a look at the test with and without macros.
How is this different from the typestate pattern?
How do I design event-driven systems?
Does this support {insert uml feature}?
Credits
The idea for this library came from reading the book Practical UML Statecharts in C/C++. I highly recommend it if you want to learn how to use state machines to design complex systems.