Skip to main content

sim_lib_stream_core/
time.rs

1//! Semantic stream time refs shared by clocks, combinators, and placement.
2//!
3//! Kernel [`Tick`] values carry a clock symbol plus a generic [`Ref`]. This
4//! module defines the stream-core convention for numeric clock indexes in that
5//! generic slot so stream operators can compare clock meaning directly without
6//! ordering opaque content ids.
7
8use sim_kernel::{Error, Ref, Result, Symbol, Tick};
9
10/// Namespace used by stream clock-index refs.
11pub const CLOCK_INDEX_REF_NAMESPACE: &str = "stream/clock-index";
12
13/// A comparable clock index extracted from a stream [`Tick`].
14#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct ClockTickIndex(u64);
16
17impl ClockTickIndex {
18    /// Builds a comparable clock-index key from its raw index value.
19    pub fn new(value: u64) -> Self {
20        Self(value)
21    }
22
23    /// Returns the raw clock-index value.
24    pub fn value(self) -> u64 {
25        self.0
26    }
27}
28
29/// Builds the semantic [`Ref`] representation for a stream clock index.
30///
31/// The tick's clock symbol carries the clock identity; the ref stores only the
32/// index in a parseable namespace so byte ordering is never used as clock time.
33pub fn clock_index_ref(index: u64) -> Ref {
34    Ref::Symbol(clock_index_symbol(index))
35}
36
37/// Builds the symbol used by [`clock_index_ref`].
38pub fn clock_index_symbol(index: u64) -> Symbol {
39    Symbol::qualified(CLOCK_INDEX_REF_NAMESPACE, index.to_string())
40}
41
42/// Extracts a comparable index for `expected_clock` from `tick`.
43///
44/// Returns `Ok(None)` when the tick belongs to another clock. Returns an error
45/// when the tick is on `expected_clock` but does not carry the semantic
46/// stream-clock index ref representation.
47pub fn tick_clock_index(tick: &Tick, expected_clock: &Symbol) -> Result<Option<ClockTickIndex>> {
48    if &tick.clock != expected_clock {
49        return Ok(None);
50    }
51    let Ref::Symbol(symbol) = &tick.index else {
52        return Err(incomparable_tick_error(tick));
53    };
54    if symbol.namespace.as_deref() != Some(CLOCK_INDEX_REF_NAMESPACE) {
55        return Err(incomparable_tick_error(tick));
56    }
57    let index = symbol.name.parse::<u64>().map_err(|err| {
58        Error::Eval(format!(
59            "stream tick on clock {} has invalid semantic index {}: {err}",
60            tick.clock.as_qualified_str(),
61            symbol.name
62        ))
63    })?;
64    Ok(Some(ClockTickIndex::new(index)))
65}
66
67fn incomparable_tick_error(tick: &Tick) -> Error {
68    Error::Eval(format!(
69        "stream tick on clock {} has incomparable index {:?}; expected {CLOCK_INDEX_REF_NAMESPACE}/<u64>",
70        tick.clock.as_qualified_str(),
71        tick.index
72    ))
73}