#![allow(clippy::print_stdout, clippy::enum_glob_use)]
use ready_active_safe::prelude::*;
#[derive(Debug, Clone, PartialEq, Eq)]
enum Mode {
Ready,
Active,
Safe,
}
impl core::fmt::Display for Mode {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{self:?}")
}
}
#[derive(Debug)]
enum Event {
Start,
Reset,
Fault,
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum Command {
Init,
Shutdown,
}
struct System;
impl Machine for System {
type Mode = Mode;
type Event = Event;
type Command = Command;
fn initial_mode(&self) -> Mode {
Mode::Ready
}
fn on_event(&self, mode: &Mode, event: &Event) -> Decision<Mode, Command> {
use Command::*;
use Event::*;
use Mode::*;
match (mode, event) {
(Ready, Start) => transition(Active).emit(Init),
(Active, Reset) => transition(Ready),
(Active, Fault) => transition(Safe).emit(Shutdown),
_ => ignore(),
}
}
}
struct ForwardOnly;
impl Policy<Mode> for ForwardOnly {
fn is_allowed(&self, from: &Mode, to: &Mode) -> bool {
matches!(
(from, to),
(Mode::Ready, Mode::Active) | (Mode::Active, Mode::Safe)
)
}
}
fn main() {
let system = System;
let policy = ForwardOnly;
let mut runner = Runner::new(&system);
println!("Starting in {:?}", runner.mode());
let commands = runner.feed_checked(&Event::Start, &policy);
println!("\nEvent: Start");
println!(" mode: {:?}, commands: {:?}", runner.mode(), commands);
let result = runner.feed_checked(&Event::Reset, &policy);
println!("\nEvent: Reset");
match &result {
Ok(cmds) => println!(" mode: {:?}, commands: {cmds:?}", runner.mode()),
Err(err) => println!(" denied: {err}"),
}
println!(" mode unchanged: {:?}", runner.mode());
let commands = runner.feed_checked(&Event::Fault, &policy);
println!("\nEvent: Fault");
println!(" mode: {:?}, commands: {:?}", runner.mode(), commands);
}