governor/
clock.rs

1//! Time sources for rate limiters.
2//!
3//! The time sources contained in this module allow the rate limiter
4//! to be (optionally) independent of std, and additionally
5//! allow mocking the passage of time.
6//!
7//! You can supply a custom time source by implementing both [`Reference`]
8//! and [`Clock`] for your own types, and by implementing `Add<Nanos>` for
9//! your [`Reference`] type:
10//! ```rust
11//! # use std::ops::Add;
12//! use governor::clock::{Reference, Clock};
13//! use governor::nanos::Nanos;
14//!
15//! #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
16//! struct MyInstant(u64);
17//!
18//! impl Add<Nanos> for MyInstant {
19//!     type Output = Self;
20//!
21//!    fn add(self, other: Nanos) -> Self {
22//!        Self(self.0 + other.as_u64())
23//!    }
24//! }
25//!
26//! impl Reference for MyInstant {
27//!     fn duration_since(&self, earlier: Self) -> Nanos {
28//!         self.0.checked_sub(earlier.0).unwrap_or(0).into()
29//!     }
30//!
31//!     fn saturating_sub(&self, duration: Nanos) -> Self {
32//!         Self(self.0.checked_sub(duration.into()).unwrap_or(self.0))
33//!     }
34//! }
35//!
36//! struct MyCounter(u64);
37//!
38//! impl Clock for MyCounter {
39//!     type Instant = MyInstant;
40//!
41//!     fn now(&self) -> Self::Instant {
42//!         MyInstant(self.0)
43//!     }
44//! }
45//! ```
46
47use core::prelude::v1::*;
48
49use alloc::sync::Arc;
50use core::convert::TryInto;
51use core::fmt::Debug;
52use core::ops::Add;
53use core::sync::atomic::Ordering;
54use core::time::Duration;
55
56use portable_atomic::AtomicU64;
57
58use crate::nanos::Nanos;
59
60/// A measurement from a clock.
61pub trait Reference:
62    Sized + Add<Nanos, Output = Self> + PartialEq + Eq + Ord + Copy + Clone + Send + Sync + Debug
63{
64    /// Determines the time that separates two measurements of a
65    /// clock. Implementations of this must perform a saturating
66    /// subtraction - if the `earlier` timestamp should be later,
67    /// `duration_since` must return the zero duration.
68    fn duration_since(&self, earlier: Self) -> Nanos;
69
70    /// Returns a reference point that lies at most `duration` in the
71    /// past from the current reference. If an underflow should occur,
72    /// returns the current reference.
73    fn saturating_sub(&self, duration: Nanos) -> Self;
74}
75
76/// A time source used by rate limiters.
77pub trait Clock {
78    /// A measurement of a monotonically increasing clock.
79    type Instant: Reference;
80
81    /// Returns a measurement of the clock.
82    fn now(&self) -> Self::Instant;
83}
84
85impl Reference for Duration {
86    /// The internal duration between this point and another.
87    /// ```rust
88    /// # use std::time::Duration;
89    /// # use governor::clock::Reference;
90    /// let diff = Duration::from_secs(20).duration_since(Duration::from_secs(10));
91    /// assert_eq!(diff, Duration::from_secs(10).into());
92    /// ```
93    fn duration_since(&self, earlier: Self) -> Nanos {
94        self.checked_sub(earlier)
95            .unwrap_or_else(|| Duration::new(0, 0))
96            .into()
97    }
98
99    /// The internal duration between this point and another.
100    /// ```rust
101    /// # use std::time::Duration;
102    /// # use governor::clock::Reference;
103    /// let diff = Reference::saturating_sub(&Duration::from_secs(20), Duration::from_secs(10).into());
104    /// assert_eq!(diff, Duration::from_secs(10));
105    /// ```
106    fn saturating_sub(&self, duration: Nanos) -> Self {
107        self.checked_sub(duration.into()).unwrap_or(*self)
108    }
109}
110
111impl Add<Nanos> for Duration {
112    type Output = Self;
113
114    fn add(self, other: Nanos) -> Self {
115        let other: Duration = other.into();
116        self + other
117    }
118}
119
120/// A mock implementation of a clock. All it does is keep track of
121/// what "now" is (relative to some point meaningful to the program),
122/// and returns that.
123///
124/// # Thread safety
125/// The mock time is represented as an atomic u64 count of nanoseconds, behind an [`Arc`].
126/// Clones of this clock will all show the same time, even if the original advances.
127#[derive(Debug, Clone, Default)]
128pub struct FakeRelativeClock {
129    now: Arc<AtomicU64>,
130}
131
132impl FakeRelativeClock {
133    /// Advances the fake clock by the given amount.
134    pub fn advance(&self, by: Duration) {
135        let by: u64 = by
136            .as_nanos()
137            .try_into()
138            .expect("Can not represent times past ~584 years");
139
140        let mut prev = self.now.load(Ordering::Acquire);
141        let mut next = prev + by;
142        while let Err(next_prev) =
143            self.now
144                .compare_exchange_weak(prev, next, Ordering::Release, Ordering::Relaxed)
145        {
146            prev = next_prev;
147            next = prev + by;
148        }
149    }
150}
151
152impl PartialEq for FakeRelativeClock {
153    /// Compares two fake relative clocks' current state, snapshotted.
154    ///
155    /// ```rust
156    /// # use std::time::Duration;
157    /// # use governor::clock::FakeRelativeClock;
158    /// let clock1 = FakeRelativeClock::default();
159    /// let clock2 = FakeRelativeClock::default();
160    /// assert_eq!(clock1, clock2);
161    /// clock1.advance(Duration::from_secs(1));
162    /// assert_ne!(clock1, clock2);
163    /// ```
164    fn eq(&self, other: &Self) -> bool {
165        self.now.load(Ordering::Relaxed) == other.now.load(Ordering::Relaxed)
166    }
167}
168
169impl Clock for FakeRelativeClock {
170    type Instant = Nanos;
171
172    fn now(&self) -> Self::Instant {
173        self.now.load(Ordering::Relaxed).into()
174    }
175}
176
177#[cfg(feature = "std")]
178mod with_std;
179#[cfg(feature = "std")]
180pub use with_std::*;
181
182#[cfg(all(feature = "std", feature = "quanta"))]
183mod quanta;
184#[cfg(all(feature = "std", feature = "quanta"))]
185pub use self::quanta::*;
186
187mod default;
188
189pub use default::*;
190
191#[cfg(all(feature = "std", test))]
192mod test {
193    use super::*;
194    use crate::nanos::Nanos;
195
196    use std::sync::Arc;
197    use std::thread;
198    use std::time::Duration;
199
200    #[test]
201    fn fake_clock_parallel_advances() {
202        let clock = Arc::new(FakeRelativeClock::default());
203        let threads = std::iter::repeat_n((), 10)
204            .map(move |_| {
205                let clock = Arc::clone(&clock);
206                thread::spawn(move || {
207                    for _ in 0..1000000 {
208                        let now = clock.now();
209                        clock.advance(Duration::from_nanos(1));
210                        assert!(clock.now() > now);
211                    }
212                })
213            })
214            .collect::<Vec<_>>();
215        for t in threads {
216            t.join().unwrap();
217        }
218    }
219
220    #[test]
221    fn duration_addition_coverage() {
222        let d = Duration::from_secs(1);
223        let one_ns = Nanos::new(1);
224        assert!(d + one_ns > d);
225    }
226}