moka/common/time/
instant.rs

1use std::time::Duration;
2
3pub(crate) const MAX_NANOS: u64 = u64::MAX - 1;
4
5/// `Instant` represents a point in time since the `Clock` was created. It has
6/// nanosecond precision.
7#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
8pub(crate) struct Instant {
9    elapsed_ns: u64,
10}
11
12impl Instant {
13    pub(crate) fn from_nanos(nanos: u64) -> Instant {
14        debug_assert!(nanos <= MAX_NANOS);
15        Instant { elapsed_ns: nanos }
16    }
17
18    pub(crate) fn from_duration_since_clock_start(duration: Duration) -> Instant {
19        Instant::from_nanos(Self::duration_to_saturating_nanoseconds(duration))
20    }
21
22    pub(crate) fn as_nanos(&self) -> u64 {
23        self.elapsed_ns
24    }
25
26    /// Converts a `std::time::Duration` to nanoseconds, saturating to
27    /// `MAX_NANOSECONDS` (`u64::MAX - 1`) if the duration is too large.
28    /// (`Duration::as_nanos` returns `u128`)
29    ///
30    /// Note that `u64::MAX - 1` is used here instead of `u64::MAX` because
31    /// `u64::MAX` is used by `moka`'s `AtomicTime` to indicate the time is unset.
32    pub(crate) fn duration_to_saturating_nanoseconds(duration: Duration) -> u64 {
33        u64::try_from(duration.as_nanos())
34            .map(|n| n.min(MAX_NANOS))
35            .unwrap_or(MAX_NANOS)
36    }
37
38    pub(crate) fn saturating_add(&self, duration: Duration) -> Instant {
39        let dur_ms = Self::duration_to_saturating_nanoseconds(duration);
40        Instant::from_nanos(self.elapsed_ns.saturating_add(dur_ms).min(MAX_NANOS))
41    }
42
43    pub(crate) fn saturating_duration_since(&self, earlier: Self) -> Duration
44    where
45        Self: Sized,
46    {
47        Duration::from_nanos(self.elapsed_ns.saturating_sub(earlier.elapsed_ns))
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn test_saturating_add() {
57        let instant = Instant::from_nanos(100_000);
58        let duration = Duration::from_nanos(50_000);
59        let result = instant.saturating_add(duration);
60        assert_eq!(result, Instant::from_nanos(150_000));
61
62        let instant = Instant::from_nanos(u64::MAX - 10_000);
63        let duration = Duration::from_nanos(12_000);
64        let result = instant.saturating_add(duration);
65        assert_eq!(result, Instant::from_nanos(u64::MAX - 1));
66    }
67
68    #[test]
69    fn test_saturating_duration_since() {
70        let instant = Instant::from_nanos(100_000);
71        let earlier = Instant::from_nanos(60_000);
72        let result = instant.saturating_duration_since(earlier);
73        assert_eq!(result, Duration::from_nanos(40_000));
74
75        let instant = Instant::from_nanos(60_000);
76        let earlier = Instant::from_nanos(100_000);
77        let result = instant.saturating_duration_since(earlier);
78        assert_eq!(result, Duration::ZERO);
79    }
80}