Skip to main content

sim_kernel/
event.rs

1//! The event contract: timestamped records emitted during evaluation.
2//!
3//! The kernel defines the [`Event`] record, its kinds, logical [`Tick`]
4//! clocks, and the [`EventSource`] contract; libraries produce the events.
5
6use std::collections::BTreeSet;
7
8use crate::{
9    env::Cx,
10    error::{Diagnostic, Error, Result},
11    id::Symbol,
12    ref_id::Ref,
13};
14
15/// A logical-clock reading: one index along a named clock.
16#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct Tick {
18    /// Symbol naming the logical clock.
19    pub clock: Symbol,
20    /// Reference to this clock's index value.
21    pub index: Ref,
22}
23
24impl Tick {
25    /// Build a tick for `clock` at `index`.
26    pub fn new(clock: Symbol, index: Ref) -> Self {
27        Self { clock, index }
28    }
29}
30
31/// A timestamped record emitted during a run's evaluation.
32///
33/// # Examples
34///
35/// ```
36/// # use sim_kernel::event::{Event, EventKind, Tick};
37/// # use sim_kernel::id::Symbol;
38/// # use sim_kernel::ref_id::Ref;
39/// let run = Ref::Symbol(Symbol::new("run"));
40/// let event = Event::started(run, 0, Ref::Symbol(Symbol::new("request"))).unwrap();
41/// assert!(matches!(event.kind, EventKind::Started { .. }));
42///
43/// // Ticks must carry distinct clocks.
44/// let dup = vec![
45///     Tick::new(Symbol::new("clock"), Ref::Symbol(Symbol::new("a"))),
46///     Tick::new(Symbol::new("clock"), Ref::Symbol(Symbol::new("b"))),
47/// ];
48/// assert!(
49///     Event::new(Ref::Symbol(Symbol::new("run")), 1, dup, EventKind::Done).is_err()
50/// );
51/// ```
52#[derive(Clone, Debug, PartialEq, Eq)]
53pub struct Event {
54    /// Reference identifying the run that emitted the event.
55    pub run: Ref,
56    /// Per-run monotonic sequence number.
57    pub seq: u64,
58    /// Logical-clock readings at the time of emission.
59    pub ticks: Vec<Tick>,
60    /// The event payload.
61    pub kind: EventKind,
62}
63
64impl Event {
65    /// Build an event after validating its ticks have distinct clocks.
66    pub fn new(run: Ref, seq: u64, ticks: Vec<Tick>, kind: EventKind) -> Result<Self> {
67        validate_ticks(&ticks)?;
68        Ok(Self {
69            run,
70            seq,
71            ticks,
72            kind,
73        })
74    }
75
76    /// Build a [`EventKind::Started`] event with no ticks.
77    pub fn started(run: Ref, seq: u64, request: Ref) -> Result<Self> {
78        Self::new(run, seq, Vec::new(), EventKind::Started { request })
79    }
80
81    /// Build a [`EventKind::Final`] event with no ticks.
82    pub fn final_value(run: Ref, seq: u64, value: Ref) -> Result<Self> {
83        Self::new(run, seq, Vec::new(), EventKind::Final(value))
84    }
85
86    /// Build a [`EventKind::Failed`] event with no ticks.
87    pub fn failed(run: Ref, seq: u64, error: Ref) -> Result<Self> {
88        Self::new(run, seq, Vec::new(), EventKind::Failed(error))
89    }
90
91    /// Build a [`EventKind::Done`] event with no ticks.
92    pub fn done(run: Ref, seq: u64) -> Result<Self> {
93        Self::new(run, seq, Vec::new(), EventKind::Done)
94    }
95}
96
97/// The payload variants an [`Event`] can carry.
98#[derive(Clone, Debug, PartialEq, Eq)]
99pub enum EventKind {
100    /// A run started from the given request.
101    Started {
102        /// Reference to the originating request.
103        request: Ref,
104    },
105    /// A claim was asserted.
106    Claim {
107        /// Reference to the asserted claim.
108        claim: Ref,
109    },
110    /// A diagnostic was emitted.
111    Diagnostic(Diagnostic),
112    /// A trace marker was emitted.
113    Trace(Ref),
114    /// A streamed chunk of output.
115    Chunk {
116        /// Reference to the chunk payload.
117        payload: Ref,
118    },
119    /// An effect was requested.
120    EffectRequested {
121        /// Reference to the requested effect.
122        effect: Ref,
123    },
124    /// An effect was resolved with a result.
125    EffectResolved {
126        /// Reference to the resolved effect.
127        effect: Ref,
128        /// Reference to the effect result.
129        result: Ref,
130    },
131    /// A continuation capture occurred at an effect.
132    Capture {
133        /// Reference to the captured effect.
134        effect: Ref,
135    },
136    /// A card was published for a subject.
137    Card {
138        /// Reference to the card's subject.
139        subject: Ref,
140        /// Reference to the card.
141        card: Ref,
142    },
143    /// The run produced its final value.
144    Final(Ref),
145    /// The run failed with an error.
146    Failed(Ref),
147    /// The run finished.
148    Done,
149}
150
151/// A source that produces a run's events in order.
152///
153/// The kernel defines the pull contract; libraries supply the production.
154pub trait EventSource: Send + Sync {
155    /// Pull the next event, or `None` when the source is exhausted.
156    fn next(&self, cx: &mut Cx) -> Result<Option<Event>>;
157
158    /// Release the source's resources; the default is a no-op.
159    fn close(&self, _cx: &mut Cx) -> Result<()> {
160        Ok(())
161    }
162}
163
164/// Validate that `ticks` carry distinct clocks, erroring on a duplicate.
165pub fn validate_ticks(ticks: &[Tick]) -> Result<()> {
166    let mut clocks = BTreeSet::new();
167    for tick in ticks {
168        if !clocks.insert(tick.clock.clone()) {
169            return Err(Error::Eval(format!(
170                "duplicate event tick clock {}",
171                tick.clock
172            )));
173        }
174    }
175    Ok(())
176}