governor/clock/
with_std.rs

1use super::{Clock, Reference};
2
3use std::prelude::v1::*;
4
5use crate::nanos::Nanos;
6use std::ops::Add;
7use std::time::{Duration, SystemTime};
8use web_time::Instant;
9
10/// The monotonic clock implemented by [`Instant`].
11#[derive(Clone, Debug, Default)]
12pub struct MonotonicClock;
13
14impl Add<Nanos> for Instant {
15    type Output = Instant;
16
17    fn add(self, other: Nanos) -> Instant {
18        let other: Duration = other.into();
19        self + other
20    }
21}
22
23impl Reference for Instant {
24    fn duration_since(&self, earlier: Self) -> Nanos {
25        if earlier < *self {
26            (*self - earlier).into()
27        } else {
28            Nanos::from(Duration::new(0, 0))
29        }
30    }
31
32    fn saturating_sub(&self, duration: Nanos) -> Self {
33        self.checked_sub(duration.into()).unwrap_or(*self)
34    }
35}
36
37impl Clock for MonotonicClock {
38    type Instant = Instant;
39
40    fn now(&self) -> Self::Instant {
41        Instant::now()
42    }
43}
44
45/// The non-monotonic clock implemented by [`SystemTime`].
46#[derive(Clone, Debug, Default)]
47pub struct SystemClock;
48
49impl Reference for SystemTime {
50    /// Returns the difference in times between the two
51    /// SystemTimes. Due to the fallible nature of SystemTimes,
52    /// returns the zero duration if a negative duration would
53    /// result (e.g. due to system clock adjustments).
54    fn duration_since(&self, earlier: Self) -> Nanos {
55        self.duration_since(earlier)
56            .unwrap_or_else(|_| Duration::new(0, 0))
57            .into()
58    }
59
60    fn saturating_sub(&self, duration: Nanos) -> Self {
61        self.checked_sub(duration.into()).unwrap_or(*self)
62    }
63}
64
65impl Add<Nanos> for SystemTime {
66    type Output = SystemTime;
67
68    fn add(self, other: Nanos) -> SystemTime {
69        let other: Duration = other.into();
70        self + other
71    }
72}
73
74impl Clock for SystemClock {
75    type Instant = SystemTime;
76
77    fn now(&self) -> Self::Instant {
78        SystemTime::now()
79    }
80}
81
82/// Identifies clocks that run similarly to the monotonic realtime clock.
83///
84/// Clocks implementing this trait can be used with rate-limiters functions that operate
85/// asynchronously.
86pub trait ReasonablyRealtime: Clock {
87    /// Returns a reference point at the start of an operation.
88    fn reference_point(&self) -> Self::Instant {
89        self.now()
90    }
91}
92
93impl ReasonablyRealtime for MonotonicClock {}
94
95impl ReasonablyRealtime for SystemClock {}
96
97/// Some tests to ensure that the code above gets exercised. We don't
98/// rely on them in tests (being nastily tainted by realism), so we
99/// have to get creative.
100#[cfg(test)]
101mod test {
102    use super::*;
103    use crate::clock::{Clock, Reference, SystemClock};
104    use crate::nanos::Nanos;
105    use std::time::Duration;
106
107    cfg_if::cfg_if! {
108        // This test is broken on macOS on M1 machines, due to
109        // https://github.com/rust-lang/rust/issues/91417:
110        if #[cfg(not(all(target_arch = "aarch64", target_os = "macos")))] {
111            use crate::clock::MonotonicClock;
112            #[test]
113            fn instant_impls_coverage() {
114                let one_ns = Nanos::new(1);
115                let c = MonotonicClock::default();
116                let now = c.now();
117                let ns_dur = Duration::from(one_ns);
118                assert_ne!(now + ns_dur, now, "{:?} + {:?}", ns_dur, now);
119                assert_eq!(one_ns, Reference::duration_since(&(now + one_ns), now));
120                assert_eq!(Nanos::new(0), Reference::duration_since(&now, now + one_ns));
121                assert_eq!(
122                    Reference::saturating_sub(&(now + Duration::from_nanos(1)), one_ns),
123                    now
124                );
125            }
126        }
127    }
128
129    #[test]
130    fn system_clock_impls_coverage() {
131        let one_ns = Nanos::new(1);
132        let c = SystemClock;
133        let now = c.now();
134        assert_ne!(now + one_ns, now);
135        // Thankfully, we're not comparing two system clock readings
136        // here so that ought to be safe, I think:
137        assert_eq!(one_ns, Reference::duration_since(&(now + one_ns), now));
138        assert_eq!(
139            Reference::saturating_sub(&(now + Duration::from_nanos(1)), one_ns),
140            now
141        );
142    }
143}