StateMachine

Struct StateMachine 

Source
pub struct StateMachine<S, E, C>
where S: State, E: Event, C: Context,
{ pub(crate) id: String, pub(crate) transitions: HashMap<(S, E), Vec<Transition<S, E, C>>>, pub(crate) fail_callback: Option<FailCallback<S, E, C>>, pub(crate) history: Arc<Mutex<Vec<TransitionRecord<S, E>>>>, pub(crate) metrics: Arc<Mutex<StateMachineMetrics>>, pub(crate) state_actions: HashMap<S, StateActions<S, E, C>>, pub(crate) state_timeouts: HashMap<S, Duration>, pub(crate) timeout_transitions: HashMap<S, (S, E)>, pub(crate) async_actions: HashMap<(S, E), Box<dyn AsyncAction<S, E, C>>>, }
Expand description

The main state machine struct

Fields§

§id: String§transitions: HashMap<(S, E), Vec<Transition<S, E, C>>>§fail_callback: Option<FailCallback<S, E, C>>§history: Arc<Mutex<Vec<TransitionRecord<S, E>>>>§metrics: Arc<Mutex<StateMachineMetrics>>§state_actions: HashMap<S, StateActions<S, E, C>>§state_timeouts: HashMap<S, Duration>§timeout_transitions: HashMap<S, (S, E)>§async_actions: HashMap<(S, E), Box<dyn AsyncAction<S, E, C>>>

Implementations§

Source§

impl<S, E, C> StateMachine<S, E, C>
where S: State, E: Event, C: Context,

Source

pub fn fire_event( &self, from: S, event: E, context: C, ) -> Result<S, TransitionError>

Fire an event and perform state transition

