futures_intrusive/timer/
clock.rs

1//! Monotonic clocks
2
3use core::sync::atomic::{AtomicUsize, Ordering};
4
5/// A monotonic source of time.
6///
7/// Clocks must always returning increasing timestamps.
8pub trait Clock: Sync {
9    /// Returns a timestamp in milliseconds which represents the current time
10    /// according to the clock.
11    ///
12    /// Clocks must only return timestamps that are bigger or equal than what
13    /// they returned on the last call to `now()`.
14    fn now(&self) -> u64;
15}
16
17/// A [`Clock`] which can be set to arbitrary timestamps for testing purposes.
18///
19/// It can be used in a test case as demonstrated in the following example:
20/// ```
21/// use futures_intrusive::timer::MockClock;
22/// # #[cfg(feature = "std")]
23/// # use futures_intrusive::timer::TimerService;
24///
25/// static TEST_CLOCK: MockClock = MockClock::new();
26/// TEST_CLOCK.set_time(2300); // Set the current time
27/// # #[cfg(feature = "std")]
28/// let timer = TimerService::new(&TEST_CLOCK);
29/// ```
30pub struct MockClock {
31    now: core::sync::atomic::AtomicUsize,
32}
33
34impl core::fmt::Debug for MockClock {
35    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
36        let now = self.now();
37        f.debug_struct("MockClock").field("now", &now).finish()
38    }
39}
40
41impl MockClock {
42    /// Creates a new instance of the [`MockClock`], which is initialized to
43    /// timestamp 0.
44    pub const fn new() -> MockClock {
45        MockClock {
46            now: AtomicUsize::new(0),
47        }
48    }
49
50    /// Sets the current timestamp inside to [`MockClock`] to the given value
51    pub fn set_time(&self, timestamp: u64) {
52        if timestamp > (core::usize::MAX as u64) {
53            panic!("timestamps bigger than usize::MAX are not supported")
54        }
55        let to_set = timestamp as usize;
56        self.now.store(to_set, Ordering::Release);
57    }
58}
59
60impl Clock for MockClock {
61    fn now(&self) -> u64 {
62        self.now.load(Ordering::Relaxed) as u64
63    }
64}
65
66#[cfg(feature = "std")]
67mod if_std {
68    use super::*;
69    use std::time::Instant;
70
71    /// A Clock that makes use of the Standard libraries [`std::time::Instant`]
72    /// functionality in order to generate monotonically increasing timestamps.
73    pub struct StdClock {
74        start: Instant,
75    }
76
77    impl core::fmt::Debug for StdClock {
78        fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
79            f.debug_struct("StdClock").finish()
80        }
81    }
82
83    impl StdClock {
84        /// Creates a new [`StdClock`]
85        pub fn new() -> StdClock {
86            StdClock {
87                start: Instant::now(),
88            }
89        }
90    }
91
92    impl Clock for StdClock {
93        fn now(&self) -> u64 {
94            let elapsed = Instant::now() - self.start;
95            elapsed.as_millis() as u64
96        }
97    }
98}
99
100#[cfg(feature = "std")]
101pub use self::if_std::*;