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::*;