Skip to main content

khive_types/
timestamp.rs

1//! Timestamp — microseconds since Unix epoch.
2//!
3//! No clock access — generation happens in host crates.
4
5use core::fmt;
6
7#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[repr(transparent)]
10pub struct Timestamp(u64);
11
12impl Timestamp {
13    pub const EPOCH: Self = Self(0);
14    pub const MAX: Self = Self(u64::MAX);
15
16    #[inline]
17    pub const fn from_micros(micros: u64) -> Self {
18        Self(micros)
19    }
20
21    #[inline]
22    pub const fn from_millis(millis: u64) -> Self {
23        Self(millis.saturating_mul(1000))
24    }
25
26    #[inline]
27    pub const fn from_secs(secs: u64) -> Self {
28        Self(secs.saturating_mul(1_000_000))
29    }
30
31    #[inline]
32    pub const fn as_micros(&self) -> u64 {
33        self.0
34    }
35
36    #[inline]
37    pub const fn as_millis(&self) -> u64 {
38        self.0 / 1000
39    }
40
41    #[inline]
42    pub const fn as_secs(&self) -> u64 {
43        self.0 / 1_000_000
44    }
45
46    #[inline]
47    pub const fn is_zero(&self) -> bool {
48        self.0 == 0
49    }
50
51    #[inline]
52    pub const fn saturating_add(self, micros: u64) -> Self {
53        Self(self.0.saturating_add(micros))
54    }
55
56    #[inline]
57    pub const fn saturating_sub(self, micros: u64) -> Self {
58        Self(self.0.saturating_sub(micros))
59    }
60
61    pub const fn duration_since(self, earlier: Self) -> u64 {
62        self.0.saturating_sub(earlier.0)
63    }
64}
65
66impl fmt::Debug for Timestamp {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        write!(f, "Timestamp({}µs)", self.0)
69    }
70}
71
72impl fmt::Display for Timestamp {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        write!(f, "{}µs", self.0)
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn conversions() {
84        let ts = Timestamp::from_secs(1700000000);
85        assert_eq!(ts.as_secs(), 1700000000);
86        assert_eq!(ts.as_millis(), 1700000000000);
87        assert_eq!(ts.as_micros(), 1700000000000000);
88    }
89
90    #[test]
91    fn ordering() {
92        let a = Timestamp::from_secs(1);
93        let b = Timestamp::from_secs(2);
94        assert!(a < b);
95    }
96
97    #[test]
98    fn arithmetic() {
99        let ts = Timestamp::from_secs(10);
100        assert_eq!(ts.saturating_add(1_000_000), Timestamp::from_secs(11));
101        assert_eq!(ts.saturating_sub(5_000_000), Timestamp::from_secs(5));
102        assert_eq!(Timestamp::from_secs(0).saturating_sub(1), Timestamp::EPOCH);
103    }
104
105    #[test]
106    fn duration_since() {
107        let a = Timestamp::from_secs(10);
108        let b = Timestamp::from_secs(15);
109        assert_eq!(b.duration_since(a), 5_000_000);
110    }
111}