Phyto FSM
A Rust procedural macro for generating state machines from PlantUML diagrams.
Overview
Many state machine frameworks provide the possibility to create a visualization from your FSM
defined by the source code, which then can be e.g. added to your documentation.
phyto-fsm does it the opposite way:
- you create a visual representation of an FSM using a PlantUML state diagram
phyto-fsm- parses the diagram during compile time
- generates a type-safe FSM representation as well as a trait to handle actions such as on transitions
- using the generated trait you define the actions to take on transitions
This way the design of the FSM is easy to grasp first hand and documentation and source code are always inline.
State Machine Features
| Feature | Description | Example |
|---|---|---|
| Events with custom data | Trigger transitions with typed event parameters | actions.rs |
| Custom data types | Use any type (primitives, structs, references, pointers) as event data | data_types.rs |
| Actions on transitions | Execute custom code when transitions occur | actions.rs |
| Composite states | Nested/hierarchical states with automatic enter state resolution | composite_states.rs |
| Substate-to-substate transitions | Transitions between substates across different parent states | substate_to_substate.rs |
| Self-transitions | States that transition to themselves | transitions.rs |
| Alternative transitions | Multiple transitions from the same state with different events | transitions.rs |
| Transition logging | Optional logging via log crate | four_seasons.rs |
Missing Features
- enter/exit actions
- exit state
- guards
- event deferring
- sub state machines
- history states
Generated Code Naming Conventions
When you use generate_fsm!("path/to/diagram.puml"), the macro generates various traits, enums, and structs based on your PlantUML diagram name and elements. Here's how they are named:
Core Generated Types
For a PlantUML diagram whose name is given by:
@startuml DiagramName
...
@enduml
The following is generated:
| Generated Item | Naming Pattern | Description |
|---|---|---|
| FSM Struct | {DiagramName} |
Main state machine struct (UpperCamelCase) |
| Event Parameters Trait | I{DiagramName}EventParams |
Trait defining event parameter types |
| Actions Trait | I{DiagramName}Actions |
Trait defining action methods |
| State Struct | {DiagramName}State |
Internal state representation |
| Module | {diagram_name} |
Generated module name (snake_case) |
Event and Action Elements
The actions and events associated with a transition must be defined as such with PlantUML:
StateA --> StateB : EventName / ActionName
- EventName becomes the event that triggers the transition
- ActionName (optional) becomes the method called during the transition
- Use
/to separate the event from the action
| PlantUML Element | Generated Item | Naming Pattern |
|---|---|---|
| Event | Method name | snake_case of event name |
| Event | Parameter type | {EventName}Params |
| Action | Method name | snake_case of action name |
| State | State name | Preserved as written in PlantUML |
| State | Function name | snake_case of state name |
Example
1. Create a PlantUML state diagram
@startuml PlantFsm
state Winter {
state Freezing
state Mild
[*] --> Freezing
Freezing -> Mild: TemperatureRises
Mild -> Freezing: TemperatureDrops
}
state Spring {
state Chilly
state Warm
[*] --> Chilly
Chilly -> Warm: TemperatureRises
Warm -> Chilly: TemperatureDrops
}
[*] --> Winter
Winter --> Spring : TimeAdvances
Spring --> Summer : TimeAdvances / StartBlooming
Summer --> Autumn : TimeAdvances / RipenFruit
Autumn --> Winter : TimeAdvances / DropPetals
@enduml
2. Generate the state machine
use generate_fsm;
// Generate FSM from PlantUML file
generate_fsm!;
3. Implement your actions
use ;
;
4. Use your state machine
use PlantFsm;