Examples found in repository?
examples/order_example.rs (line 74)
43fn basic_example() {
44    println!("=== Basic State Machine Example ===");
45
46    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
47
48    builder
49        .external_transition()
50        .from(OrderState::New)
51        .to(OrderState::PaymentPending)
52        .on(OrderEvent::Pay)
53        .perform(|_s, _e, ctx| {
54            println!("Order {} payment initiated", ctx.order_id);
55        });
56
57    builder
58        .external_transition()
59        .from(OrderState::PaymentPending)
60        .to(OrderState::PaymentReceived)
61        .on(OrderEvent::ConfirmPayment)
62        .perform(|_s, _e, ctx| {
63            println!("Payment confirmed for order {}", ctx.order_id);
64        });
65
66    let state_machine = builder.id("BasicOrderMachine").build();
67
68    let context = OrderContext {
69        order_id: "ORD-001".to_string(),
70        amount: 99.99,
71        customer_id: "CUST-123".to_string(),
72    };
73
74    let result = state_machine.fire_event(OrderState::New, OrderEvent::Pay, context.clone());
75    println!("Transition result: {:?}", result);
76}
77
78/// Example 2: With history tracking (requires 'history' feature)
79#[cfg(feature = "history")]
80fn history_example() {
81    println!("\n=== History Tracking Example ===");
82
83    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
84
85    builder
86        .external_transition()
87        .from(OrderState::New)
88        .to(OrderState::PaymentPending)
89        .on(OrderEvent::Pay)
90        .perform(|_s, _e, _c| {});
91
92    builder
93        .external_transition()
94        .from(OrderState::PaymentPending)
95        .to(OrderState::PaymentReceived)
96        .on(OrderEvent::ConfirmPayment)
97        .perform(|_s, _e, _c| {});
98
99    builder
100        .external_transition()
101        .from(OrderState::PaymentReceived)
102        .to(OrderState::Processing)
103        .on(OrderEvent::Process)
104        .perform(|_s, _e, _c| {});
105
106    let state_machine = builder.id("HistoryOrderMachine").build();
107
108    let context = OrderContext {
109        order_id: "ORD-002".to_string(),
110        amount: 149.99,
111        customer_id: "CUST-456".to_string(),
112    };
113
114    // Execute multiple transitions
115    let _ = state_machine.fire_event(OrderState::New, OrderEvent::Pay, context.clone());
116    let _ = state_machine.fire_event(
117        OrderState::PaymentPending,
118        OrderEvent::ConfirmPayment,
119        context.clone(),
120    );
121    let _ = state_machine.fire_event(OrderState::PaymentReceived, OrderEvent::Process, context);
122
123    // Check history
124    let history = state_machine.get_history();
125    println!("Transition history:");
126    for (i, record) in history.iter().enumerate() {
127        println!(
128            "  {}. {:?} -> {:?} via {:?} (success: {})",
129            i + 1,
130            record.from,
131            record.to,
132            record.event,
133            record.success
134        );
135    }
136}
137
138/// Example 3: With entry/exit actions (requires 'extended' feature)
139#[cfg(feature = "extended")]
140fn extended_example() {
141    println!("\n=== Extended State Machine Example ===");
142
143    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
144
145    builder
146        .with_entry_action(OrderState::Processing, |state, ctx| {
147            println!(
148                "ENTRY: Starting to process order {} in state {:?}",
149                ctx.order_id, state
150            );
151        })
152        .with_exit_action(OrderState::Processing, |state, ctx| {
153            println!(
154                "EXIT: Finished processing order {} from state {:?}",
155                ctx.order_id, state
156            );
157        })
158        .with_entry_action(OrderState::Shipped, |_state, ctx| {
159            println!("ENTRY: Order {} has been shipped!", ctx.order_id);
160        });
161
162    builder
163        .external_transition()
164        .from(OrderState::PaymentReceived)
165        .to(OrderState::Processing)
166        .on(OrderEvent::Process)
167        .perform(|_s, _e, _c| {});
168
169    builder
170        .external_transition()
171        .from(OrderState::Processing)
172        .to(OrderState::Shipped)
173        .on(OrderEvent::Ship)
174        .perform(|_s, _e, _c| {});
175
176    let state_machine = builder.id("ExtendedOrderMachine").build();
177
178    let context = OrderContext {
179        order_id: "ORD-003".to_string(),
180        amount: 299.99,
181        customer_id: "CUST-789".to_string(),
182    };
183
184    let _ = state_machine.fire_event(
185        OrderState::PaymentReceived,
186        OrderEvent::Process,
187        context.clone(),
188    );
189    let _ = state_machine.fire_event(OrderState::Processing, OrderEvent::Ship, context);
190}
191
192/// Example 4: With metrics (requires 'metrics' feature)
193#[cfg(feature = "metrics")]
194fn metrics_example() {
195    println!("\n=== Metrics Collection Example ===");
196
197    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
198
199    // Add multiple transitions
200    builder
201        .external_transition()
202        .from(OrderState::New)
203        .to(OrderState::PaymentPending)
204        .on(OrderEvent::Pay)
205        .perform(|_s, _e, _c| {});
206
207    builder
208        .external_transition()
209        .from(OrderState::PaymentPending)
210        .to(OrderState::PaymentReceived)
211        .on(OrderEvent::ConfirmPayment)
212        .when(|_s, _e, ctx| ctx.amount > 0.0)
213        .perform(|_s, _e, _c| {});
214
215    builder
216        .external_transitions()
217        .from_among(vec![
218            OrderState::New,
219            OrderState::PaymentPending,
220            OrderState::Processing,
221        ])
222        .to(OrderState::Cancelled)
223        .on(OrderEvent::Cancel)
224        .perform(|_s, _e, _c| {});
225
226    let state_machine = builder.id("MetricsOrderMachine").build();
227
228    // Simulate multiple orders
229    for i in 0..10 {
230        let context = OrderContext {
231            order_id: format!("ORD-{:03}", i),
232            amount: (i as f64) * 10.0,
233            customer_id: format!("CUST-{:03}", i),
234        };
235
236        let _ = state_machine.fire_event(OrderState::New, OrderEvent::Pay, context.clone());
237
238        if i % 3 == 0 {
239            // Some orders get cancelled
240            let _ =
241                state_machine.fire_event(OrderState::PaymentPending, OrderEvent::Cancel, context);
242        } else {
243            // Others proceed normally
244            let _ = state_machine.fire_event(
245                OrderState::PaymentPending,
246                OrderEvent::ConfirmPayment,
247                context,
248            );
249        }
250    }
251
252    // Get and display metrics
253    let metrics = state_machine.get_metrics();
254    println!("State Machine Metrics:");
255    println!("  Total transitions: {}", metrics.total_transitions);
256    println!("  Successful: {}", metrics.successful_transitions);
257    println!("  Failed: {}", metrics.failed_transitions);
258    println!("  Success rate: {:.2}%", metrics.success_rate() * 100.0);
259
260    if let Some(avg_time) = metrics.average_transition_time() {
261        println!("  Average transition time: {:?}", avg_time);
262    }
263
264    println!("  State visit counts:");
265    for (state, count) in &metrics.state_visit_counts {
266        println!("    {}: {}", state, count);
267    }
268}
269
270/// Example 5: With guard priorities (requires 'guards' feature)
271#[cfg(feature = "guards")]
272fn guards_example() {
273    println!("\n=== Guard Priorities Example ===");
274
275    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
276
277    // Multiple transitions with different priorities
278    builder
279        .external_transition()
280        .from(OrderState::PaymentReceived)
281        .to(OrderState::Processing)
282        .on(OrderEvent::Process)
283        .when(|_s, _e, ctx| ctx.amount < 100.0)
284        .with_priority(10)
285        .perform(|_s, _e, ctx| {
286            println!(
287                "Processing small order {} (amount: {})",
288                ctx.order_id, ctx.amount
289            );
290        });
291
292    builder
293        .external_transition()
294        .from(OrderState::PaymentReceived)
295        .to(OrderState::Processing)
296        .on(OrderEvent::Process)
297        .when(|_s, _e, ctx| ctx.amount >= 100.0 && ctx.amount < 1000.0)
298        .with_priority(20)
299        .perform(|_s, _e, ctx| {
300            println!(
301                "Processing medium order {} (amount: {})",
302                ctx.order_id, ctx.amount
303            );
304        });
305
306    builder
307        .external_transition()
308        .from(OrderState::PaymentReceived)
309        .to(OrderState::Processing)
310        .on(OrderEvent::Process)
311        .when(|_s, _e, ctx| ctx.amount >= 1000.0)
312        .with_priority(30)
313        .perform(|_s, _e, ctx| {
314            println!(
315                "Processing large order {} (amount: {}) - Priority handling!",
316                ctx.order_id, ctx.amount
317            );
318        });
319
320    let state_machine = builder.id("GuardsOrderMachine").build();
321
322    // Test with different order amounts
323    let contexts = vec![
324        OrderContext {
325            order_id: "ORD-SMALL".to_string(),
326            amount: 50.0,
327            customer_id: "C1".to_string(),
328        },
329        OrderContext {
330            order_id: "ORD-MEDIUM".to_string(),
331            amount: 500.0,
332            customer_id: "C2".to_string(),
333        },
334        OrderContext {
335            order_id: "ORD-LARGE".to_string(),
336            amount: 5000.0,
337            customer_id: "C3".to_string(),
338        },
339    ];
340
341    for context in contexts {
342        let _ = state_machine.fire_event(OrderState::PaymentReceived, OrderEvent::Process, context);
343    }
344}
345
346/// Example 6: With visualization (requires 'visualization' feature)
347#[cfg(feature = "visualization")]
348fn visualization_example() {
349    println!("\n=== Visualization Example ===");
350
351    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
352
353    // Build a complete order flow
354    builder
355        .external_transition()
356        .from(OrderState::New)
357        .to(OrderState::PaymentPending)
358        .on(OrderEvent::Pay)
359        .perform(|_s, _e, _c| {});
360
361    builder
362        .external_transition()
363        .from(OrderState::PaymentPending)
364        .to(OrderState::PaymentReceived)
365        .on(OrderEvent::ConfirmPayment)
366        .perform(|_s, _e, _c| {});
367
368    builder
369        .external_transition()
370        .from(OrderState::PaymentReceived)
371        .to(OrderState::Processing)
372        .on(OrderEvent::Process)
373        .perform(|_s, _e, _c| {});
374
375    builder
376        .external_transition()
377        .from(OrderState::Processing)
378        .to(OrderState::Shipped)
379        .on(OrderEvent::Ship)
380        .perform(|_s, _e, _c| {});
381
382    builder
383        .external_transition()
384        .from(OrderState::Shipped)
385        .to(OrderState::Delivered)
386        .on(OrderEvent::Deliver)
387        .perform(|_s, _e, _c| {});
388
389    builder
390        .external_transitions()
391        .from_among(vec![
392            OrderState::New,
393            OrderState::PaymentPending,
394            OrderState::Processing,
395        ])
396        .to(OrderState::Cancelled)
397        .on(OrderEvent::Cancel)
398        .perform(|_s, _e, _c| {});
399
400    builder
401        .external_transition()
402        .from(OrderState::Cancelled)
403        .to(OrderState::Refunded)
404        .on(OrderEvent::Refund)
405        .perform(|_s, _e, _c| {});
406
407    let state_machine = builder.id("VisualOrderMachine").build();
408
409    println!("DOT Format:");
410    println!("{}", state_machine.to_dot());
411
412    println!("\nPlantUML Format:");
413    println!("{}", state_machine.to_plantuml());
414}
415
416/// Example 7: With parallel regions (requires 'parallel' feature)
417#[cfg(feature = "parallel")]
418fn parallel_example() {
419    println!("\n=== Parallel Regions Example ===");
420
421    // Order processing region
422    let mut order_builder =
423        StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
424    order_builder
425        .external_transition()
426        .from(OrderState::New)
427        .to(OrderState::Processing)
428        .on(OrderEvent::Process)
429        .perform(|_s, _e, ctx| {
430            println!("Order region: Processing order {}", ctx.order_id);
431        });
432
433    // Payment processing region (using same states/events for simplicity)
434    let mut payment_builder =
435        StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
436    payment_builder
437        .external_transition()
438        .from(OrderState::PaymentPending)
439        .to(OrderState::PaymentReceived)
440        .on(OrderEvent::ConfirmPayment)
441        .perform(|_s, _e, ctx| {
442            println!(
443                "Payment region: Payment confirmed for order {}",
444                ctx.order_id
445            );
446        });
447
448    let mut parallel_machine = ParallelStateMachine::new();
449    parallel_machine.add_region(order_builder.id("OrderRegion").build());
450    parallel_machine.add_region(payment_builder.id("PaymentRegion").build());
451
452    let context = OrderContext {
453        order_id: "ORD-PARALLEL".to_string(),
454        amount: 199.99,
455        customer_id: "CUST-P1".to_string(),
456    };
457
458    // Fire events in parallel regions
459    println!("Firing Process event in parallel regions:");
460    let results = parallel_machine.fire_event(
461        vec![OrderState::New, OrderState::PaymentPending],
462        OrderEvent::Process,
463        context.clone(),
464    );
465
466    for (i, result) in results.iter().enumerate() {
467        println!("  Region {}: {:?}", i, result);
468    }
469
470    println!("Firing ConfirmPayment event in parallel regions:");
471    let results = parallel_machine.fire_event(
472        vec![OrderState::Processing, OrderState::PaymentPending],
473        OrderEvent::ConfirmPayment,
474        context,
475    );
476
477    for (i, result) in results.iter().enumerate() {
478        println!("  Region {}: {:?}", i, result);
479    }
480}
481
482/// Example 8: Complete example with multiple features
483#[cfg(all(feature = "history", feature = "metrics", feature = "extended"))]
484fn complete_example() {
485    println!("\n=== Complete Example with Multiple Features ===");
486
487    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
488
489    // Configure entry/exit actions
490    builder
491        .with_entry_action(OrderState::Processing, |_s, ctx| {
492            println!("[ENTRY] Starting to process order {}", ctx.order_id);
493        })
494        .with_exit_action(OrderState::Processing, |_s, ctx| {
495            println!("[EXIT] Finished processing order {}", ctx.order_id);
496        });
497
498    // Build transitions
499    builder
500        .external_transition()
501        .from(OrderState::New)
502        .to(OrderState::PaymentPending)
503        .on(OrderEvent::Pay)
504        .perform(|_s, _e, ctx| {
505            println!("Payment initiated for ${}", ctx.amount);
506        });
507
508    builder
509        .external_transition()
510        .from(OrderState::PaymentPending)
511        .to(OrderState::PaymentReceived)
512        .on(OrderEvent::ConfirmPayment)
513        .when(|_s, _e, ctx| ctx.amount > 0.0)
514        .perform(|_s, _e, ctx| {
515            println!("Payment confirmed: ${}", ctx.amount);
516        });
517
518    builder
519        .external_transition()
520        .from(OrderState::PaymentReceived)
521        .to(OrderState::Processing)
522        .on(OrderEvent::Process)
523        .perform(|_s, _e, _c| {});
524
525    builder
526        .external_transition()
527        .from(OrderState::Processing)
528        .to(OrderState::Shipped)
529        .on(OrderEvent::Ship)
530        .perform(|_s, _e, ctx| {
531            println!("Order {} shipped", ctx.order_id);
532        });
533
534    builder.set_fail_callback(Arc::new(|state, event, ctx| {
535        println!(
536            "FAILED: Cannot handle {:?} in state {:?} for order {}",
537            event, state, ctx.order_id
538        );
539    }));
540
541    let state_machine = builder.id("CompleteOrderMachine").build();
542
543    // Process an order through the complete flow
544    let context = OrderContext {
545        order_id: "ORD-COMPLETE".to_string(),
546        amount: 999.99,
547        customer_id: "CUST-VIP".to_string(),
548    };
549
550    println!("\nProcessing order through complete flow:");
551    let states = [
552        (OrderState::New, OrderEvent::Pay),
553        (OrderState::PaymentPending, OrderEvent::ConfirmPayment),
554        (OrderState::PaymentReceived, OrderEvent::Process),
555        (OrderState::Processing, OrderEvent::Ship),
556    ];
557
558    for (state, event) in &states {
559        let result = state_machine.fire_event(state.clone(), event.clone(), context.clone());
560        println!("  {:?} + {:?} = {:?}", state, event, result);
561    }
562
563    // Try an invalid transition
564    println!("\nTrying invalid transition:");
565    let _ = state_machine.fire_event(OrderState::Shipped, OrderEvent::Pay, context);
566
567    // Display collected data
568    println!("\nHistory:");
569    for record in state_machine.get_history() {
570        println!(
571            "  {:?} -> {:?} (success: {})",
572            record.from, record.to, record.success
573        );
574    }
575
576    println!("\nMetrics:");
577    let metrics = state_machine.get_metrics();
578    println!(
579        "  Total: {}, Success: {}, Failed: {}",
580        metrics.total_transitions, metrics.successful_transitions, metrics.failed_transitions
581    );
582}
More examples
Hide additional examples
examples/traffic_light_example.rs (line 312)
290pub fn simulate_traffic_light_system() {
291    println!("=== Traffic Light Control System Demo ===\n");
292
293    let state_machine = build_traffic_light_system();
294
295    let mut context = TrafficContext {
296        intersection_id: "Main-St-First-Ave".to_string(),
297        traffic_density: 0.5,
298        pedestrian_waiting: false,
299        emergency_active: false,
300        time_in_state: std::time::Duration::from_secs(0),
301    };
302
303    // Normal cycle
304    println!("--- Normal Traffic Cycle ---");
305    let states_and_events = vec![
306        (TrafficLightState::Green, TrafficLightEvent::Timer),
307        (TrafficLightState::Yellow, TrafficLightEvent::Timer),
308        (TrafficLightState::Red, TrafficLightEvent::Timer),
309    ];
310
311    for (state, event) in states_and_events {
312        match state_machine.fire_event(state, event, context.clone()) {
313            Ok(new_state) => {
314                println!("  -> Now in {:?} state\n", new_state);
315            }
316            Err(e) => {
317                eprintln!("  ERROR: {}\n", e);
318            }
319        }
320        std::thread::sleep(std::time::Duration::from_millis(500));
321    }
322
323    // Emergency vehicle scenario
324    println!("--- Emergency Vehicle Detected ---");
325    context.emergency_active = true;
326
327    match state_machine.fire_event(
328        TrafficLightState::Green,
329        TrafficLightEvent::EmergencyVehicleDetected,
330        context.clone(),
331    ) {
332        Ok(new_state) => {
333            println!("  -> Now in {:?} state\n", new_state);
334
335            // Clear emergency after some time
336            std::thread::sleep(std::time::Duration::from_secs(2));
337            context.emergency_active = false;
338
339            match state_machine.fire_event(
340                new_state,
341                TrafficLightEvent::EmergencyCleared,
342                context.clone(),
343            ) {
344                Ok(cleared_state) => {
345                    println!("  -> Emergency cleared, now in {:?} state\n", cleared_state);
346                }
347                Err(e) => eprintln!("  ERROR clearing emergency: {}\n", e),
348            }
349        }
350        Err(e) => eprintln!("  ERROR handling emergency: {}\n", e),
351    }
352
353    // Feature-specific demonstrations
354    #[cfg(feature = "history")]
355    demonstrate_history(&state_machine);
356
357    #[cfg(feature = "metrics")]
358    demonstrate_metrics(&state_machine);
359
360    #[cfg(feature = "visualization")]
361    demonstrate_visualization(&state_machine);
362}
Source

