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