# InMemoryJournal
*Requires feature `journal`.*
An in-memory journal of [`TransitionRecord`](transition_record.md) values.
Records what happened so a system can be audited or replayed.
## Construction
```rust
use ready_active_safe::journal::InMemoryJournal;
let journal: InMemoryJournal<&str, &str, &str> = InMemoryJournal::new();
assert!(journal.is_empty());
assert_eq!(journal.len(), 0);
```
## `record_step` — capture a transition
```rust
use ready_active_safe::journal::InMemoryJournal;
let mut journal: InMemoryJournal<&str, &str, &str> = InMemoryJournal::new();
journal.record_step(&"ready", &"active", &"start", &["init"]);
journal.record_step(&"active", &"safe", &"fault", &["shutdown"]);
assert_eq!(journal.len(), 2);
```
## `records` — view all records
```rust
use ready_active_safe::journal::InMemoryJournal;
let mut journal: InMemoryJournal<&str, &str, &str> = InMemoryJournal::new();
journal.record_step(&"ready", &"active", &"start", &["init"]);
let records = journal.records();
assert_eq!(records.len(), 1);
assert_eq!(records[0].from, "ready");
assert_eq!(records[0].to, "active");
```
## Query Helpers
### `transitions_from` / `transitions_to`
```rust
use ready_active_safe::journal::InMemoryJournal;
let mut journal: InMemoryJournal<&str, &str, &str> = InMemoryJournal::new();
journal.record_step(&"ready", &"active", &"start", &[]);
journal.record_step(&"active", &"safe", &"fault", &[]);
journal.record_step(&"safe", &"active", &"recover", &[]);
let from_active: Vec<_> = journal.transitions_from(&"active").collect();
assert_eq!(from_active.len(), 1);
assert_eq!(from_active[0].to, "safe");
let to_active: Vec<_> = journal.transitions_to(&"active").collect();
assert_eq!(to_active.len(), 2); // start + recover
```
### `last`
```rust
use ready_active_safe::journal::InMemoryJournal;
let mut journal: InMemoryJournal<&str, &str, &str> = InMemoryJournal::new();
assert!(journal.last().is_none());
journal.record_step(&"ready", &"active", &"start", &[]);
assert_eq!(journal.last().map(|r| r.to), Some("active"));
```
## `replay` — deterministic replay
Replays all records through a machine, verifying that decisions match:
```rust
use ready_active_safe::prelude::*;
use ready_active_safe::journal::InMemoryJournal;
#[derive(Debug, Clone, PartialEq, Eq)]
enum Mode { Ready, Active, Safe }
#[derive(Debug, Clone, PartialEq, Eq)]
enum Event { Start, 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> {
match (mode, event) {
(Mode::Ready, Event::Start) => transition(Mode::Active).emit(Command::Init),
(Mode::Active, Event::Fault) => transition(Mode::Safe).emit(Command::Shutdown),
_ => stay(),
}
}
}
let mut journal: InMemoryJournal<Mode, Event, Command> = InMemoryJournal::new();
journal.record_step(&Mode::Ready, &Mode::Active, &Event::Start, &[Command::Init]);
journal.record_step(&Mode::Active, &Mode::Safe, &Event::Fault, &[Command::Shutdown]);
let final_mode = journal.replay(&System, Mode::Ready)?;
assert_eq!(final_mode, Mode::Safe);
# Ok::<(), ready_active_safe::journal::ReplayError>(())
```
## See Also
- [`TransitionRecord`](transition_record.md) — individual records
- [`ReplayError`](replay_error.md) — errors when replay diverges
- [`Runner`](runner.md) — use alongside a journal for recording