A modern, efficient deterministic finite state machine library for Rust 2024 edition.
- β‘ Deterministic: One state + input = one next state (guaranteed)
- π Type Safe: Compile-time prevention of invalid transitions
- π Callback System: React to state changes with flexible event hooks
- π§ Macro-Driven: Clean declarative syntax for state machine definition
- π Visualization: Auto-generate Mermaid diagrams and documentation
- π Analysis Tools: Pathfinding, reachability, and connectivity analysis
- π Memory Efficient: Ring buffer with configurable history (default: 512)
- π¦ Optional Serde: Serialization support with
serdefeature
[dependencies]
yasm = "0.4.1"
# With serialization support
yasm = { version = "0.4.1", features = ["serde"] }use yasm::*;
define_state_machine! {
name: DoorStateMachine,
states: { Closed, Open, Locked },
inputs: { OpenDoor, CloseDoor, Lock, Unlock },
initial: Closed,
transitions: {
Closed + OpenDoor => Open,
Open + CloseDoor => Closed,
Closed + Lock => Locked,
Locked + Unlock => Closed
}
}fn main() {
let mut door = StateMachineInstance::<DoorStateMachine>::new();
println!("Current: {:?}", door.current_state()); // Closed
door.transition(Input::OpenDoor).unwrap();
println!("After opening: {:?}", door.current_state()); // Open
// Check what's possible next
println!("Valid inputs: {:?}", door.valid_inputs()); // [CloseDoor]
}React to state machine events with flexible callback hooks:
let mut door = StateMachineInstance::<DoorStateMachine>::new();
// React to specific state entries
door.on_state_entry(State::Open, |state| {
println!("Door opened! Turning on lights...");
});
// React to specific transitions
door.on_transition(State::Closed, Input::Lock, |from, input, to| {
println!("Security system activated: {from:?} --{input:?}--> {to:?}");
});
// Global monitoring
door.on_any_transition(|from, input, to| {
println!("State change: {from:?} β {to:?}");
});
// Now all transitions will trigger callbacks
door.transition(Input::OpenDoor).unwrap(); // Triggers callbacksAnalyze your state machine structure:
// Find reachable states
let reachable = StateMachineQuery::<DoorStateMachine>::reachable_states(&State::Closed);
println!("From Closed, can reach: {reachable:?}");
// Check connectivity
let has_path = StateMachineQuery::<DoorStateMachine>::has_path(
&State::Open,
&State::Locked
);
println!("Open can reach Locked: {has_path}");
// Find shortest path
if let Some(path) = StateMachineQuery::<DoorStateMachine>::shortest_path(
&State::Open,
&State::Locked
) {
println!("Shortest path: {path:?}");
}Generate visual documentation automatically:
// Mermaid state diagram
let diagram = StateMachineDoc::<DoorStateMachine>::generate_mermaid();
println!("{diagram}");
// Transition table
let table = StateMachineDoc::<DoorStateMachine>::generate_transition_table();
println!("{table}");Track transitions with efficient ring buffer:
// Custom history size
let mut door = StateMachineInstance::<DoorStateMachine>::with_max_history(100);
// Make some transitions
door.transition(Input::OpenDoor).unwrap();
door.transition(Input::CloseDoor).unwrap();
// View history
println!("History: {:?}", door.history());
println!("History length: {}", door.history_len());Hidden Operations
Use underscore-prefixed inputs for internal operations that won't appear in documentation:
define_state_machine! {
name: ServerStateMachine,
states: { Active, Maintenance },
inputs: { Maintain, Restore, _Debug, _AdminReset }, // Hidden inputs
initial: Active,
transitions: {
Active + Maintain => Maintenance,
Maintenance + Restore => Active,
// Hidden transitions (functional but not documented)
Active + _Debug => Active,
Maintenance + _AdminReset => Active
}
}The callback system supports various event types:
let mut workflow = StateMachineInstance::<WorkflowStateMachine>::new();
// State-specific callbacks
workflow.on_state_entry(State::Review, |state| { /* ... */ });
workflow.on_state_exit(State::Draft, |state| { /* ... */ });
// Transition-specific callbacks
workflow.on_transition(State::Draft, Input::Submit, |from, input, to| { /* ... */ });
// Global callbacks
workflow.on_any_state_entry(|state| { /* ... */ });
workflow.on_any_state_exit(|state| { /* ... */ });
workflow.on_any_transition(|from, input, to| { /* ... */ });
// Callback management
println!("Total callbacks: {}", workflow.callback_count());
workflow.clear_callbacks();Enable with the serde feature for serialization:
[dependencies]
yasm = { version = "0.4.1", features = ["serde"] }#[cfg(feature = "serde")]
{
let state = State::Open;
let json = serde_json::to_string(&state).unwrap();
let restored: State = serde_json::from_str(&json).unwrap();
}Run comprehensive examples:
# Basic usage patterns
cargo run --example basic_demo
# Advanced features and analysis
cargo run --example advanced_usage
# Callback system demonstration
cargo run --example callback_demo
# Simple callback examples
cargo run --example simple_callback_demo
# Documentation generation
cargo run --example generate_docssrc/
βββ lib.rs # Public API and comprehensive tests
βββ core.rs # StateMachine trait definition
βββ instance.rs # StateMachineInstance with history & callbacks
βββ callbacks.rs # Callback registry and event system
βββ query.rs # Analysis algorithms (paths, reachability)
βββ doc.rs # Documentation generation utilities
βββ macros.rs # define_state_machine! macro implementation
StateMachine- Core trait defining state machine behaviorStateMachineInstance<SM>- Runtime instance with state and historyCallbackRegistry<SM>- Event callback management systemStateMachineQuery<SM>- Analysis and pathfinding utilitiesStateMachineDoc<SM>- Documentation generation tools
// Instance management
let mut sm = StateMachineInstance::<MyStateMachine>::new();
let mut sm = StateMachineInstance::<MyStateMachine>::with_max_history(256);
// State operations
sm.transition(input)?; // Execute transition
sm.current_state(); // Get current state
sm.valid_inputs(); // Get valid inputs
sm.can_accept(&input); // Check if input is valid
// Callback registration
sm.on_state_entry(state, callback);
sm.on_transition(from, input, callback);
sm.on_any_transition(callback);
// History access
sm.history(); // Get transition history
sm.history_len(); // History length
sm.reset(); // Reset to initial state
// Analysis
StateMachineQuery::<SM>::reachable_states(&from);
StateMachineQuery::<SM>::shortest_path(&from, &to);
StateMachineQuery::<SM>::has_path(&from, &to);
// Documentation
StateMachineDoc::<SM>::generate_mermaid();
StateMachineDoc::<SM>::generate_transition_table();# Run all tests
cargo test
# Test with features
cargo test --features serde
# Test specific functionality
cargo test callbacksMIT License. See LICENSE for details.
Built with β€οΈ for the Rust community