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}