1#![allow(clippy::print_stdout, clippy::enum_glob_use)]
7
8use ready_active_safe::prelude::*;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11enum Mode {
12 Ready,
13 Active,
14 Safe,
15}
16
17impl core::fmt::Display for Mode {
18 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
19 write!(f, "{self:?}")
20 }
21}
22
23#[derive(Debug)]
24enum Event {
25 Start,
26 Reset,
27 Fault,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
31enum Command {
32 Init,
33 Shutdown,
34}
35
36struct System;
37
38impl Machine for System {
39 type Mode = Mode;
40 type Event = Event;
41 type Command = Command;
42
43 fn initial_mode(&self) -> Mode {
44 Mode::Ready
45 }
46
47 fn on_event(&self, mode: &Mode, event: &Event) -> Decision<Mode, Command> {
48 use Command::*;
49 use Event::*;
50 use Mode::*;
51
52 match (mode, event) {
53 (Ready, Start) => transition(Active).emit(Init),
54 (Active, Reset) => transition(Ready),
55 (Active, Fault) => transition(Safe).emit(Shutdown),
56 _ => ignore(),
57 }
58 }
59}
60
61struct ForwardOnly;
63
64impl Policy<Mode> for ForwardOnly {
65 fn is_allowed(&self, from: &Mode, to: &Mode) -> bool {
66 matches!(
67 (from, to),
68 (Mode::Ready, Mode::Active) | (Mode::Active, Mode::Safe)
69 )
70 }
71}
72
73fn main() {
74 let system = System;
75 let policy = ForwardOnly;
76 let mut runner = Runner::new(&system);
77
78 println!("Starting in {:?}", runner.mode());
79
80 let commands = runner.feed_checked(&Event::Start, &policy);
82 println!("\nEvent: Start");
83 println!(" mode: {:?}, commands: {:?}", runner.mode(), commands);
84
85 let result = runner.feed_checked(&Event::Reset, &policy);
87 println!("\nEvent: Reset");
88 match &result {
89 Ok(cmds) => println!(" mode: {:?}, commands: {cmds:?}", runner.mode()),
90 Err(err) => println!(" denied: {err}"),
91 }
92 println!(" mode unchanged: {:?}", runner.mode());
93
94 let commands = runner.feed_checked(&Event::Fault, &policy);
96 println!("\nEvent: Fault");
97 println!(" mode: {:?}, commands: {:?}", runner.mode(), commands);
98}