Skip to main content

hippmem_core/
time.rs

1//! Timestamp newtype (Timestamp) and the injectable Clock trait.
2//!
3//! Corresponds to ADR-007 and 02#0. Constitution §4.3: all "now" inside the library MUST be obtained via the Clock trait,
4//! and **MUST NOT** call `SystemTime::now()` directly.
5
6use serde::{Deserialize, Serialize};
7
8/// Unix millisecond timestamp (UTC). An i64 newtype. See ADR-007.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
10pub struct Timestamp(pub i64);
11
12impl Timestamp {
13    /// Extracts the inner i64 value (Unix milliseconds).
14    pub fn as_i64(&self) -> i64 {
15        self.0
16    }
17
18    /// Constructs from Unix milliseconds.
19    pub fn from_millis(ms: i64) -> Self {
20        Self(ms)
21    }
22}
23
24// ── Clock trait ──
25
26/// Injectable clock: all "now" inside the library is obtained through this trait.
27///
28/// See constitution §4.3 (test reproducibility), ADR-007.
29pub trait Clock {
30    /// Returns the current UTC timestamp (Unix milliseconds).
31    fn now(&self) -> Timestamp;
32}
33
34/// System clock: uses `std::time::SystemTime::now()` to obtain real time.
35///
36/// **For application layer and factory methods only**; library logic MUST obtain time through the `Clock` trait.
37pub struct SystemClock;
38
39impl Clock for SystemClock {
40    fn now(&self) -> Timestamp {
41        let ms = std::time::SystemTime::now()
42            .duration_since(std::time::UNIX_EPOCH)
43            .unwrap_or_default()
44            .as_millis() as i64;
45        Timestamp(ms)
46    }
47}
48
49/// Fixed clock: returns a fixed Timestamp, used for testing.
50pub struct FixedClock {
51    timestamp: Timestamp,
52}
53
54impl FixedClock {
55    /// Creates a fixed clock that always returns the given timestamp.
56    pub fn new(timestamp: Timestamp) -> Self {
57        Self { timestamp }
58    }
59
60    /// Sets a new fixed timestamp.
61    pub fn set(&mut self, timestamp: Timestamp) {
62        self.timestamp = timestamp;
63    }
64}
65
66impl Clock for FixedClock {
67    fn now(&self) -> Timestamp {
68        self.timestamp
69    }
70}