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}