Skip to main content

sim_kernel/
event_ledger.rs

1//! The event ledger: the contract for accumulating ordered events by tick.
2//!
3//! The kernel defines the [`EventLedger`] store and its ordering rules;
4//! libraries decide what events flow through it and how it is persisted.
5
6use std::collections::BTreeMap;
7
8use crate::{
9    error::{Error, Result},
10    event::{Event, EventKind, Tick, validate_ticks},
11    ref_id::Ref,
12};
13
14/// Ordered store of events grouped by run, allocating sequence numbers.
15///
16/// # Examples
17///
18/// ```
19/// # use sim_kernel::event_ledger::EventLedger;
20/// # use sim_kernel::id::Symbol;
21/// # use sim_kernel::ref_id::Ref;
22/// let mut ledger = EventLedger::new();
23/// let run = Ref::Symbol(Symbol::new("run"));
24/// let request = Ref::Symbol(Symbol::new("request"));
25/// let started = ledger.started(run.clone(), request).unwrap();
26/// let done = ledger.done(run.clone()).unwrap();
27/// assert_eq!(started.seq, 0);
28/// assert_eq!(done.seq, 1);
29/// assert_eq!(ledger.len_for_run(&run), 2);
30/// ```
31#[derive(Clone, Debug, Default)]
32pub struct EventLedger {
33    next_seq_by_run: BTreeMap<Ref, u64>,
34    events_by_run: BTreeMap<Ref, Vec<Event>>,
35}
36
37impl EventLedger {
38    /// Create an empty ledger.
39    pub fn new() -> Self {
40        Self::default()
41    }
42
43    /// Total number of events across all runs.
44    pub fn len(&self) -> usize {
45        self.events_by_run.values().map(Vec::len).sum()
46    }
47
48    /// Whether the ledger holds no events.
49    pub fn is_empty(&self) -> bool {
50        self.events_by_run.values().all(Vec::is_empty)
51    }
52
53    /// Number of events recorded for `run`.
54    pub fn len_for_run(&self, run: &Ref) -> usize {
55        self.events_by_run.get(run).map_or(0, Vec::len)
56    }
57
58    /// Events recorded for `run`, in order.
59    pub fn events_for_run(&self, run: &Ref) -> &[Event] {
60        self.events_by_run.get(run).map_or(&[], Vec::as_slice)
61    }
62
63    /// Iterate over all events across all runs.
64    pub fn iter(&self) -> impl Iterator<Item = &Event> {
65        self.events_by_run.values().flat_map(|events| events.iter())
66    }
67
68    /// Append an event of `kind` to `run` with no ticks.
69    pub fn push(&mut self, run: Ref, kind: EventKind) -> Result<Event> {
70        self.push_with_ticks(run, Vec::new(), kind)
71    }
72
73    /// Append an event of `kind` to `run` carrying the given ticks.
74    pub fn push_with_ticks(
75        &mut self,
76        run: Ref,
77        ticks: Vec<Tick>,
78        kind: EventKind,
79    ) -> Result<Event> {
80        validate_ticks(&ticks)?;
81        let seq = self.allocate_seq(&run)?;
82        let event = Event::new(run.clone(), seq, ticks, kind)?;
83        self.events_by_run
84            .entry(run)
85            .or_default()
86            .push(event.clone());
87        Ok(event)
88    }
89
90    /// Append a [`EventKind::Started`] event to `run`.
91    pub fn started(&mut self, run: Ref, request: Ref) -> Result<Event> {
92        self.push(run, EventKind::Started { request })
93    }
94
95    /// Append a [`EventKind::Final`] event to `run`.
96    pub fn final_value(&mut self, run: Ref, value: Ref) -> Result<Event> {
97        self.push(run, EventKind::Final(value))
98    }
99
100    /// Append a [`EventKind::Failed`] event to `run`.
101    pub fn failed(&mut self, run: Ref, error: Ref) -> Result<Event> {
102        self.push(run, EventKind::Failed(error))
103    }
104
105    /// Append a [`EventKind::Done`] event to `run`.
106    pub fn done(&mut self, run: Ref) -> Result<Event> {
107        self.push(run, EventKind::Done)
108    }
109
110    fn allocate_seq(&mut self, run: &Ref) -> Result<u64> {
111        let next = self.next_seq_by_run.entry(run.clone()).or_insert(0);
112        let seq = *next;
113        *next = (*next)
114            .checked_add(1)
115            .ok_or_else(|| Error::Eval("event sequence overflow".to_owned()))?;
116        Ok(seq)
117    }
118}