pub fn verify(&self, from: S, event: E) -> bool

Verify if a transition is possible

Source

pub fn id(&self) -> &str

Get the ID of the state machine

Source

pub fn get_history(&self) -> Vec<TransitionRecord<S, E>>

Get transition history

Examples found in repository?
examples/traffic_light_example.rs (line 369)
365fn demonstrate_history(
366    state_machine: &StateMachine<TrafficLightState, TrafficLightEvent, TrafficContext>,
367) {
368    println!("--- Transition History ---");
369    let history = state_machine.get_history();
370    for (i, record) in history.iter().enumerate() {
371        println!(
372            "  {}. {:?} -> {:?} via {:?} ({})",
373            i + 1,
374            record.from,
375            record.to,
376            record.event,
377            if record.success { "✓" } else { "✗" }
378        );
379    }
380    println!();
381}
More examples
Hide additional examples
examples/order_example.rs (line 124)
80fn history_example() {
81    println!("\n=== History Tracking Example ===");
82
83    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
84
85    builder
86        .external_transition()
87        .from(OrderState::New)
88        .to(OrderState::PaymentPending)
89        .on(OrderEvent::Pay)
90        .perform(|_s, _e, _c| {});
91
92    builder
93        .external_transition()
94        .from(OrderState::PaymentPending)
95        .to(OrderState::PaymentReceived)
96        .on(OrderEvent::ConfirmPayment)
97        .perform(|_s, _e, _c| {});
98
99    builder
100        .external_transition()
101        .from(OrderState::PaymentReceived)
102        .to(OrderState::Processing)
103        .on(OrderEvent::Process)
104        .perform(|_s, _e, _c| {});
105
106    let state_machine = builder.id("HistoryOrderMachine").build();
107
108    let context = OrderContext {
109        order_id: "ORD-002".to_string(),
110        amount: 149.99,
111        customer_id: "CUST-456".to_string(),
112    };
113
114    // Execute multiple transitions
115    let _ = state_machine.fire_event(OrderState::New, OrderEvent::Pay, context.clone());
116    let _ = state_machine.fire_event(
117        OrderState::PaymentPending,
118        OrderEvent::ConfirmPayment,
119        context.clone(),
120    );
121    let _ = state_machine.fire_event(OrderState::PaymentReceived, OrderEvent::Process, context);
122
123    // Check history
124    let history = state_machine.get_history();
125    println!("Transition history:");
126    for (i, record) in history.iter().enumerate() {
127        println!(
128            "  {}. {:?} -> {:?} via {:?} (success: {})",
129            i + 1,
130            record.from,
131            record.to,
132            record.event,
133            record.success
134        );
135    }
136}
137
138/// Example 3: With entry/exit actions (requires 'extended' feature)
139#[cfg(feature = "extended")]
140fn extended_example() {
141    println!("\n=== Extended State Machine Example ===");
142
143    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
144
145    builder
146        .with_entry_action(OrderState::Processing, |state, ctx| {
147            println!(
148                "ENTRY: Starting to process order {} in state {:?}",
149                ctx.order_id, state
150            );
151        })
152        .with_exit_action(OrderState::Processing, |state, ctx| {
153            println!(
154                "EXIT: Finished processing order {} from state {:?}",
155                ctx.order_id, state
156            );
157        })
158        .with_entry_action(OrderState::Shipped, |_state, ctx| {
159            println!("ENTRY: Order {} has been shipped!", ctx.order_id);
160        });
161
162    builder
163        .external_transition()
164        .from(OrderState::PaymentReceived)
165        .to(OrderState::Processing)
166        .on(OrderEvent::Process)
167        .perform(|_s, _e, _c| {});
168
169    builder
170        .external_transition()
171        .from(OrderState::Processing)
172        .to(OrderState::Shipped)
173        .on(OrderEvent::Ship)
174        .perform(|_s, _e, _c| {});
175
176    let state_machine = builder.id("ExtendedOrderMachine").build();
177
178    let context = OrderContext {
179        order_id: "ORD-003".to_string(),
180        amount: 299.99,
181        customer_id: "CUST-789".to_string(),
182    };
183
184    let _ = state_machine.fire_event(
185        OrderState::PaymentReceived,
186        OrderEvent::Process,
187        context.clone(),
188    );
189    let _ = state_machine.fire_event(OrderState::Processing, OrderEvent::Ship, context);
190}
191
192/// Example 4: With metrics (requires 'metrics' feature)
193#[cfg(feature = "metrics")]
194fn metrics_example() {
195    println!("\n=== Metrics Collection Example ===");
196
197    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
198
199    // Add multiple transitions
200    builder
201        .external_transition()
202        .from(OrderState::New)
203        .to(OrderState::PaymentPending)
204        .on(OrderEvent::Pay)
205        .perform(|_s, _e, _c| {});
206
207    builder
208        .external_transition()
209        .from(OrderState::PaymentPending)
210        .to(OrderState::PaymentReceived)
211        .on(OrderEvent::ConfirmPayment)
212        .when(|_s, _e, ctx| ctx.amount > 0.0)
213        .perform(|_s, _e, _c| {});
214
215    builder
216        .external_transitions()
217        .from_among(vec![
218            OrderState::New,
219            OrderState::PaymentPending,
220            OrderState::Processing,
221        ])
222        .to(OrderState::Cancelled)
223        .on(OrderEvent::Cancel)
224        .perform(|_s, _e, _c| {});
225
226    let state_machine = builder.id("MetricsOrderMachine").build();
227
228    // Simulate multiple orders
229    for i in 0..10 {
230        let context = OrderContext {
231            order_id: format!("ORD-{:03}", i),
232            amount: (i as f64) * 10.0,
233            customer_id: format!("CUST-{:03}", i),
234        };
235
236        let _ = state_machine.fire_event(OrderState::New, OrderEvent::Pay, context.clone());
237
238        if i % 3 == 0 {
239            // Some orders get cancelled
240            let _ =
241                state_machine.fire_event(OrderState::PaymentPending, OrderEvent::Cancel, context);
242        } else {
243            // Others proceed normally
244            let _ = state_machine.fire_event(
245                OrderState::PaymentPending,
246                OrderEvent::ConfirmPayment,
247                context,
248            );
249        }
250    }
251
252    // Get and display metrics
253    let metrics = state_machine.get_metrics();
254    println!("State Machine Metrics:");
255    println!("  Total transitions: {}", metrics.total_transitions);
256    println!("  Successful: {}", metrics.successful_transitions);
257    println!("  Failed: {}", metrics.failed_transitions);
258    println!("  Success rate: {:.2}%", metrics.success_rate() * 100.0);
259
260    if let Some(avg_time) = metrics.average_transition_time() {
261        println!("  Average transition time: {:?}", avg_time);
262    }
263
264    println!("  State visit counts:");
265    for (state, count) in &metrics.state_visit_counts {
266        println!("    {}: {}", state, count);
267    }
268}
269
270/// Example 5: With guard priorities (requires 'guards' feature)
271#[cfg(feature = "guards")]
272fn guards_example() {
273    println!("\n=== Guard Priorities Example ===");
274
275    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
276
277    // Multiple transitions with different priorities
278    builder
279        .external_transition()
280        .from(OrderState::PaymentReceived)
281        .to(OrderState::Processing)
282        .on(OrderEvent::Process)
283        .when(|_s, _e, ctx| ctx.amount < 100.0)
284        .with_priority(10)
285        .perform(|_s, _e, ctx| {
286            println!(
287                "Processing small order {} (amount: {})",
288                ctx.order_id, ctx.amount
289            );
290        });
291
292    builder
293        .external_transition()
294        .from(OrderState::PaymentReceived)
295        .to(OrderState::Processing)
296        .on(OrderEvent::Process)
297        .when(|_s, _e, ctx| ctx.amount >= 100.0 && ctx.amount < 1000.0)
298        .with_priority(20)
299        .perform(|_s, _e, ctx| {
300            println!(
301                "Processing medium order {} (amount: {})",
302                ctx.order_id, ctx.amount
303            );
304        });
305
306    builder
307        .external_transition()
308        .from(OrderState::PaymentReceived)
309        .to(OrderState::Processing)
310        .on(OrderEvent::Process)
311        .when(|_s, _e, ctx| ctx.amount >= 1000.0)
312        .with_priority(30)
313        .perform(|_s, _e, ctx| {
314            println!(
315                "Processing large order {} (amount: {}) - Priority handling!",
316                ctx.order_id, ctx.amount
317            );
318        });
319
320    let state_machine = builder.id("GuardsOrderMachine").build();
321
322    // Test with different order amounts
323    let contexts = vec![
324        OrderContext {
325            order_id: "ORD-SMALL".to_string(),
326            amount: 50.0,
327            customer_id: "C1".to_string(),
328        },
329        OrderContext {
330            order_id: "ORD-MEDIUM".to_string(),
331            amount: 500.0,
332            customer_id: "C2".to_string(),
333        },
334        OrderContext {
335            order_id: "ORD-LARGE".to_string(),
336            amount: 5000.0,
337            customer_id: "C3".to_string(),
338        },
339    ];
340
341    for context in contexts {
342        let _ = state_machine.fire_event(OrderState::PaymentReceived, OrderEvent::Process, context);
343    }
344}
345
346/// Example 6: With visualization (requires 'visualization' feature)
347#[cfg(feature = "visualization")]
348fn visualization_example() {
349    println!("\n=== Visualization Example ===");
350
351    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
352
353    // Build a complete order flow
354    builder
355        .external_transition()
356        .from(OrderState::New)
357        .to(OrderState::PaymentPending)
358        .on(OrderEvent::Pay)
359        .perform(|_s, _e, _c| {});
360
361    builder
362        .external_transition()
363        .from(OrderState::PaymentPending)
364        .to(OrderState::PaymentReceived)
365        .on(OrderEvent::ConfirmPayment)
366        .perform(|_s, _e, _c| {});
367
368    builder
369        .external_transition()
370        .from(OrderState::PaymentReceived)
371        .to(OrderState::Processing)
372        .on(OrderEvent::Process)
373        .perform(|_s, _e, _c| {});
374
375    builder
376        .external_transition()
377        .from(OrderState::Processing)
378        .to(OrderState::Shipped)
379        .on(OrderEvent::Ship)
380        .perform(|_s, _e, _c| {});
381
382    builder
383        .external_transition()
384        .from(OrderState::Shipped)
385        .to(OrderState::Delivered)
386        .on(OrderEvent::Deliver)
387        .perform(|_s, _e, _c| {});
388
389    builder
390        .external_transitions()
391        .from_among(vec![
392            OrderState::New,
393            OrderState::PaymentPending,
394            OrderState::Processing,
395        ])
396        .to(OrderState::Cancelled)
397        .on(OrderEvent::Cancel)
398        .perform(|_s, _e, _c| {});
399
400    builder
401        .external_transition()
402        .from(OrderState::Cancelled)
403        .to(OrderState::Refunded)
404        .on(OrderEvent::Refund)
405        .perform(|_s, _e, _c| {});
406
407    let state_machine = builder.id("VisualOrderMachine").build();
408
409    println!("DOT Format:");
410    println!("{}", state_machine.to_dot());
411
412    println!("\nPlantUML Format:");
413    println!("{}", state_machine.to_plantuml());
414}
415
416/// Example 7: With parallel regions (requires 'parallel' feature)
417#[cfg(feature = "parallel")]
418fn parallel_example() {
419    println!("\n=== Parallel Regions Example ===");
420
421    // Order processing region
422    let mut order_builder =
423        StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
424    order_builder
425        .external_transition()
426        .from(OrderState::New)
427        .to(OrderState::Processing)
428        .on(OrderEvent::Process)
429        .perform(|_s, _e, ctx| {
430            println!("Order region: Processing order {}", ctx.order_id);
431        });
432
433    // Payment processing region (using same states/events for simplicity)
434    let mut payment_builder =
435        StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
436    payment_builder
437        .external_transition()
438        .from(OrderState::PaymentPending)
439        .to(OrderState::PaymentReceived)
440        .on(OrderEvent::ConfirmPayment)
441        .perform(|_s, _e, ctx| {
442            println!(
443                "Payment region: Payment confirmed for order {}",
444                ctx.order_id
445            );
446        });
447
448    let mut parallel_machine = ParallelStateMachine::new();
449    parallel_machine.add_region(order_builder.id("OrderRegion").build());
450    parallel_machine.add_region(payment_builder.id("PaymentRegion").build());
451
452    let context = OrderContext {
453        order_id: "ORD-PARALLEL".to_string(),
454        amount: 199.99,
455        customer_id: "CUST-P1".to_string(),
456    };
457
458    // Fire events in parallel regions
459    println!("Firing Process event in parallel regions:");
460    let results = parallel_machine.fire_event(
461        vec![OrderState::New, OrderState::PaymentPending],
462        OrderEvent::Process,
463        context.clone(),
464    );
465
466    for (i, result) in results.iter().enumerate() {
467        println!("  Region {}: {:?}", i, result);
468    }
469
470    println!("Firing ConfirmPayment event in parallel regions:");
471    let results = parallel_machine.fire_event(
472        vec![OrderState::Processing, OrderState::PaymentPending],
473        OrderEvent::ConfirmPayment,
474        context,
475    );
476
477    for (i, result) in results.iter().enumerate() {
478        println!("  Region {}: {:?}", i, result);
479    }
480}
481
482/// Example 8: Complete example with multiple features
483#[cfg(all(feature = "history", feature = "metrics", feature = "extended"))]
484fn complete_example() {
485    println!("\n=== Complete Example with Multiple Features ===");
486
487    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
488
489    // Configure entry/exit actions
490    builder
491        .with_entry_action(OrderState::Processing, |_s, ctx| {
492            println!("[ENTRY] Starting to process order {}", ctx.order_id);
493        })
494        .with_exit_action(OrderState::Processing, |_s, ctx| {
495            println!("[EXIT] Finished processing order {}", ctx.order_id);
496        });
497
498    // Build transitions
499    builder
500        .external_transition()
501        .from(OrderState::New)
502        .to(OrderState::PaymentPending)
503        .on(OrderEvent::Pay)
504        .perform(|_s, _e, ctx| {
505            println!("Payment initiated for ${}", ctx.amount);
506        });
507
508    builder
509        .external_transition()
510        .from(OrderState::PaymentPending)
511        .to(OrderState::PaymentReceived)
512        .on(OrderEvent::ConfirmPayment)
513        .when(|_s, _e, ctx| ctx.amount > 0.0)
514        .perform(|_s, _e, ctx| {
515            println!("Payment confirmed: ${}", ctx.amount);
516        });
517
518    builder
519        .external_transition()
520        .from(OrderState::PaymentReceived)
521        .to(OrderState::Processing)
522        .on(OrderEvent::Process)
523        .perform(|_s, _e, _c| {});
524
525    builder
526        .external_transition()
527        .from(OrderState::Processing)
528        .to(OrderState::Shipped)
529        .on(OrderEvent::Ship)
530        .perform(|_s, _e, ctx| {
531            println!("Order {} shipped", ctx.order_id);
532        });
533
534    builder.set_fail_callback(Arc::new(|state, event, ctx| {
535        println!(
536            "FAILED: Cannot handle {:?} in state {:?} for order {}",
537            event, state, ctx.order_id
538        );
539    }));
540
541    let state_machine = builder.id("CompleteOrderMachine").build();
542
543    // Process an order through the complete flow
544    let context = OrderContext {
545        order_id: "ORD-COMPLETE".to_string(),
546        amount: 999.99,
547        customer_id: "CUST-VIP".to_string(),
548    };
549
550    println!("\nProcessing order through complete flow:");
551    let states = [
552        (OrderState::New, OrderEvent::Pay),
553        (OrderState::PaymentPending, OrderEvent::ConfirmPayment),
554        (OrderState::PaymentReceived, OrderEvent::Process),
555        (OrderState::Processing, OrderEvent::Ship),
556    ];
557
558    for (state, event) in &states {
559        let result = state_machine.fire_event(state.clone(), event.clone(), context.clone());
560        println!("  {:?} + {:?} = {:?}", state, event, result);
561    }
562
563    // Try an invalid transition
564    println!("\nTrying invalid transition:");
565    let _ = state_machine.fire_event(OrderState::Shipped, OrderEvent::Pay, context);
566
567    // Display collected data
568    println!("\nHistory:");
569    for record in state_machine.get_history() {
570        println!(
571            "  {:?} -> {:?} (success: {})",
572            record.from, record.to, record.success
573        );
574    }
575
576    println!("\nMetrics:");
577    let metrics = state_machine.get_metrics();
578    println!(
579        "  Total: {}, Success: {}, Failed: {}",
580        metrics.total_transitions, metrics.successful_transitions, metrics.failed_transitions
581    );
582}
Source

