pub struct StateMachine<S, E, C>{
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>
impl<S, E, C> StateMachine<S, E, C>
Sourcepub fn fire_event(
&self,
from: S,
event: E,
context: C,
) -> Result<S, TransitionError>
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
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}Sourcepub fn get_history(&self) -> Vec<TransitionRecord<S, E>>
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
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}Sourcepub fn clear_history(&self)
pub fn clear_history(&self)
Clear transition history
Sourcepub fn get_metrics(&self) -> StateMachineMetrics
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
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}Sourcepub fn add_entry_action<F>(&mut self, state: S, action: F)
pub fn add_entry_action<F>(&mut self, state: S, action: F)
Add entry action for a state
Sourcepub fn add_exit_action<F>(&mut self, state: S, action: F)
pub fn add_exit_action<F>(&mut self, state: S, action: F)
Add exit action for a state
Sourcepub fn set_state_timeout(
&mut self,
state: S,
duration: Duration,
target_state: S,
timeout_event: E,
)
pub fn set_state_timeout( &mut self, state: S, duration: Duration, target_state: S, timeout_event: E, )
Set timeout for a state
Sourcepub fn to_dot(&self) -> String
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
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}Sourcepub fn to_plantuml(&self) -> String
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
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}