1#![allow(clippy::print_stdout, clippy::enum_glob_use)]
8
9use ready_active_safe::prelude::*;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12enum Mode {
13 Ready,
14 Active,
15 Safe,
16}
17
18impl core::fmt::Display for Mode {
19 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
20 write!(f, "{self:?}")
21 }
22}
23
24#[derive(Debug, Clone)]
25enum Event {
26 PowerOn,
27 SensorReady,
28 BeginMeasurement,
29 DataCollected,
30 AnomalyDetected,
31 OperatorReset,
32}
33
34#[derive(Debug, Clone, PartialEq)]
35enum Command {
36 InitializeSensors,
37 StartDataAcquisition,
38 StoreReading,
39 TriggerAlarm,
40 ClearAlarm,
41 RecalibrateSensors,
42}
43
44struct LabInstrument;
45
46impl Machine for LabInstrument {
47 type Mode = Mode;
48 type Event = Event;
49 type Command = Command;
50
51 fn initial_mode(&self) -> Mode {
52 Mode::Ready
53 }
54
55 fn on_event(
56 &self,
57 mode: &Self::Mode,
58 event: &Self::Event,
59 ) -> Decision<Self::Mode, Self::Command> {
60 use Command::*;
61 use Event::*;
62 use Mode::*;
63
64 match (mode, event) {
65 (Ready, PowerOn) => stay().emit(InitializeSensors),
66 (Ready, BeginMeasurement) => transition(Active).emit(StartDataAcquisition),
67 (Active, DataCollected) => stay().emit(StoreReading),
68 (Active, AnomalyDetected) => transition(Safe).emit(TriggerAlarm),
69 (Safe, OperatorReset) => transition(Ready).emit_all([ClearAlarm, RecalibrateSensors]),
70 _ => ignore(),
71 }
72 }
73}
74
75fn main() {
76 let instrument = LabInstrument;
77 let mut runner = Runner::new(&instrument);
78
79 let events = [
80 Event::PowerOn,
81 Event::SensorReady,
82 Event::BeginMeasurement,
83 Event::DataCollected,
84 Event::DataCollected,
85 Event::AnomalyDetected,
86 Event::OperatorReset,
87 Event::BeginMeasurement,
88 ];
89
90 let mut journal: InMemoryJournal<Mode, Event, Command> = InMemoryJournal::new();
92
93 println!("--- Recording transitions ---\n");
94 for event in events {
95 let from = runner.mode().clone();
96 let commands = runner.feed(&event);
97 let to = runner.mode().clone();
98
99 println!(" {from:?} + {event:?} => {to:?}");
100 if !commands.is_empty() {
101 println!(" commands: {commands:?}");
102 }
103
104 journal.record_step(&from, &to, &event, &commands);
105 }
106
107 println!("\n--- Journal: {} records ---\n", journal.len());
108 for record in journal.records() {
109 println!(
110 " step {}: {:?} => {:?} (via {:?})",
111 record.step, record.from, record.to, record.event,
112 );
113 }
114
115 println!("\n--- Replaying ---\n");
117 match journal.replay(&instrument, instrument.initial_mode()) {
118 Ok(final_mode) => {
119 println!(" replay verified: final mode = {final_mode:?}");
120 assert_eq!(final_mode, runner.mode().clone());
121 }
122 Err(err) => {
123 println!(" {err}");
124 }
125 }
126}