pub fn clear_history(&self)

Clear transition history

Source

pub fn get_metrics(&self) -> StateMachineMetrics

Get metrics

Examples found in repository?
examples/traffic_light_example.rs (line 388)
384fn demonstrate_metrics(
385    state_machine: &StateMachine<TrafficLightState, TrafficLightEvent, TrafficContext>,
386) {
387    println!("--- Performance Metrics ---");
388    let metrics = state_machine.get_metrics();
389    println!("  Total transitions: {}", metrics.total_transitions);
390    println!("  Success rate: {:.1}%", metrics.success_rate() * 100.0);
391    if let Some(avg_time) = metrics.average_transition_time() {
392        println!("  Average transition time: {:?}", avg_time);
393    }
394    println!("  State visits:");
395    for (state, count) in &metrics.state_visit_counts {
396        println!("    {}: {} times", state, count);
397    }
398    println!();
399}
More examples
Hide additional examples
examples/order_example.rs (line 253)
194fn metrics_example() {
195    println!("\n=== Metrics Collection Example ===");
196
197    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
198
199    // Add multiple transitions
200    builder
201        .external_transition()
202        .from(OrderState::New)
203        .to(OrderState::PaymentPending)
204        .on(OrderEvent::Pay)
205        .perform(|_s, _e, _c| {});
206
207    builder
208        .external_transition()
209        .from(OrderState::PaymentPending)
210        .to(OrderState::PaymentReceived)
211        .on(OrderEvent::ConfirmPayment)
212        .when(|_s, _e, ctx| ctx.amount > 0.0)
213        .perform(|_s, _e, _c| {});
214
215    builder
216        .external_transitions()
217        .from_among(vec![
218            OrderState::New,
219            OrderState::PaymentPending,
220            OrderState::Processing,
221        ])
222        .to(OrderState::Cancelled)
223        .on(OrderEvent::Cancel)
224        .perform(|_s, _e, _c| {});
225
226    let state_machine = builder.id("MetricsOrderMachine").build();
227
228    // Simulate multiple orders
229    for i in 0..10 {
230        let context = OrderContext {
231            order_id: format!("ORD-{:03}", i),
232            amount: (i as f64) * 10.0,
233            customer_id: format!("CUST-{:03}", i),
234        };
235
236        let _ = state_machine.fire_event(OrderState::New, OrderEvent::Pay, context.clone());
237
238        if i % 3 == 0 {
239            // Some orders get cancelled
240            let _ =
241                state_machine.fire_event(OrderState::PaymentPending, OrderEvent::Cancel, context);
242        } else {
243            // Others proceed normally
244            let _ = state_machine.fire_event(
245                OrderState::PaymentPending,
246                OrderEvent::ConfirmPayment,
247                context,
248            );
249        }
250    }
251
252    // Get and display metrics
253    let metrics = state_machine.get_metrics();
254    println!("State Machine Metrics:");
255    println!("  Total transitions: {}", metrics.total_transitions);
256    println!("  Successful: {}", metrics.successful_transitions);
257    println!("  Failed: {}", metrics.failed_transitions);
258    println!("  Success rate: {:.2}%", metrics.success_rate() * 100.0);
259
260    if let Some(avg_time) = metrics.average_transition_time() {
261        println!("  Average transition time: {:?}", avg_time);
262    }
263
264    println!("  State visit counts:");
265    for (state, count) in &metrics.state_visit_counts {
266        println!("    {}: {}", state, count);
267    }
268}
269
270/// Example 5: With guard priorities (requires 'guards' feature)
271#[cfg(feature = "guards")]
272fn guards_example() {
273    println!("\n=== Guard Priorities Example ===");
274
275    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
276
277    // Multiple transitions with different priorities
278    builder
279        .external_transition()
280        .from(OrderState::PaymentReceived)
281        .to(OrderState::Processing)
282        .on(OrderEvent::Process)
283        .when(|_s, _e, ctx| ctx.amount < 100.0)
284        .with_priority(10)
285        .perform(|_s, _e, ctx| {
286            println!(
287                "Processing small order {} (amount: {})",
288                ctx.order_id, ctx.amount
289            );
290        });
291
292    builder
293        .external_transition()
294        .from(OrderState::PaymentReceived)
295        .to(OrderState::Processing)
296        .on(OrderEvent::Process)
297        .when(|_s, _e, ctx| ctx.amount >= 100.0 && ctx.amount < 1000.0)
298        .with_priority(20)
299        .perform(|_s, _e, ctx| {
300            println!(
301                "Processing medium order {} (amount: {})",
302                ctx.order_id, ctx.amount
303            );
304        });
305
306    builder
307        .external_transition()
308        .from(OrderState::PaymentReceived)
309        .to(OrderState::Processing)
310        .on(OrderEvent::Process)
311        .when(|_s, _e, ctx| ctx.amount >= 1000.0)
312        .with_priority(30)
313        .perform(|_s, _e, ctx| {
314            println!(
315                "Processing large order {} (amount: {}) - Priority handling!",
316                ctx.order_id, ctx.amount
317            );
318        });
319
320    let state_machine = builder.id("GuardsOrderMachine").build();
321
322    // Test with different order amounts
323    let contexts = vec![
324        OrderContext {
325            order_id: "ORD-SMALL".to_string(),
326            amount: 50.0,
327            customer_id: "C1".to_string(),
328        },
329        OrderContext {
330            order_id: "ORD-MEDIUM".to_string(),
331            amount: 500.0,
332            customer_id: "C2".to_string(),
333        },
334        OrderContext {
335            order_id: "ORD-LARGE".to_string(),
336            amount: 5000.0,
337            customer_id: "C3".to_string(),
338        },
339    ];
340
341    for context in contexts {
342        let _ = state_machine.fire_event(OrderState::PaymentReceived, OrderEvent::Process, context);
343    }
344}
345
346/// Example 6: With visualization (requires 'visualization' feature)
347#[cfg(feature = "visualization")]
348fn visualization_example() {
349    println!("\n=== Visualization Example ===");
350
351    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
352
353    // Build a complete order flow
354    builder
355        .external_transition()
356        .from(OrderState::New)
357        .to(OrderState::PaymentPending)
358        .on(OrderEvent::Pay)
359        .perform(|_s, _e, _c| {});
360
361    builder
362        .external_transition()
363        .from(OrderState::PaymentPending)
364        .to(OrderState::PaymentReceived)
365        .on(OrderEvent::ConfirmPayment)
366        .perform(|_s, _e, _c| {});
367
368    builder
369        .external_transition()
370        .from(OrderState::PaymentReceived)
371        .to(OrderState::Processing)
372        .on(OrderEvent::Process)
373        .perform(|_s, _e, _c| {});
374
375    builder
376        .external_transition()
377        .from(OrderState::Processing)
378        .to(OrderState::Shipped)
379        .on(OrderEvent::Ship)
380        .perform(|_s, _e, _c| {});
381
382    builder
383        .external_transition()
384        .from(OrderState::Shipped)
385        .to(OrderState::Delivered)
386        .on(OrderEvent::Deliver)
387        .perform(|_s, _e, _c| {});
388
389    builder
390        .external_transitions()
391        .from_among(vec![
392            OrderState::New,
393            OrderState::PaymentPending,
394            OrderState::Processing,
395        ])
396        .to(OrderState::Cancelled)
397        .on(OrderEvent::Cancel)
398        .perform(|_s, _e, _c| {});
399
400    builder
401        .external_transition()
402        .from(OrderState::Cancelled)
403        .to(OrderState::Refunded)
404        .on(OrderEvent::Refund)
405        .perform(|_s, _e, _c| {});
406
407    let state_machine = builder.id("VisualOrderMachine").build();
408
409    println!("DOT Format:");
410    println!("{}", state_machine.to_dot());
411
412    println!("\nPlantUML Format:");
413    println!("{}", state_machine.to_plantuml());
414}
415
416/// Example 7: With parallel regions (requires 'parallel' feature)
417#[cfg(feature = "parallel")]
418fn parallel_example() {
419    println!("\n=== Parallel Regions Example ===");
420
421    // Order processing region
422    let mut order_builder =
423        StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
424    order_builder
425        .external_transition()
426        .from(OrderState::New)
427        .to(OrderState::Processing)
428        .on(OrderEvent::Process)
429        .perform(|_s, _e, ctx| {
430            println!("Order region: Processing order {}", ctx.order_id);
431        });
432
433    // Payment processing region (using same states/events for simplicity)
434    let mut payment_builder =
435        StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
436    payment_builder
437        .external_transition()
438        .from(OrderState::PaymentPending)
439        .to(OrderState::PaymentReceived)
440        .on(OrderEvent::ConfirmPayment)
441        .perform(|_s, _e, ctx| {
442            println!(
443                "Payment region: Payment confirmed for order {}",
444                ctx.order_id
445            );
446        });
447
448    let mut parallel_machine = ParallelStateMachine::new();
449    parallel_machine.add_region(order_builder.id("OrderRegion").build());
450    parallel_machine.add_region(payment_builder.id("PaymentRegion").build());
451
452    let context = OrderContext {
453        order_id: "ORD-PARALLEL".to_string(),
454        amount: 199.99,
455        customer_id: "CUST-P1".to_string(),
456    };
457
458    // Fire events in parallel regions
459    println!("Firing Process event in parallel regions:");
460    let results = parallel_machine.fire_event(
461        vec![OrderState::New, OrderState::PaymentPending],
462        OrderEvent::Process,
463        context.clone(),
464    );
465
466    for (i, result) in results.iter().enumerate() {
467        println!("  Region {}: {:?}", i, result);
468    }
469
470    println!("Firing ConfirmPayment event in parallel regions:");
471    let results = parallel_machine.fire_event(
472        vec![OrderState::Processing, OrderState::PaymentPending],
473        OrderEvent::ConfirmPayment,
474        context,
475    );
476
477    for (i, result) in results.iter().enumerate() {
478        println!("  Region {}: {:?}", i, result);
479    }
480}
481
482/// Example 8: Complete example with multiple features
483#[cfg(all(feature = "history", feature = "metrics", feature = "extended"))]
484fn complete_example() {
485    println!("\n=== Complete Example with Multiple Features ===");
486
487    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
488
489    // Configure entry/exit actions
490    builder
491        .with_entry_action(OrderState::Processing, |_s, ctx| {
492            println!("[ENTRY] Starting to process order {}", ctx.order_id);
493        })
494        .with_exit_action(OrderState::Processing, |_s, ctx| {
495            println!("[EXIT] Finished processing order {}", ctx.order_id);
496        });
497
498    // Build transitions
499    builder
500        .external_transition()
501        .from(OrderState::New)
502        .to(OrderState::PaymentPending)
503        .on(OrderEvent::Pay)
504        .perform(|_s, _e, ctx| {
505            println!("Payment initiated for ${}", ctx.amount);
506        });
507
508    builder
509        .external_transition()
510        .from(OrderState::PaymentPending)
511        .to(OrderState::PaymentReceived)
512        .on(OrderEvent::ConfirmPayment)
513        .when(|_s, _e, ctx| ctx.amount > 0.0)
514        .perform(|_s, _e, ctx| {
515            println!("Payment confirmed: ${}", ctx.amount);
516        });
517
518    builder
519        .external_transition()
520        .from(OrderState::PaymentReceived)
521        .to(OrderState::Processing)
522        .on(OrderEvent::Process)
523        .perform(|_s, _e, _c| {});
524
525    builder
526        .external_transition()
527        .from(OrderState::Processing)
528        .to(OrderState::Shipped)
529        .on(OrderEvent::Ship)
530        .perform(|_s, _e, ctx| {
531            println!("Order {} shipped", ctx.order_id);
532        });
533
534    builder.set_fail_callback(Arc::new(|state, event, ctx| {
535        println!(
536            "FAILED: Cannot handle {:?} in state {:?} for order {}",
537            event, state, ctx.order_id
538        );
539    }));
540
541    let state_machine = builder.id("CompleteOrderMachine").build();
542
543    // Process an order through the complete flow
544    let context = OrderContext {
545        order_id: "ORD-COMPLETE".to_string(),
546        amount: 999.99,
547        customer_id: "CUST-VIP".to_string(),
548    };
549
550    println!("\nProcessing order through complete flow:");
551    let states = [
552        (OrderState::New, OrderEvent::Pay),
553        (OrderState::PaymentPending, OrderEvent::ConfirmPayment),
554        (OrderState::PaymentReceived, OrderEvent::Process),
555        (OrderState::Processing, OrderEvent::Ship),
556    ];
557
558    for (state, event) in &states {
559        let result = state_machine.fire_event(state.clone(), event.clone(), context.clone());
560        println!("  {:?} + {:?} = {:?}", state, event, result);
561    }
562
563    // Try an invalid transition
564    println!("\nTrying invalid transition:");
565    let _ = state_machine.fire_event(OrderState::Shipped, OrderEvent::Pay, context);
566
567    // Display collected data
568    println!("\nHistory:");
569    for record in state_machine.get_history() {
570        println!(
571            "  {:?} -> {:?} (success: {})",
572            record.from, record.to, record.success
573        );
574    }
575
576    println!("\nMetrics:");
577    let metrics = state_machine.get_metrics();
578    println!(
579        "  Total: {}, Success: {}, Failed: {}",
580        metrics.total_transitions, metrics.successful_transitions, metrics.failed_transitions
581    );
582}
Source

