monoio/time/
instant.rs

1#![allow(clippy::trivially_copy_pass_by_ref)]
2
3use std::{fmt, ops, time::Duration};
4
5/// A measurement of a monotonically nondecreasing clock.
6/// Opaque and useful only with `Duration`.
7///
8/// Instants are always guaranteed to be no less than any previously measured
9/// instant when created, and are often useful for tasks such as measuring
10/// benchmarks or timing how long an operation takes.
11///
12/// Note, however, that instants are not guaranteed to be **steady**. In other
13/// words, each tick of the underlying clock may not be the same length (e.g.
14/// some seconds may be longer than others). An instant may jump forwards or
15/// experience time dilation (slow down or speed up), but it will never go
16/// backwards.
17///
18/// Instants are opaque types that can only be compared to one another. There is
19/// no method to get "the number of seconds" from an instant. Instead, it only
20/// allows measuring the duration between two instants (or comparing two
21/// instants).
22///
23/// The size of an `Instant` struct may vary depending on the target operating
24/// system.
25///
26/// # Note
27///
28/// This type wraps the inner `std` variant and is used to align the Monoio
29/// clock for uses of `now()`. This can be useful for testing where you can
30/// take advantage of `time::pause()` and `time::advance()`.
31#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
32pub struct Instant {
33    std: std::time::Instant,
34}
35
36impl Instant {
37    /// Returns an instant corresponding to "now".
38    ///
39    /// # Examples
40    ///
41    /// ```
42    /// use monoio::time::Instant;
43    ///
44    /// let now = Instant::now();
45    /// ```
46    pub fn now() -> Instant {
47        variant::now()
48    }
49
50    /// Create a `monoio::time::Instant` from a `std::time::Instant`.
51    pub fn from_std(std: std::time::Instant) -> Instant {
52        Instant { std }
53    }
54
55    pub(crate) fn far_future() -> Instant {
56        // Roughly 30 years from now.
57        // API does not provide a way to obtain max `Instant`
58        // or convert specific date in the future to instant.
59        // 1000 years overflows on macOS, 100 years overflows on FreeBSD.
60        Self::now() + Duration::from_secs(86400 * 365 * 30)
61    }
62
63    /// Convert the value into a `std::time::Instant`.
64    pub fn into_std(self) -> std::time::Instant {
65        self.std
66    }
67
68    /// Returns the amount of time elapsed from another instant to this one.
69    ///
70    /// # Panics
71    ///
72    /// This function will panic if `earlier` is later than `self`.
73    pub fn duration_since(&self, earlier: Instant) -> Duration {
74        self.std.duration_since(earlier.std)
75    }
76
77    /// Returns the amount of time elapsed from another instant to this one, or
78    /// None if that instant is later than this one.
79    ///
80    /// # Examples
81    ///
82    /// ```
83    /// use monoio::time::{sleep, Duration, Instant};
84    ///
85    /// #[monoio::main(timer_enabled = true)]
86    /// async fn main() {
87    ///     let now = Instant::now();
88    ///     sleep(Duration::new(0, 50)).await;
89    ///     let new_now = Instant::now();
90    ///     println!("{:?}", new_now.checked_duration_since(now));
91    ///     println!("{:?}", now.checked_duration_since(new_now)); // None
92    /// }
93    /// ```
94    pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
95        self.std.checked_duration_since(earlier.std)
96    }
97
98    /// Returns the amount of time elapsed from another instant to this one, or
99    /// zero duration if that instant is later than this one.
100    ///
101    /// # Examples
102    ///
103    /// ```
104    /// use monoio::time::{sleep, Duration, Instant};
105    ///
106    /// #[monoio::main(timer_enabled = true)]
107    /// async fn main() {
108    ///     let now = Instant::now();
109    ///     sleep(Duration::new(0, 10)).await;
110    ///     let new_now = Instant::now();
111    ///     println!("{:?}", new_now.saturating_duration_since(now));
112    ///     println!("{:?}", now.saturating_duration_since(new_now)); // 0ns
113    /// }
114    /// ```
115    pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
116        self.std.saturating_duration_since(earlier.std)
117    }
118
119    /// Returns the amount of time elapsed since this instant was created.
120    ///
121    /// # Panics
122    ///
123    /// This function may panic if the current time is earlier than this
124    /// instant, which is something that can happen if an `Instant` is
125    /// produced synthetically.
126    ///
127    /// # Examples
128    ///
129    /// ```
130    /// use monoio::time::{sleep, Duration, Instant};
131    ///
132    /// #[monoio::main(timer_enabled = true)]
133    /// async fn main() {
134    ///     let instant = Instant::now();
135    ///     let three_secs = Duration::from_millis(30);
136    ///     sleep(three_secs).await;
137    ///     assert!(instant.elapsed() >= three_secs);
138    /// }
139    /// ```
140    pub fn elapsed(&self) -> Duration {
141        Instant::now() - *self
142    }
143
144    /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be
145    /// represented as `Instant` (which means it's inside the bounds of the
146    /// underlying data structure), `None` otherwise.
147    pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
148        self.std.checked_add(duration).map(Instant::from_std)
149    }
150
151    /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be
152    /// represented as `Instant` (which means it's inside the bounds of the
153    /// underlying data structure), `None` otherwise.
154    pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
155        self.std.checked_sub(duration).map(Instant::from_std)
156    }
157}
158
159impl From<std::time::Instant> for Instant {
160    fn from(time: std::time::Instant) -> Instant {
161        Instant::from_std(time)
162    }
163}
164
165impl From<Instant> for std::time::Instant {
166    fn from(time: Instant) -> std::time::Instant {
167        time.into_std()
168    }
169}
170
171impl ops::Add<Duration> for Instant {
172    type Output = Instant;
173
174    fn add(self, other: Duration) -> Instant {
175        Instant::from_std(self.std + other)
176    }
177}
178
179impl ops::AddAssign<Duration> for Instant {
180    fn add_assign(&mut self, rhs: Duration) {
181        *self = *self + rhs;
182    }
183}
184
185impl ops::Sub for Instant {
186    type Output = Duration;
187
188    fn sub(self, rhs: Instant) -> Duration {
189        self.std - rhs.std
190    }
191}
192
193impl ops::Sub<Duration> for Instant {
194    type Output = Instant;
195
196    fn sub(self, rhs: Duration) -> Instant {
197        Instant::from_std(self.std.checked_sub(rhs).unwrap())
198    }
199}
200
201impl ops::SubAssign<Duration> for Instant {
202    fn sub_assign(&mut self, rhs: Duration) {
203        *self = *self - rhs;
204    }
205}
206
207impl fmt::Debug for Instant {
208    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
209        self.std.fmt(fmt)
210    }
211}
212
213mod variant {
214    use super::Instant;
215
216    pub(super) fn now() -> Instant {
217        Instant::from_std(std::time::Instant::now())
218    }
219}