1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use super::{Clock, Reference};

use std::prelude::v1::*;

use crate::nanos::Nanos;
use std::ops::Add;
use std::time::{Duration, Instant, SystemTime};

/// The monotonic clock implemented by [`Instant`].
#[derive(Clone, Debug, Default)]
pub struct MonotonicClock;

impl Add<Nanos> for Instant {
    type Output = Instant;

    fn add(self, other: Nanos) -> Instant {
        let other: Duration = other.into();
        self + other
    }
}

impl Reference for Instant {
    fn duration_since(&self, earlier: Self) -> Nanos {
        if earlier < *self {
            (*self - earlier).into()
        } else {
            Nanos::from(Duration::new(0, 0))
        }
    }

    fn saturating_sub(&self, duration: Nanos) -> Self {
        self.checked_sub(duration.into()).unwrap_or(*self)
    }
}

impl Clock for MonotonicClock {
    type Instant = Instant;

    fn now(&self) -> Self::Instant {
        Instant::now()
    }
}

/// The non-monotonic clock implemented by [`SystemTime`].
#[derive(Clone, Debug, Default)]
pub struct SystemClock;

impl Reference for SystemTime {
    /// Returns the difference in times between the two
    /// SystemTimes. Due to the fallible nature of SystemTimes,
    /// returns the zero duration if a negative duration would
    /// result (e.g. due to system clock adjustments).
    fn duration_since(&self, earlier: Self) -> Nanos {
        self.duration_since(earlier)
            .unwrap_or_else(|_| Duration::new(0, 0))
            .into()
    }

    fn saturating_sub(&self, duration: Nanos) -> Self {
        self.checked_sub(duration.into()).unwrap_or(*self)
    }
}

impl Add<Nanos> for SystemTime {
    type Output = SystemTime;

    fn add(self, other: Nanos) -> SystemTime {
        let other: Duration = other.into();
        self + other
    }
}

impl Clock for SystemClock {
    type Instant = SystemTime;

    fn now(&self) -> Self::Instant {
        SystemTime::now()
    }
}

/// Identifies clocks that run similarly to the monotonic realtime clock.
///
/// Clocks implementing this trait can be used with rate-limiters functions that operate
/// asynchronously.
pub trait ReasonablyRealtime: Clock {
    /// Returns a reference point at the start of an operation.
    fn reference_point(&self) -> Self::Instant {
        self.now()
    }
}

impl ReasonablyRealtime for MonotonicClock {}

impl ReasonablyRealtime for SystemClock {}

/// Some tests to ensure that the code above gets exercised. We don't
/// rely on them in tests (being nastily tainted by realism), so we
/// have to get creative.
#[cfg(test)]
mod test {
    use super::*;
    use crate::clock::{Clock, Reference, SystemClock};
    use crate::nanos::Nanos;
    use std::time::Duration;

    cfg_if::cfg_if! {
        // This test is broken on macOS on M1 machines, due to
        // https://github.com/rust-lang/rust/issues/91417:
        if #[cfg(not(all(target_arch = "aarch64", target_os = "macos")))] {
            use crate::clock::MonotonicClock;
            #[test]
            fn instant_impls_coverage() {
                let one_ns = Nanos::new(1);
                let c = MonotonicClock::default();
                let now = c.now();
                let ns_dur = Duration::from(one_ns);
                assert_ne!(now + ns_dur, now, "{:?} + {:?}", ns_dur, now);
                assert_eq!(one_ns, Reference::duration_since(&(now + one_ns), now));
                assert_eq!(Nanos::new(0), Reference::duration_since(&now, now + one_ns));
                assert_eq!(
                    Reference::saturating_sub(&(now + Duration::from_nanos(1)), one_ns),
                    now
                );
            }
        }
    }

    #[test]
    fn system_clock_impls_coverage() {
        let one_ns = Nanos::new(1);
        let c = SystemClock::default();
        let now = c.now();
        assert_ne!(now + one_ns, now);
        // Thankfully, we're not comparing two system clock readings
        // here so that ought to be safe, I think:
        assert_eq!(one_ns, Reference::duration_since(&(now + one_ns), now));
        assert_eq!(
            Reference::saturating_sub(&(now + Duration::from_nanos(1)), one_ns),
            now
        );
    }
}