1use rs_statemachine::*;
4use std::sync::Arc;
5
6#[derive(Debug, Clone, Hash, Eq, PartialEq)]
7enum OrderState {
8 New,
9 PaymentPending,
10 PaymentReceived,
11 Processing,
12 Shipped,
13 Delivered,
14 Cancelled,
15 Refunded,
16}
17
18impl State for OrderState {}
19
20#[derive(Debug, Clone, Hash, Eq, PartialEq)]
21enum OrderEvent {
22 Pay,
23 ConfirmPayment,
24 Process,
25 Ship,
26 Deliver,
27 Cancel,
28 Refund,
29}
30
31impl Event for OrderEvent {}
32
33#[derive(Debug, Clone)]
34struct OrderContext {
35 order_id: String,
36 amount: f64,
37 customer_id: String,
38}
39
40impl Context for OrderContext {}
41
42fn 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#[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 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 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#[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#[cfg(feature = "metrics")]
194fn metrics_example() {
195 println!("\n=== Metrics Collection Example ===");
196
197 let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
198
199 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 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 let _ =
241 state_machine.fire_event(OrderState::PaymentPending, OrderEvent::Cancel, context);
242 } else {
243 let _ = state_machine.fire_event(
245 OrderState::PaymentPending,
246 OrderEvent::ConfirmPayment,
247 context,
248 );
249 }
250 }
251
252 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#[cfg(feature = "guards")]
272fn guards_example() {
273 println!("\n=== Guard Priorities Example ===");
274
275 let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
276
277 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 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#[cfg(feature = "visualization")]
348fn visualization_example() {
349 println!("\n=== Visualization Example ===");
350
351 let mut builder = StateMachineBuilderFactory::create::<OrderState, OrderEvent, OrderContext>();
352
353 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#[cfg(feature = "parallel")]
418fn parallel_example() {
419 println!("\n=== Parallel Regions Example ===");
420
421 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 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 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#[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 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 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 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 println!("\nTrying invalid transition:");
565 let _ = state_machine.fire_event(OrderState::Shipped, OrderEvent::Pay, context);
566
567 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}
583
584fn main() {
585 basic_example();
586
587 #[cfg(feature = "history")]
588 history_example();
589
590 #[cfg(feature = "extended")]
591 extended_example();
592
593 #[cfg(feature = "metrics")]
594 metrics_example();
595
596 #[cfg(feature = "guards")]
597 guards_example();
598
599 #[cfg(feature = "visualization")]
600 visualization_example();
601
602 #[cfg(feature = "parallel")]
603 parallel_example();
604
605 #[cfg(all(feature = "history", feature = "metrics", feature = "extended"))]
606 complete_example();
607}