pub fn add_entry_action<F>(&mut self, state: S, action: F)
where F: Fn(&S, &C) + Send + Sync + 'static,

Add entry action for a state

Source

pub fn add_exit_action<F>(&mut self, state: S, action: F)
where F: Fn(&S, &C) + Send + Sync + 'static,

Add exit action for a state

Source

pub fn set_state_timeout( &mut self, state: S, duration: Duration, target_state: S, timeout_event: E, )

Set timeout for a state

Source

pub fn to_dot(&self) -> String

Export to DOT format

Examples found in repository?
examples/traffic_light_example.rs (line 408)
402fn demonstrate_visualization(
403    state_machine: &StateMachine<TrafficLightState, TrafficLightEvent, TrafficContext>,
404) {
405    println!("--- State Machine Visualization ---");
406    println!("Saving to 'traffic_light.dot' and 'traffic_light.puml'");
407
408    let dot = state_machine.to_dot();
409    let plantuml = state_machine.to_plantuml();
410
411    // In a real application, you would write these to files
412    if let Err(e) = std::fs::write("traffic_light.dot", dot) {
413        eprintln!("Failed to write DOT file: {}", e);
414    }
415
416    if let Err(e) = std::fs::write("traffic_light.puml", plantuml) {
417        eprintln!("Failed to write PlantUML file: {}", e);
418    }
419
420    println!("  ✓ Visualization files created\n");
421}
More examples
Hide additional examples
examples/order_example.rs (line 410)
348fn visualization_example() {
349    println!("\n=== Visualization Example ===");
350
351    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
352
353    // Build a complete order flow
354    builder
355        .external_transition()
356        .from(OrderState::New)
357        .to(OrderState::PaymentPending)
358        .on(OrderEvent::Pay)
359        .perform(|_s, _e, _c| {});
360
361    builder
362        .external_transition()
363        .from(OrderState::PaymentPending)
364        .to(OrderState::PaymentReceived)
365        .on(OrderEvent::ConfirmPayment)
366        .perform(|_s, _e, _c| {});
367
368    builder
369        .external_transition()
370        .from(OrderState::PaymentReceived)
371        .to(OrderState::Processing)
372        .on(OrderEvent::Process)
373        .perform(|_s, _e, _c| {});
374
375    builder
376        .external_transition()
377        .from(OrderState::Processing)
378        .to(OrderState::Shipped)
379        .on(OrderEvent::Ship)
380        .perform(|_s, _e, _c| {});
381
382    builder
383        .external_transition()
384        .from(OrderState::Shipped)
385        .to(OrderState::Delivered)
386        .on(OrderEvent::Deliver)
387        .perform(|_s, _e, _c| {});
388
389    builder
390        .external_transitions()
391        .from_among(vec![
392            OrderState::New,
393            OrderState::PaymentPending,
394            OrderState::Processing,
395        ])
396        .to(OrderState::Cancelled)
397        .on(OrderEvent::Cancel)
398        .perform(|_s, _e, _c| {});
399
400    builder
401        .external_transition()
402        .from(OrderState::Cancelled)
403        .to(OrderState::Refunded)
404        .on(OrderEvent::Refund)
405        .perform(|_s, _e, _c| {});
406
407    let state_machine = builder.id("VisualOrderMachine").build();
408
409    println!("DOT Format:");
410    println!("{}", state_machine.to_dot());
411
412    println!("\nPlantUML Format:");
413    println!("{}", state_machine.to_plantuml());
414}
Source

