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