### Ruby State Machine Example Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md A basic example of a state machine in Ruby using the state_machines gem. It defines states, events, transitions, and callback hooks. ```ruby class Vehicle state_machine :state, initial: :parked do event :ignite do transition parked: :idling end before_transition parked: :idling, do: :check_fuel end def check_fuel puts "Checking fuel..." end end # Usage vehicle = Vehicle.new vehicle.ignite # Mutates vehicle in place ``` -------------------------------- ### Implement Dynamic Event Dispatching Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Provides a complete example of using a dynamic state machine to handle events at runtime. It demonstrates creating the machine, dispatching events, and querying the current state. ```rust use state_machines::state_machine; state_machine! { name: TrafficLight, dynamic: true, initial: Red, states: [Red, Yellow, Green], events { next { transition: { from: Red, to: Green } transition: { from: Green, to: Yellow } transition: { from: Yellow, to: Red } } } } fn main() { let mut light = DynamicTrafficLight::new(()); light.handle(TrafficLightEvent::Next).unwrap(); assert_eq!(light.current_state(), "Green"); } ``` -------------------------------- ### Define and use a state machine with the state_machine! macro Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Demonstrates how to define a state machine using the provided macro and perform type-safe transitions. The example shows the transition flow between Red, Green, and Yellow states. ```toml [dependencies] state-machines = "0.8" ``` ```rust use state_machines::state_machine; // Define your state machine state_machine! { name: TrafficLight, initial: Red, states: [Red, Yellow, Green], events { next { transition: { from: Red, to: Green } transition: { from: Green, to: Yellow } transition: { from: Yellow, to: Red } } } } fn main() { // Typestate pattern: each transition returns a new typed machine let light = TrafficLight::new(()); // Type is TrafficLight let light = light.next().unwrap(); // Type is TrafficLight let light = light.next().unwrap(); // Type is TrafficLight } ``` -------------------------------- ### Event-Driven Dynamic State Machine Example in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md An example of an event-driven connection state machine using the dynamic mode. It defines states, events, and transitions, then handles network events. ```rust use state_machines::{state_machine, DynamicError}; state_machine! { name: Connection, dynamic: true, initial: Disconnected, states: [Disconnected, Connecting, Connected, Failed], events { connect { transition: { from: Disconnected, to: Connecting } } established { transition: { from: Connecting, to: Connected } } timeout { transition: { from: Connecting, to: Failed } } disconnect { transition: { from: [Connecting, Connected], to: Disconnected } } } } fn handle_network_events(conn: &mut DynamicConnection<()>) { // Receive events from network layer let events = vec![ ConnectionEvent::Connect, ConnectionEvent::Established, ConnectionEvent::Disconnect, ]; for event in events { match conn.handle(event) { Ok(()) => { println!("State: {}", conn.current_state()); } Err(DynamicError::InvalidTransition { from, event }) => { eprintln!("Can't {} from {}", event, from); } Err(DynamicError::GuardFailed { guard, event }) => { eprintln!("Guard {} failed for {}", guard, event); } Err(DynamicError::ActionFailed { action, event }) => { eprintln!("Action {} failed for {}", action, event); } } } } fn main() { let mut conn = DynamicConnection::new(()); handle_network_events(&mut conn); } ``` -------------------------------- ### Ruby State Machine Example Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Demonstrates a state machine implementation in Ruby using the state_machines gem. It defines states, events, and transition callbacks. ```ruby class Vehicle state_machine :state, initial: :parked do event :ignite do transition parked: :idling end before_transition parked: :idling, do: :check_fuel end def check_fuel puts "Checking fuel..." end end # Usage vehicle = Vehicle.new vehicle.ignite # Mutates vehicle in place ``` -------------------------------- ### Define and Use Typestate Machine in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Demonstrates the use of the state_machine! macro to define states and transitions. The example shows how the typestate pattern enforces valid state transitions at compile time. ```rust use state_machines::state_machine; state_machine! { name: Vehicle, initial: Parked, states: [Parked, Idling], events { ignite { before: [check_fuel], transition: { from: Parked, to: Idling } } } } impl Vehicle { fn check_fuel(&self) { println!("Checking fuel..."); } } fn main() { let vehicle = Vehicle::new(()); let vehicle = vehicle.ignite().unwrap(); } ``` -------------------------------- ### Rust State Machine with Guards and Callbacks Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Demonstrates a Rust state machine with guards for conditional transitions and callbacks for executing logic before or after transitions. It includes examples of successful and failed transitions due to guard conditions. ```rust use state_machines::{state_machine, core::GuardError}; use std::sync::atomic::{AtomicBool, Ordering}; static DOOR_OBSTRUCTED: AtomicBool = AtomicBool::new(false); state_machine! { name: Door, initial: Closed, states: [Closed, Open], events { open { guards: [path_clear], before: [check_safety], after: [log_opened], transition: { from: Closed, to: Open } } close { transition: { from: Open, to: Closed } } } } impl Door { fn path_clear(&self, _ctx: &C) -> bool { !DOOR_OBSTRUCTED.load(Ordering::Relaxed) } fn check_safety(&self) { println!("Checking if path is clear..."); } fn log_opened(&self) { println!("Door opened at {:?}", std::time::SystemTime::now()); } } fn main() { // Successful transition let door = Door::new(()); let door = door.open().unwrap(); let door = door.close().unwrap(); // Failed guard check DOOR_OBSTRUCTED.store(true, Ordering::Relaxed); let err = door.open().expect_err("should fail when obstructed"); let (_door, guard_err) = err; assert_eq!(guard_err.guard, "path_clear"); // Inspect the error kind use state_machines::core::TransitionErrorKind; match guard_err.kind { TransitionErrorKind::GuardFailed { guard } => { println!("Guard '{}' failed", guard); } _ => unreachable!(), } } ``` -------------------------------- ### Rust Typestate State Machine Example Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Illustrates a state machine in Rust using the typestate pattern provided by the state_machines library. This approach leverages the type system for compile-time safety and guarantees. ```rust use state_machines::state_machine; state_machine! { name: Vehicle, initial: Parked, states: [Parked, Idling], events { ignite { before: [check_fuel], transition: { from: Parked, to: Idling } } } } impl Vehicle { fn check_fuel(&self) { println!("Checking fuel..."); } } fn main() { // Type: Vehicle let vehicle = Vehicle::new(()); // Type: Vehicle let vehicle = vehicle.ignite().unwrap(); } ``` -------------------------------- ### Implement Guards and Callbacks in Rust State Machines Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Demonstrates the use of guards to validate transitions and before/after callbacks for side effects. The example shows how to handle guard failures using the library's error types. ```rust use state_machines::{state_machine, core::GuardError}; use std::sync::atomic::{AtomicBool, Ordering}; static DOOR_OBSTRUCTED: AtomicBool = AtomicBool::new(false); state_machine! { name: Door, initial: Closed, states: [Closed, Open], events { open { guards: [path_clear], before: [check_safety], after: [log_opened], transition: { from: Closed, to: Open } } close { transition: { from: Open, to: Closed } } } } impl Door { fn path_clear(&self, _ctx: &C) -> bool { !DOOR_OBSTRUCTED.load(Ordering::Relaxed) } fn check_safety(&self) { println!("Checking if path is clear..."); } fn log_opened(&self) { println!("Door opened at {:?}", std::time::SystemTime::now()); } } fn main() { let door = Door::new(()); let door = door.open().unwrap(); let door = door.close().unwrap(); DOOR_OBSTRUCTED.store(true, Ordering::Relaxed); let err = door.open().expect_err("should fail when obstructed"); let (_door, guard_err) = err; assert_eq!(guard_err.guard, "path_clear"); } ``` -------------------------------- ### Rust Circuit Breaker Pattern Example Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md An implementation of the circuit breaker pattern using dynamic state machines in Rust. Demonstrates state transitions and data manipulation for managing request failures. ```rust use std::time::Instant; use std::time::Duration; #[derive(Debug, Clone)] struct OpenData { opened_at: Instant, failure_count: u32, } #[derive(Debug, Clone)] struct HalfOpenData { consecutive_successes: u32, } state_machine! { name: Circuit, dynamic: true, initial: Closed, states: [ Closed, Open(OpenData), HalfOpen(HalfOpenData), ], events { trip { transition: { from: Closed, to: Open } } attempt_reset { transition: { from: Open, to: HalfOpen } } reset { transition: { from: HalfOpen, to: Closed } } fail_again { transition: { from: HalfOpen, to: Open } } } } struct CircuitBreaker { machine: DynamicCircuit, } impl CircuitBreaker { pub fn new() -> Self { Self { machine: DynamicCircuit::new(()), } } pub fn call(&mut self) -> Result { match self.machine.current_state() { "Closed" => { // Execute call match execute_request() { Ok(resp) => Ok(resp), Err(e) => { // Trip circuit on failure self.machine.handle(CircuitEvent::Trip).unwrap(); self.machine .set_open_data(OpenData { opened_at: Instant::now(), failure_count: 1, }) .unwrap(); Err(e) } } } "Open" => { // Check if timeout expired if let Some(data) = self.machine.open_data() { if data.opened_at.elapsed() > Duration::from_secs(60) { // Try half-open self.machine.handle(CircuitEvent::AttemptReset).unwrap(); self.machine .set_half_open_data(HalfOpenData { consecutive_successes: 0, }) .unwrap(); return self.call(); // Retry } } Err(Error::CircuitOpen) } "HalfOpen" => { // Execute call, track successes match execute_request() { Ok(resp) => { // Increment success counter if let Some(data) = self.machine.half_open_data_mut() { data.consecutive_successes += 1; // Reset after 3 successes if data.consecutive_successes >= 3 { self.machine.handle(CircuitEvent::Reset).unwrap(); } } Ok(resp) } Err(e) => { // Back to Open self.machine.handle(CircuitEvent::FailAgain).unwrap(); Err(e) } } } _ => unreachable!(), } } } // Dummy functions/types for compilation struct Response; struct Error; impl Error { const CircuitOpen: Self = Error; } fn execute_request() -> Result { Ok(Response) } ``` -------------------------------- ### Dynamic Mode Error Handling Example in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Illustrates error handling in Rust's dynamic state machines. Unlike typestate, dynamic mode keeps the machine in a valid state even after an error. ```rust let mut machine = DynamicTrafficLight::new(()); // Invalid transition let result = machine.handle(TrafficLightEvent::Next); // Red → Green (valid) assert!(result.is_ok()); // Machine is now in Green state, regardless of success/failure assert_eq!(machine.current_state(), "Green"); ``` -------------------------------- ### Rust: Implement Transactional Semantics with Around Callbacks Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Demonstrates how to use 'around callbacks' in Rust to wrap state transitions with transaction-like semantics. It includes Before and AfterSuccess hooks that bracket the entire transition execution, ensuring operations like logging or resource management are handled atomically. The example uses `AroundStage::Before` and `AroundStage::AfterSuccess` to increment a counter, simulating transaction commit and rollback logic. ```rust use state_machines::{state_machine, core::{AroundStage, AroundOutcome}}; use std::sync::atomic::{AtomicUsize, Ordering}; static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); state_machine! { name: Transaction, initial: Idle, states: [Idle, Processing, Complete], events { begin { around: [transaction_wrapper], transition: { from: Idle, to: Processing } } succeed { transition: { from: Processing, to: Complete } } } } impl Transaction { fn transaction_wrapper(&self, stage: AroundStage) -> AroundOutcome { match stage { AroundStage::Before => { println!("Starting transaction..."); CALL_COUNT.fetch_add(1, Ordering::SeqCst); AroundOutcome::Proceed } AroundStage::AfterSuccess => { println!("Transaction committed!"); CALL_COUNT.fetch_add(10, Ordering::SeqCst); AroundOutcome::Proceed } } } } fn main() { let transaction = Transaction::new(()); let transaction = transaction.begin().unwrap(); // CALL_COUNT is now 11 (Before: +1, AfterSuccess: +10) assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 11); } ``` -------------------------------- ### Rust: Abort State Transitions with Around Callbacks Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Illustrates how to abort state transitions in Rust using 'around callbacks' at the `AroundStage::Before` stage. By returning `AroundOutcome::Abort` with a `TransitionError`, the transition is prevented from occurring. This is useful for implementing complex guard conditions or pre-transition checks that can halt the process. The example shows how to inspect the resulting error to confirm the abort reason. ```rust use state_machines::{ state_machine, core::{AroundStage, AroundOutcome, TransitionError}, }; state_machine! { name: Guarded, initial: Start, states: [Start, End], events { advance { around: [abort_guard], transition: { from: Start, to: End } } } } impl Guarded { fn abort_guard(&self, stage: AroundStage) -> AroundOutcome { match stage { AroundStage::Before => { // Abort at Before stage AroundOutcome::Abort(TransitionError::guard_failed( Start, "advance", "abort_guard", )) } AroundStage::AfterSuccess => { // Won't be called when Before aborts AroundOutcome::Proceed } } } } fn main() { let machine = Guarded::new(()); let result = machine.advance(); assert!(result.is_err()); let (_machine, err) = result.unwrap_err(); assert_eq!(err.guard, "abort_guard"); } ``` -------------------------------- ### Define and Use a Basic State Machine in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md This Rust code defines a simple TrafficLight state machine using the `state_machine!` macro. It demonstrates the typestate pattern where each valid transition returns a new, type-safe instance of the state machine, preventing invalid transitions at compile time. The example shows how to initialize the machine and trigger transitions. ```rust use state_machines::state_machine; // Define your state machine state_machine! { name: TrafficLight, initial: Red, states: [Red, Yellow, Green], events { next { transition: { from: Red, to: Green } transition: { from: Green, to: Yellow } transition: { from: Yellow, to: Red } } } } fn main() { // Typestate pattern: each transition returns a new typed machine let light = TrafficLight::new(()); // Type is TrafficLight let light = light.next().unwrap(); // Type is TrafficLight let light = light.next().unwrap(); // Type is TrafficLight } ``` -------------------------------- ### Run Performance Benchmarks Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Command to execute the library's performance benchmarks to verify zero-cost abstraction claims. ```bash cargo bench --bench typestate_transitions ``` -------------------------------- ### Comparison of Typestate and Dynamic State Machine Modes in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md A table comparing the performance, safety, and use cases of typestate and dynamic modes for state machines in Rust. ```markdown | Mode | Overhead | Safety | Use Case | |------|----------|--------|----------| | **Typestate** | Zero (PhantomData) | Compile-time | Known sequences | | **Dynamic** | Enum match (~few ns) | Runtime | Event-driven | ``` -------------------------------- ### Switching from Typestate to Dynamic Mode in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Demonstrates converting a typestate state machine to a dynamic one for runtime flexibility. This allows handling events from external sources in a loop. ```rust use state_machines::TrafficLight; // Start with typestate for setup let light = TrafficLight::new(()); // Type: TrafficLight<(), Red> // Perform type-safe transitions let light = light.next().unwrap(); // Type: TrafficLight<(), Green> // Convert to dynamic for event loop let mut dynamic_light = light.into_dynamic(); // Now handle runtime events loop { let event = receive_event(); // From network, user input, etc match dynamic_light.handle(event) { Ok(()) => println!("Transitioned to {}", dynamic_light.current_state()), Err(e) => eprintln!("Transition failed: {:?}", e), } } ``` -------------------------------- ### Rust State Machine with Concrete Context for Embedded Systems Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Illustrates defining a Rust state machine with a concrete context type, suitable for embedded systems. This allows guards and callbacks to directly access hardware-specific fields, improving type safety and performance. ```rust use state_machines::state_machine; #[derive(Debug, Default)] struct HardwareSensors { temperature_c: i16, pressure_kpa: u32, } state_machine! { name: Door, context: HardwareSensors, // ← Concrete context type initial: Closed, states: [Closed, Open], events { open { guards: [safe_conditions], transition: { from: Closed, to: Open } } close { transition: { from: Open, to: Closed } } } } impl Door { fn safe_conditions(&self, ctx: &HardwareSensors) -> bool { // Direct field access! ctx.temperature_c >= -40 && ctx.temperature_c <= 85 && ctx.pressure_kpa >= 95 && ctx.pressure_kpa <= 105 } } fn main() { let sensors = HardwareSensors { temperature_c: 22, pressure_kpa: 101, }; let door = Door::new(sensors); let door = door.open().unwrap(); let _door = door.close().unwrap(); } ``` -------------------------------- ### Define Asynchronous State Machines in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Demonstrates how to enable async support in a state machine definition. It includes an async guard function and shows how to await state transitions in an async main function. ```rust use state_machines::state_machine; state_machine! { name: HttpRequest, initial: Idle, async: true, states: [Idle, Pending, Success, Failed], events { send { guards: [has_network], transition: { from: Idle, to: Pending } } succeed { transition: { from: Pending, to: Success } } fail { transition: { from: Pending, to: Failed } } } } impl HttpRequest { async fn has_network(&self, _ctx: &C) -> bool { tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; true } } #[tokio::main] async fn main() { let request = HttpRequest::new(()); let request = request.send().await.unwrap(); let request = request.succeed().await.unwrap(); } ``` -------------------------------- ### Enable Dynamic Dispatch in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Shows how to enable dynamic dispatch for state machines to support runtime event routing. This can be configured via the macro parameter or through Cargo feature flags. ```rust state_machine! { name: TrafficLight, dynamic: true, initial: Red, states: [Red, Yellow, Green], events { /* ... */ } } ``` ```toml [dependencies] state-machines = { version = "0.6", features = ["dynamic"] } ``` -------------------------------- ### Converting from Dynamic to Typestate Mode in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Shows how to convert a dynamic state machine back to a typestate machine when the current state is known. This restores compile-time guarantees. ```rust let mut dynamic = DynamicTrafficLight::new(()); dynamic.handle(TrafficLightEvent::Next).unwrap(); // Extract typed machine if in Green state if let Ok(typed) = dynamic.into_green() { // Type: TrafficLight<(), Green> // Now have compile-time guarantees again let _ = typed.next(); } ``` -------------------------------- ### Implement no_std State Machine for Embedded Systems Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Shows how to configure the state machine for no_std environments, suitable for embedded targets like ESP32. This implementation uses zero-sized state markers and avoids heap allocation. ```rust #![no_std] use state_machines::state_machine; state_machine! { name: LedController, initial: Off, states: [Off, On, Blinking], events { toggle { transition: { from: Off, to: On } } blink { transition: { from: On, to: Blinking } } } } fn embedded_main() { let led = LedController::new(()); let led = led.toggle().unwrap(); let led = led.blink().unwrap(); } ``` -------------------------------- ### Configure Multiple Around Callbacks in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Demonstrates how to chain multiple around callbacks within a state machine definition. These callbacks execute in sequence to handle logging, metrics, and transaction management during transitions. ```rust state_machine! { name: Multi, initial: X, states: [X, Y], events { go { around: [logging_wrapper, metrics_wrapper, transaction_wrapper], transition: { from: X, to: Y } } } } ``` -------------------------------- ### Implement Event-Driven State Machines in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Shows how to define a dynamic state machine using the state_machine! macro and process a sequence of events while handling potential transition errors. ```rust use state_machines::{state_machine, DynamicError}; state_machine! { name: Connection, dynamic: true, initial: Disconnected, states: [Disconnected, Connecting, Connected, Failed], events { connect { transition: { from: Disconnected, to: Connecting } } established { transition: { from: Connecting, to: Connected } } timeout { transition: { from: Connecting, to: Failed } } disconnect { transition: { from: [Connecting, Connected], to: Disconnected } } } } fn handle_network_events(conn: &mut DynamicConnection<()>) { let events = vec![ ConnectionEvent::Connect, ConnectionEvent::Established, ConnectionEvent::Disconnect, ]; for event in events { match conn.handle(event) { Ok(()) => { println!("State: {}", conn.current_state()); } Err(DynamicError::InvalidTransition { from, event }) => { eprintln!("Can't {} from {}", event, from); } Err(DynamicError::GuardFailed { guard, event }) => { eprintln!("Guard {} failed for {}", guard, event); } Err(DynamicError::ActionFailed { action, event }) => { eprintln!("Action {} failed for {}", action, event); } Err(DynamicError::WrongState { expected, actual, operation }) => { eprintln!("Operation {} expected state {}, but in {}", operation, expected, actual); } } } } ``` -------------------------------- ### Enable Dynamic Dispatch Mode Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Shows how to enable runtime dynamic dispatch for state machines. This allows for event handling from external sources and storing machines in collections. ```rust state_machine! { name: TrafficLight, dynamic: true, initial: Red, states: [Red, Yellow, Green], events { /* ... */ } } ``` ```toml [dependencies] state-machines = { version = "0.2", features = ["dynamic"] } ``` -------------------------------- ### Convert between Typestate and Dynamic modes in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Demonstrates how to convert a compile-time typestate machine into a dynamic machine for runtime flexibility, and how to safely convert back to a typed machine when the state is known. ```rust // Start with typestate for setup let light = TrafficLight::new(()); // Type: TrafficLight<(), Red> // Perform type-safe transitions let light = light.next().unwrap(); // Type: TrafficLight<(), Green> // Convert to dynamic for event loop let mut dynamic_light = light.into_dynamic(); // Now handle runtime events loop { let event = receive_event(); // From network, user input, etc match dynamic_light.handle(event) { Ok(()) => println!("Transitioned to {}", dynamic_light.current_state()), Err(e) => eprintln!("Transition failed: {:?}", e), } } // Convert back to typestate when you know the current state let mut dynamic = DynamicTrafficLight::new(()); dynamic.handle(TrafficLightEvent::Next).unwrap(); // Extract typed machine if in Green state if let Ok(typed) = dynamic.into_green() { // Type: TrafficLight<(), Green> // Now have compile-time guarantees again let _ = typed.next(); } ``` -------------------------------- ### Rust State Machine Macro Internals (Under the Hood) Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Illustrates the internal code generated by the `state_machine!` macro for hierarchical states in Rust. It shows the implementation of `SubstateOf` traits for polymorphism and the generation of state-specific data accessors. ```rust // Marker trait for polymorphism impl SubstateOf for LaunchPrep {} impl SubstateOf for Launching {} // Polymorphic transition implementation impl> LaunchSequence { pub fn abort(self) -> Result, ...> { // Works from ANY state where S implements SubstateOf } } // State-specific data accessors (no Option wrapper!) impl LaunchSequence { pub fn launch_prep_data(&self) -> &PrepData { ... } pub fn launch_prep_data_mut(&mut self) -> &mut PrepData { ... } } ``` -------------------------------- ### Rust Hierarchical States with Superstates Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Defines a state machine with hierarchical states (superstates) in Rust. It demonstrates how to group related states like 'LaunchPrep' and 'Launching' under a 'Flight' superstate, enabling polymorphic transitions and automatic resolution to child states. State-specific data is accessed via generated accessor methods. ```rust use state_machines::state_machine; #[derive(Default, Debug, Clone)] struct PrepData { checklist_complete: bool, } #[derive(Default, Debug, Clone)] struct LaunchData { engines_ignited: bool, } state_machine! { name: LaunchSequence, initial: Standby, states: [ Standby, superstate Flight { state LaunchPrep(PrepData), state Launching(LaunchData), }, InOrbit, ], events { enter_flight { transition: { from: Standby, to: Flight } } ignite { transition: { from: Standby, to: LaunchPrep } } cycle_engines { transition: { from: LaunchPrep, to: Launching } } ascend { transition: { from: Flight, to: InOrbit } } abort { transition: { from: Flight, to: Standby } } } } fn main() { // Start in Standby let sequence = LaunchSequence::new(()); // Transition to Flight superstate resolves to initial child (LaunchPrep) let sequence = sequence.enter_flight().unwrap(); // Access state-specific data (guaranteed non-None) let prep_data = sequence.launch_prep_data(); println!("Checklist complete: {}", prep_data.checklist_complete); // Move to Launching within Flight superstate let sequence = sequence.cycle_engines().unwrap(); // abort() is defined on Flight, but works from ANY substate let sequence = sequence.abort().unwrap(); // Type: LaunchSequence // Go directly to LaunchPrep (bypassing superstate entry) let sequence = sequence.ignite().unwrap(); // Type: LaunchSequence // abort() STILL works - polymorphic transition! let _sequence = sequence.abort().unwrap(); } ``` -------------------------------- ### Ruby State Predicate Comparison for Hierarchical States Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Compares the Rust approach to hierarchical states with a Ruby equivalent using state predicates. This highlights the compile-time safety and efficiency of Rust's typestate pattern versus Ruby's runtime checks. ```ruby # Ruby approach def in_flight? [:launch_prep, :launching].include?(state) end # Rust: Compile-time polymorphism via trait bounds impl> LaunchSequence { pub fn abort(self) -> ... { } } ``` -------------------------------- ### Distinguish Transition Error Types in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Illustrates how to return specific TransitionErrorKind variants within an around callback to provide detailed feedback when a transition fails. ```rust use state_machines::{ state_machine, core::{AroundStage, AroundOutcome, TransitionError, TransitionErrorKind}, }; state_machine! { name: Workflow, initial: Pending, states: [Pending, Validated, Complete], events { validate { around: [validation_wrapper], transition: { from: Pending, to: Validated } } } } impl Workflow { fn validation_wrapper(&self, stage: AroundStage) -> AroundOutcome { match stage { AroundStage::Before => { AroundOutcome::Abort(TransitionError { from: Pending, event: "validate", kind: TransitionErrorKind::ActionFailed { action: "validation_wrapper", }, }) } AroundStage::AfterSuccess => AroundOutcome::Proceed, } } } fn main() { let workflow = Workflow::new(()); let result = workflow.validate(); if let Err((_workflow, err)) = result { match err.kind { TransitionErrorKind::GuardFailed { guard } => { println!("Guard '{}' prevented transition", guard); } TransitionErrorKind::ActionFailed { action } => { println!("Action '{}' aborted transition", action); } TransitionErrorKind::InvalidTransition => { println!("Invalid state transition"); } } } } ``` -------------------------------- ### Handle Event Payloads in State Machines Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Shows how to pass custom data structures as payloads to state machine events. The guard function receives the payload reference to validate transitions based on input data. ```rust use state_machines::state_machine; #[derive(Clone, Debug)] struct LoginCredentials { username: String, password: String, } state_machine! { name: AuthSession, initial: LoggedOut, states: [LoggedOut, LoggedIn, Locked], events { login { payload: LoginCredentials, guards: [valid_credentials], transition: { from: LoggedOut, to: LoggedIn } } logout { transition: { from: LoggedIn, to: LoggedOut } } } } impl AuthSession { fn valid_credentials(&self, _ctx: &C, creds: &LoginCredentials) -> bool { creds.username == "admin" && creds.password == "secret" } } fn main() { let session = AuthSession::new(()); let good_creds = LoginCredentials { username: "admin".to_string(), password: "secret".to_string(), }; let session = session.login(good_creds).unwrap(); } ``` -------------------------------- ### Generated Dynamic Dispatch Components Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Illustrates the structures and methods automatically generated by the macro when dynamic mode is enabled, including the event enum and the dynamic wrapper. ```rust pub enum TrafficLightEvent { Next, } pub struct DynamicTrafficLight { // Internal state wrapper } impl DynamicTrafficLight { pub fn new(ctx: C) -> Self { /* ... */ } pub fn handle(&mut self, event: TrafficLightEvent) -> Result<(), DynamicError> { /* ... */ } pub fn current_state(&self) -> &'static str { /* ... */ } } ``` -------------------------------- ### Rust No-std State Machine for Embedded Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Shows a state machine implementation in Rust designed for `no_std` environments, suitable for embedded systems like ESP32. It demonstrates disabling default features for minimal dependencies. ```rust #![no_std] use state_machines::state_machine; state_machine! { name: LedController, initial: Off, states: [Off, On, Blinking], events { toggle { transition: { from: Off, to: On } } blink { transition: { from: On, to: Blinking } } } } fn embedded_main() { // Type: LedController let led = LedController::new(()); // Type: LedController let led = led.toggle().unwrap(); // Type: LedController let led = led.blink().unwrap(); // Wire up to GPIO pins... } # fn main() {} // For doctest ``` -------------------------------- ### Implement Transaction-like Around Callbacks in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Demonstrates using AroundStage to execute logic before and after a state transition. This pattern is useful for managing resources or logging that requires bracketed execution. ```rust use state_machines::{state_machine, core::{AroundStage, AroundOutcome}}; use std::sync::atomic::{AtomicUsize, Ordering}; static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); state_machine! { name: Transaction, initial: Idle, states: [Idle, Processing, Complete], events { begin { around: [transaction_wrapper], transition: { from: Idle, to: Processing } } succeed { transition: { from: Processing, to: Complete } } } } impl Transaction { fn transaction_wrapper(&self, stage: AroundStage) -> AroundOutcome { match stage { AroundStage::Before => { println!("Starting transaction..."); CALL_COUNT.fetch_add(1, Ordering::SeqCst); AroundOutcome::Proceed } AroundStage::AfterSuccess => { println!("Transaction committed!"); CALL_COUNT.fetch_add(10, Ordering::SeqCst); AroundOutcome::Proceed } } } } fn main() { let transaction = Transaction::new(()); let transaction = transaction.begin().unwrap(); assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 11); } ``` -------------------------------- ### Abort Transitions via Around Callbacks in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Shows how to prevent a state transition by returning AroundOutcome::Abort during the Before stage. This is useful for implementing custom validation or security guards. ```rust use state_machines::{ state_machine, core::{AroundStage, AroundOutcome, TransitionError}, }; state_machine! { name: Guarded, initial: Start, states: [Start, End], events { advance { around: [abort_guard], transition: { from: Start, to: End } } } } impl Guarded { fn abort_guard(&self, stage: AroundStage) -> AroundOutcome { match stage { AroundStage::Before => { AroundOutcome::Abort(TransitionError::guard_failed( Start, "advance", "abort_guard", )) } AroundStage::AfterSuccess => { AroundOutcome::Proceed } } } } fn main() { let machine = Guarded::new(()); let result = machine.advance(); assert!(result.is_err()); let (_machine, err) = result.unwrap_err(); assert_eq!(err.guard, "abort_guard"); } ``` -------------------------------- ### Pass Payloads to State Machine Events Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Explains how to pass custom data structures as payloads to state machine events. Guards can access these payloads to perform conditional logic based on the provided input. ```rust #[derive(Clone, Debug)] struct LoginCredentials { username: String, password: String, } state_machine! { name: AuthSession, initial: LoggedOut, states: [LoggedOut, LoggedIn, Locked], events { login { payload: LoginCredentials, guards: [valid_credentials], transition: { from: LoggedOut, to: LoggedIn } } logout { transition: { from: LoggedIn, to: LoggedOut } } } } impl AuthSession { fn valid_credentials(&self, _ctx: &C, creds: &LoginCredentials) -> bool { creds.username == "admin" && creds.password == "secret" } } fn main() { let session = AuthSession::new(()); let good_creds = LoginCredentials { username: "admin".to_string(), password: "secret".to_string(), }; let session = session.login(good_creds).unwrap(); } ``` -------------------------------- ### Handle Dynamic State Machine Errors Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Defines the structure of the DynamicError enum and demonstrates how dynamic mode maintains machine state integrity even after failed transitions. ```rust pub enum DynamicError { InvalidTransition { from: &'static str, event: &'static str }, GuardFailed { guard: &'static str, event: &'static str }, ActionFailed { action: &'static str, event: &'static str }, WrongState { expected: &'static str, actual: &'static str, operation: &'static str }, } let mut machine = DynamicTrafficLight::new(()); // Invalid transition let result = machine.handle(TrafficLightEvent::Next); // Red → Green (valid) assert!(result.is_ok()); // Machine is now in Green state, regardless of success/failure assert_eq!(machine.current_state(), "Green"); ``` -------------------------------- ### Rust: Differentiate Error Types in Around Callbacks Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Shows how to use 'around callbacks' in Rust to distinguish between different types of transition failures. The `AroundStage::Before` callback can return an `AroundOutcome::Abort` with a `TransitionError` that specifies the `TransitionErrorKind`, such as `ActionFailed` or `GuardFailed`. This allows for more granular error handling and reporting based on the root cause of the transition failure. ```rust use state_machines::{ state_machine, core::{AroundStage, AroundOutcome, TransitionError, TransitionErrorKind}, }; state_machine! { name: Workflow, initial: Pending, states: [Pending, Validated, Complete], events { validate { around: [validation_wrapper], transition: { from: Pending, to: Validated } } } } impl Workflow { fn validation_wrapper(&self, stage: AroundStage) -> AroundOutcome { match stage { AroundStage::Before => { // Abort with ActionFailed (not GuardFailed) AroundOutcome::Abort(TransitionError { from: Pending, event: "validate", kind: TransitionErrorKind::ActionFailed { action: "validation_wrapper", }, }) } AroundStage::AfterSuccess => AroundOutcome::Proceed, } } } fn main() { let workflow = Workflow::new(()); let result = workflow.validate(); if let Err((_workflow, err)) = result { // Inspect the error kind to distinguish failure types match err.kind { TransitionErrorKind::GuardFailed { guard } => { println!("Guard '{}' prevented transition", guard); } TransitionErrorKind::ActionFailed { action } => { println!("Action '{}' aborted transition", action); } TransitionErrorKind::InvalidTransition => { println!("Invalid state transition"); } } } } ``` -------------------------------- ### Rust State Data Accessors Source: https://github.com/state-machines/state-machines-rs/blob/master/state-machines/README.md Generated accessor methods for accessing and mutating state-specific data in dynamic state machines. Includes read-only, mutable, and setter accessors. ```rust pub fn open_data(&self) -> Option<&OpenData> pub fn open_data_mut(&mut self) -> Option<&mut OpenData> pub fn set_open_data(&mut self, data: OpenData) -> Result<(), DynamicError> ``` -------------------------------- ### DynamicError Enum for State Machine Errors in Rust Source: https://github.com/state-machines/state-machines-rs/blob/master/README.md Defines the `DynamicError` enum used in Rust's dynamic state machines. It includes variants for invalid transitions, failed guards, and failed actions. ```rust pub enum DynamicError { InvalidTransition { from: &'static str, event: &'static str }, GuardFailed { guard: &'static str, event: &'static str }, ActionFailed { action: &'static str, event: &'static str }, } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.