pub fn to_plantuml(&self) -> String

Export to PlantUML format

Examples found in repository?
examples/traffic_light_example.rs (line 409)
402fn demonstrate_visualization(
403    state_machine: &StateMachine<TrafficLightState, TrafficLightEvent, TrafficContext>,
404) {
405    println!("--- State Machine Visualization ---");
406    println!("Saving to 'traffic_light.dot' and 'traffic_light.puml'");
407
408    let dot = state_machine.to_dot();
409    let plantuml = state_machine.to_plantuml();
410
411    // In a real application, you would write these to files
412    if let Err(e) = std::fs::write("traffic_light.dot", dot) {
413        eprintln!("Failed to write DOT file: {}", e);
414    }
415
416    if let Err(e) = std::fs::write("traffic_light.puml", plantuml) {
417        eprintln!("Failed to write PlantUML file: {}", e);
418    }
419
420    println!("  ✓ Visualization files created\n");
421}
More examples
Hide additional examples
examples/order_example.rs (line 413)
348fn visualization_example() {
349    println!("\n=== Visualization Example ===");
350
351    let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
352
353    // Build a complete order flow
354    builder
355        .external_transition()
356        .from(OrderState::New)
357        .to(OrderState::PaymentPending)
358        .on(OrderEvent::Pay)
359        .perform(|_s, _e, _c| {});
360
361    builder
362        .external_transition()
363        .from(OrderState::PaymentPending)
364        .to(OrderState::PaymentReceived)
365        .on(OrderEvent::ConfirmPayment)
366        .perform(|_s, _e, _c| {});
367
368    builder
369        .external_transition()
370        .from(OrderState::PaymentReceived)
371        .to(OrderState::Processing)
372        .on(OrderEvent::Process)
373        .perform(|_s, _e, _c| {});
374
375    builder
376        .external_transition()
377        .from(OrderState::Processing)
378        .to(OrderState::Shipped)
379        .on(OrderEvent::Ship)
380        .perform(|_s, _e, _c| {});
381
382    builder
383        .external_transition()
384        .from(OrderState::Shipped)
385        .to(OrderState::Delivered)
386        .on(OrderEvent::Deliver)
387        .perform(|_s, _e, _c| {});
388
389    builder
390        .external_transitions()
391        .from_among(vec![
392            OrderState::New,
393            OrderState::PaymentPending,
394            OrderState::Processing,
395        ])
396        .to(OrderState::Cancelled)
397        .on(OrderEvent::Cancel)
398        .perform(|_s, _e, _c| {});
399
400    builder
401        .external_transition()
402        .from(OrderState::Cancelled)
403        .to(OrderState::Refunded)
404        .on(OrderEvent::Refund)
405        .perform(|_s, _e, _c| {});
406
407    let state_machine = builder.id("VisualOrderMachine").build();
408
409    println!("DOT Format:");
410    println!("{}", state_machine.to_dot());
411
412    println!("\nPlantUML Format:");
413    println!("{}", state_machine.to_plantuml());
414}
Source§

impl<S, E, C> StateMachine<S, E, C>
where S: State + Send + Sync, E: Event + Send + Sync, C: Context + Send + Sync,

Source

pub async fn fire_event_async( &self, from: S, event: E, context: C, ) -> Result<S, TransitionError>

Fire an event asynchronously

Auto Trait Implementations§

§

impl<S, E, C> Freeze for StateMachine<S, E, C>

§

impl<S, E, C> !RefUnwindSafe for StateMachine<S, E, C>

§

impl<S, E, C> Send for StateMachine<S, E, C>
where S: Send, E: Send,

§

impl<S, E, C> Sync for StateMachine<S, E, C>
where S: Sync + Send, E: Sync + Send,

§

impl<S, E, C> Unpin for StateMachine<S, E, C>
where S: Unpin, E: Unpin,

§

impl<S, E, C> !UnwindSafe for StateMachine<S, E, C>

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.