ready-active-safe 0.1.3

Lifecycle engine for externally driven systems
Documentation
# 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();

runner.feed_and_dispatch(&Event::Start, |cmd| log.push(cmd));
assert_eq!(runner.mode(), &Mode::Active);
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`