Skip to main content

oriera_common/
lib.rs

1//! L0 Common — shared types used across all layers.
2//! No dependencies on other oriera crates.
3
4/// Nanoseconds since the UNIX epoch (wall clock).
5///
6/// Used for logs and metrics. Frame timing and anything feeding the
7/// deterministic replay (book T5) must use the L2 frame counter instead,
8/// never wall-clock time.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
10pub struct Timestamp(pub u64);
11
12impl Timestamp {
13    pub fn now() -> Self {
14        Self(
15            std::time::SystemTime::now()
16                .duration_since(std::time::UNIX_EPOCH)
17                .map(|d| d.as_nanos() as u64)
18                .unwrap_or(0),
19        )
20    }
21    /// Seconds elapsed from `since` to `self` (0 if `since` is later).
22    pub fn elapsed(self, since: Self) -> f32 {
23        (self.0.saturating_sub(since.0)) as f32 / 1_000_000_000.0
24    }
25}
26
27/// Frame counter, starts at 0, increments each tick. Deterministic.
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
29pub struct FrameIndex(pub u64);
30
31/// Model token accounting for one call or a running total (book T15
32/// metering). L7 providers report it, L9 systems accumulate it, the
33/// app/UI layer reads it — one vocabulary across layers, so a usage
34/// meter never re-derives units per provider.
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
36pub struct TokenUsage {
37    pub prompt: u64,
38    pub completion: u64,
39}
40
41impl TokenUsage {
42    pub const ZERO: TokenUsage = TokenUsage {
43        prompt: 0,
44        completion: 0,
45    };
46
47    pub fn total(self) -> u64 {
48        self.prompt + self.completion
49    }
50}
51
52impl std::ops::Add for TokenUsage {
53    type Output = TokenUsage;
54    fn add(self, rhs: TokenUsage) -> TokenUsage {
55        TokenUsage {
56            prompt: self.prompt + rhs.prompt,
57            completion: self.completion + rhs.completion,
58        }
59    }
60}
61
62impl std::ops::AddAssign for TokenUsage {
63    fn add_assign(&mut self, rhs: TokenUsage) {
64        self.prompt += rhs.prompt;
65        self.completion += rhs.completion;
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn elapsed_is_zero_for_later_since() {
75        let a = Timestamp(1_000);
76        let b = Timestamp(2_000);
77        assert!((b.elapsed(a) - 0.000_001).abs() < 1e-9);
78        assert_eq!(a.elapsed(b), 0.0);
79    }
80
81    #[test]
82    fn token_usage_accumulates() {
83        let a = TokenUsage {
84            prompt: 10,
85            completion: 5,
86        };
87        let mut total = a + TokenUsage::ZERO;
88        total += TokenUsage {
89            prompt: 1,
90            completion: 2,
91        };
92        assert_eq!(total.total(), 18);
93        assert_eq!(
94            total,
95            TokenUsage {
96                prompt: 11,
97                completion: 7
98            }
99        );
100    }
101}