# Runner
*Requires feature `runtime`.*
Owns the current mode and feeds events into a [`Machine`](machine.md).
`Runner` is a thin convenience layer around the core contracts. It stores
the mode, calls `decide`, applies mode changes, and returns commands. It is
**not** a framework — it does not provide an event queue, scheduler, or
async runtime.
## Construction
```rust
use ready_active_safe::prelude::*;
use ready_active_safe::runtime::Runner;
# #[derive(Debug, Clone, PartialEq, Eq)]
# enum Mode { Ready, Active, Safe }
# #[derive(Debug)]
# enum Event { Start, Stop }
# #[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> {
# match (mode, event) {
# (Mode::Ready, Event::Start) => transition(Mode::Active).emit(Command::Init),
# (Mode::Active, Event::Stop) => transition(Mode::Safe).emit(Command::Shutdown),
# _ => stay(),
# }
# }
# }
let system = System;
// Start at initial_mode()
let runner = Runner::new(&system);
assert_eq!(runner.mode(), &Mode::Ready);
```
## `with_mode` — explicit starting mode
```rust
use ready_active_safe::prelude::*;
use ready_active_safe::runtime::Runner;
# #[derive(Debug, Clone, PartialEq, Eq)]
# enum Mode { Ready, Active, Safe }
# #[derive(Debug)]
# enum Event { Start, Stop }
# #[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> {
# match (mode, event) {
# (Mode::Ready, Event::Start) => transition(Mode::Active).emit(Command::Init),
# (Mode::Active, Event::Stop) => transition(Mode::Safe).emit(Command::Shutdown),
# _ => stay(),
# }
# }
# }
let system = System;
let runner = Runner::with_mode(&system, Mode::Active);
assert_eq!(runner.mode(), &Mode::Active);
```
## `feed` — process an event
```rust
use ready_active_safe::prelude::*;
use ready_active_safe::runtime::Runner;
# #[derive(Debug, Clone, PartialEq, Eq)]
# enum Mode { Ready, Active, Safe }
# #[derive(Debug)]
# enum Event { Start, Stop }
# #[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> {
# match (mode, event) {
# (Mode::Ready, Event::Start) => transition(Mode::Active).emit(Command::Init),
# (Mode::Active, Event::Stop) => transition(Mode::Safe).emit(Command::Shutdown),
# _ => stay(),
# }
# }
# }
let system = System;
let mut runner = Runner::new(&system);
let commands = runner.feed(&Event::Start);
assert_eq!(runner.mode(), &Mode::Active);
assert_eq!(commands, vec![Command::Init]);
```
## `feed_checked` — feed with policy guard
```rust
use ready_active_safe::prelude::*;
use ready_active_safe::runtime::Runner;
# #[derive(Debug, Clone, PartialEq, Eq)]
# enum Mode { Ready, Active, Safe }
# #[derive(Debug)]
# enum Event { Start, Stop }
# #[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> {
# match (mode, event) {
# (Mode::Ready, Event::Start) => transition(Mode::Active).emit(Command::Init),
# (Mode::Active, Event::Stop) => transition(Mode::Safe).emit(Command::Shutdown),
# _ => stay(),
# }
# }
# }
let system = System;
let mut runner = Runner::new(&system);
// Allowed
let commands = runner.feed_checked(&Event::Start, &AllowAll)?;
assert_eq!(runner.mode(), &Mode::Active);
// Denied — mode stays unchanged
let mut runner2 = Runner::new(&system);
let err = runner2.feed_checked(&Event::Start, &DenyAll).unwrap_err();
assert_eq!(runner2.mode(), &Mode::Ready);
assert!(matches!(err, LifecycleError::TransitionDenied { .. }));
# Ok::<(), LifecycleError<Mode>>(())
```
## `feed_and_dispatch` — feed + execute commands
```rust
use ready_active_safe::prelude::*;
use ready_active_safe::runtime::Runner;
# #[derive(Debug, Clone, PartialEq, Eq)]
# enum Mode { Ready, Active, Safe }
# #[derive(Debug)]
# enum Event { Start, Stop }
# #[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> {
# match (mode, event) {
# (Mode::Ready, Event::Start) => transition(Mode::Active).emit(Command::Init),
# (Mode::Active, Event::Stop) => transition(Mode::Safe).emit(Command::Shutdown),
# _ => stay(),
# }
# }
# }
let system = System;
let mut runner = Runner::new(&system);
let mut log = Vec::new();
assert_eq!(log, vec![Command::Init]);
```
## See Also
- [`Machine`](machine.md) — the trait `Runner` delegates to
- [`Policy`](policy.md) — used by `feed_checked`
- [`InMemoryJournal`](in_memory_journal.md) — record transitions alongside `Runner`