This directory contains example applications demonstrating various features of the statechart library.
To run an example:
cargo run --example <example_name>For example:
cargo run --example traffic_lightTo run examples with the derive macros feature enabled:
cargo run --example media_player --features macrosA simple traffic light controller demonstrating:
- Basic state transitions
- Event processing
- Actions on transitions
- Context state tracking
Key Concepts:
- Simple state machine with 3 states (Red, Yellow, Green)
- Timer-based transitions
- Cycle counting in context
Run:
cargo run --example traffic_lightA door controller with safety features demonstrating:
- Guard conditions
- Complex transition logic
- Safety mechanisms
- State-dependent behavior
Key Concepts:
- Guards to control transitions based on context
- Obstacle detection and reversal
- Safety-enabled operation
- Multiple transitions from same state
Run:
cargo run --example door_controllerA media player with buffering demonstrating:
- Derive macros for cleaner code
- Multiple state transitions
- Buffer management
- Playback control
Key Concepts:
- Using
#[derive(StateId)],#[derive(EventId)], and#[derive(Context)] - Guard conditions based on buffer level
- Position tracking
- Play/Pause/Stop operations
Run:
cargo run --example media_player --features macrosEach example follows this pattern:
- Define State and Event Types: Enums representing states and events
- Define Context: Struct holding state machine data
- Implement Required Traits:
StateId,EventId,Context(or use derive macros) - Build State Machine: Use the builder API to configure states and transitions
- Process Events: Simulate real-world event processing
- Display Results: Show state changes and context updates
We recommend exploring the examples in this order:
- traffic_light.rs - Start here for basic concepts
- door_controller.rs - Learn about guards and complex logic
- media_player.rs - See derive macros and advanced features
let mut machine = StateMachine::builder()
.initial_state(MyState::Initial)
.add_state(MyState::Initial)
.add_state(MyState::Final)
.add_transition(
Transition::new(MyState::Initial, MyState::Final, MyEvent::Go)
)
.build()?;.add_transition(
Transition::new(source, target, event)
.with_action(|ctx: &mut MyContext| {
// Perform action
ctx.counter += 1;
})
).add_transition(
Transition::new(source, target, event)
.with_guard(|ctx: &MyContext| ctx.is_ready)
.with_action(|ctx: &mut MyContext| {
// Only executes if guard passes
})
)#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, StateId)]
enum MyState {
Idle,
Active,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EventId)]
enum MyEvent {
Start,
Stop,
}
#[derive(Debug, Clone, Context)]
struct MyContext {
data: String,
}After exploring these examples:
- Read the API Documentation
- Check out the Integration Tests for more complex scenarios
- Review the Architecture Documentation
- Try building your own state machine!
Have an interesting use case? Consider contributing an example! Examples should:
- Demonstrate a specific feature or pattern
- Be well-commented and easy to understand
- Include a description in this README
- Follow the existing code style