1use rs_statemachine::*;
7use std::sync::Arc;
8
9#[derive(Debug, Clone, Hash, Eq, PartialEq)]
10enum TrafficLightState {
11 Red,
12 Yellow,
13 Green,
14 FlashingYellow, Emergency, }
17
18impl State for TrafficLightState {}
19
20#[derive(Debug, Clone, Hash, Eq, PartialEq)]
21enum TrafficLightEvent {
22 Timer,
23 EmergencyVehicleDetected,
24 EmergencyCleared,
25 MaintenanceMode,
26 NormalMode,
27 PedestrianRequest,
28}
29
30impl Event for TrafficLightEvent {}
31
32#[derive(Debug, Clone)]
33struct TrafficContext {
34 intersection_id: String,
35 traffic_density: f32, pedestrian_waiting: bool,
37 emergency_active: bool,
38 time_in_state: std::time::Duration,
39}
40
41impl Context for TrafficContext {}
42
43pub fn build_traffic_light_system(
45) -> StateMachine<TrafficLightState, TrafficLightEvent, TrafficContext> {
46 let mut builder =
47 StateMachineBuilderFactory::create::<TrafficLightState, TrafficLightEvent, TrafficContext>(
48 );
49
50 configure_basic_transitions(&mut builder);
52
53 #[cfg(feature = "extended")]
54 configure_entry_exit_actions(&mut builder);
55
56 #[cfg(feature = "guards")]
57 configure_priority_transitions(&mut builder);
58
59 #[cfg(feature = "timeout")]
60 configure_timeouts(&mut builder);
61
62 builder.set_fail_callback(Arc::new(|state, event, ctx| {
63 eprintln!(
64 "WARNING: Invalid transition from {:?} with {:?} at intersection {}",
65 state, event, ctx.intersection_id
66 );
67 }));
68 builder.id("TrafficLightController").build()
69}
70
71fn configure_basic_transitions<'a>(
73 builder: &'a mut StateMachineBuilder<TrafficLightState, TrafficLightEvent, TrafficContext>,
74) -> &'a mut StateMachineBuilder<TrafficLightState, TrafficLightEvent, TrafficContext> {
75 builder
77 .external_transition()
78 .from(TrafficLightState::Green)
79 .to(TrafficLightState::Yellow)
80 .on(TrafficLightEvent::Timer)
81 .perform(|_s, _e, ctx| {
82 println!("[{}] Changing to YELLOW", ctx.intersection_id);
83 });
84
85 builder
86 .external_transition()
87 .from(TrafficLightState::Yellow)
88 .to(TrafficLightState::Red)
89 .on(TrafficLightEvent::Timer)
90 .perform(|_s, _e, ctx| {
91 println!("[{}] Changing to RED", ctx.intersection_id);
92 });
93
94 builder
95 .external_transition()
96 .from(TrafficLightState::Red)
97 .to(TrafficLightState::Green)
98 .on(TrafficLightEvent::Timer)
99 .when(|_s, _e, ctx| !ctx.emergency_active)
100 .perform(|_s, _e, ctx| {
101 println!("[{}] Changing to GREEN", ctx.intersection_id);
102 });
103
104 builder
106 .external_transitions()
107 .from_among(vec![
108 TrafficLightState::Green,
109 TrafficLightState::Yellow,
110 TrafficLightState::Red,
111 ])
112 .to(TrafficLightState::Emergency)
113 .on(TrafficLightEvent::EmergencyVehicleDetected)
114 .perform(|from, _e, ctx| {
115 println!(
116 "[{}] EMERGENCY MODE! Was in {:?}",
117 ctx.intersection_id, from
118 );
119 });
120
121 builder
122 .external_transition()
123 .from(TrafficLightState::Emergency)
124 .to(TrafficLightState::Red)
125 .on(TrafficLightEvent::EmergencyCleared)
126 .perform(|_s, _e, ctx| {
127 println!(
128 "[{}] Emergency cleared, returning to RED",
129 ctx.intersection_id
130 );
131 });
132
133 builder
135 .external_transitions()
136 .from_among(vec![
137 TrafficLightState::Green,
138 TrafficLightState::Yellow,
139 TrafficLightState::Red,
140 ])
141 .to(TrafficLightState::FlashingYellow)
142 .on(TrafficLightEvent::MaintenanceMode)
143 .perform(|_s, _e, ctx| {
144 println!(
145 "[{}] Entering maintenance mode - FLASHING YELLOW",
146 ctx.intersection_id
147 );
148 });
149
150 builder
151 .external_transition()
152 .from(TrafficLightState::FlashingYellow)
153 .to(TrafficLightState::Red)
154 .on(TrafficLightEvent::NormalMode)
155 .perform(|_s, _e, ctx| {
156 println!("[{}] Exiting maintenance mode", ctx.intersection_id);
157 });
158
159 builder
160}
161
162#[cfg(feature = "extended")]
164fn configure_entry_exit_actions(
165 builder: &mut StateMachineBuilder<TrafficLightState, TrafficLightEvent, TrafficContext>,
166) {
167 builder.with_entry_action(TrafficLightState::Green, |_state, ctx| {
169 println!(
170 "[{}] GREEN light ON - Vehicles may proceed",
171 ctx.intersection_id
172 );
173 });
175
176 builder.with_entry_action(TrafficLightState::Yellow, |_state, ctx| {
177 println!(
178 "[{}] YELLOW light ON - Prepare to stop",
179 ctx.intersection_id
180 );
181 });
182
183 builder.with_entry_action(TrafficLightState::Red, |_state, ctx| {
184 println!(
185 "[{}] RED light ON - Vehicles must stop",
186 ctx.intersection_id
187 );
188 if ctx.pedestrian_waiting {
189 println!(
190 "[{}] Pedestrian crossing signal activated",
191 ctx.intersection_id
192 );
193 }
194 });
195
196 builder.with_entry_action(TrafficLightState::Emergency, |_state, ctx| {
197 println!(
198 "[{}] EMERGENCY MODE - All lights RED except emergency route",
199 ctx.intersection_id
200 );
201 });
203
204 builder.with_exit_action(TrafficLightState::Green, |_state, ctx| {
206 println!("[{}] GREEN light OFF", ctx.intersection_id);
207 });
208
209 builder.with_exit_action(TrafficLightState::Emergency, |_state, ctx| {
210 println!("[{}] Exiting emergency mode", ctx.intersection_id);
211 });
212}
213
214#[cfg(feature = "guards")]
216fn configure_priority_transitions(
217 builder: &mut StateMachineBuilder<TrafficLightState, TrafficLightEvent, TrafficContext>,
218) {
219 builder
221 .external_transition()
222 .from(TrafficLightState::Green)
223 .to(TrafficLightState::Yellow)
224 .on(TrafficLightEvent::PedestrianRequest)
225 .when(|_s, _e, ctx| ctx.traffic_density < 0.3 && ctx.pedestrian_waiting)
226 .with_priority(100)
227 .perform(|_s, _e, ctx| {
228 println!(
229 "[{}] Pedestrian priority - changing to yellow",
230 ctx.intersection_id
231 );
232 });
233
234 builder
236 .external_transition()
237 .from(TrafficLightState::Green)
238 .to(TrafficLightState::Yellow)
239 .on(TrafficLightEvent::PedestrianRequest)
240 .when(|_s, _e, ctx| {
241 ctx.pedestrian_waiting && ctx.time_in_state > std::time::Duration::from_secs(10)
242 })
243 .with_priority(50)
244 .perform(|_s, _e, ctx| {
245 println!("[{}] Pedestrian request accepted", ctx.intersection_id);
246 });
247
248 builder
250 .internal_transition()
251 .within(TrafficLightState::Green)
252 .on(TrafficLightEvent::Timer)
253 .when(|_s, _e, ctx| {
254 ctx.traffic_density > 0.8 && ctx.time_in_state < std::time::Duration::from_secs(90)
255 })
256 .with_priority(200)
257 .perform(|_s, _e, ctx| {
258 println!(
259 "[{}] High traffic - extending green phase",
260 ctx.intersection_id
261 );
262 });
263}
264
265#[cfg(feature = "timeout")]
267fn configure_timeouts(
268 builder: &mut StateMachineBuilder<TrafficLightState, TrafficLightEvent, TrafficContext>,
269) {
270 use std::time::Duration;
271
272 builder.with_state_timeout(
274 TrafficLightState::Yellow,
275 Duration::from_secs(5),
276 TrafficLightState::Red,
277 TrafficLightEvent::Timer,
278 );
279
280 builder.with_state_timeout(
282 TrafficLightState::Emergency,
283 Duration::from_secs(300), TrafficLightState::Red,
285 TrafficLightEvent::EmergencyCleared,
286 );
287}
288
289pub 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 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 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 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 #[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}
363
364#[cfg(feature = "history")]
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}
382
383#[cfg(feature = "metrics")]
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}
400
401#[cfg(feature = "visualization")]
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 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}
422
423fn main() {
425 println!("Enabled features:");
427 #[cfg(feature = "history")]
428 println!(" ✓ history");
429 #[cfg(feature = "extended")]
430 println!(" ✓ extended");
431 #[cfg(feature = "metrics")]
432 println!(" ✓ metrics");
433 #[cfg(feature = "guards")]
434 println!(" ✓ guards");
435 #[cfg(feature = "timeout")]
436 println!(" ✓ timeout");
437 #[cfg(feature = "visualization")]
438 println!(" ✓ visualization");
439 println!();
440
441 simulate_traffic_light_system();
443
444 println!("--- Feature Combination Examples ---");
446
447 #[cfg(all(feature = "history", feature = "metrics"))]
448 {
449 println!("With history + metrics: Full audit trail with performance analysis");
450 }
451
452 #[cfg(all(feature = "extended", feature = "guards"))]
453 {
454 println!("With extended + guards: Complex state logic with prioritized transitions");
455 }
456
457 #[cfg(not(any(feature = "history", feature = "extended", feature = "metrics")))]
458 {
459 println!("Running with minimal features - core functionality only");
460 }
461}