1//! The [`Instant`] struct and its associated `impl`s.
2
3use core::borrow::Borrow;
4use core::cmp::{Ord, Ordering, PartialEq, PartialOrd};
5use core::ops::{Add, Sub};
6use core::time::Duration as StdDuration;
7use std::time::Instant as StdInstant;
8
9use crate::Duration;
10
11/// A measurement of a monotonically non-decreasing clock. Opaque and useful only with [`Duration`].
12///
13/// Instants are always guaranteed to be no less than any previously measured instant when created,
14/// and are often useful for tasks such as measuring benchmarks or timing how long an operation
15/// takes.
16///
17/// Note, however, that instants are not guaranteed to be **steady**. In other words, each tick of
18/// the underlying clock may not be the same length (e.g. some seconds may be longer than others).
19/// An instant may jump forwards or experience time dilation (slow down or speed up), but it will
20/// never go backwards.
21///
22/// Instants are opaque types that can only be compared to one another. There is no method to get
23/// "the number of seconds" from an instant. Instead, it only allows measuring the duration between
24/// two instants (or comparing two instants).
25///
26/// This implementation allows for operations with signed [`Duration`]s, but is otherwise identical
27/// to [`std::time::Instant`].
28#[repr(transparent)]
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct Instant(pub StdInstant);
31
32impl Instant {
33 // region: delegation
34 /// Returns an `Instant` corresponding to "now".
35 ///
36 /// ```rust
37 /// # use time::Instant;
38 /// println!("{:?}", Instant::now());
39 /// ```
40 pub fn now() -> Self {
41 Self(StdInstant::now())
42 }
43
44 /// Returns the amount of time elapsed since this instant was created. The duration will always
45 /// be nonnegative if the instant is not synthetically created.
46 ///
47 /// ```rust
48 /// # use time::{Instant, ext::{NumericalStdDuration, NumericalDuration}};
49 /// # use std::thread;
50 /// let instant = Instant::now();
51 /// thread::sleep(1.std_milliseconds());
52 /// assert!(instant.elapsed() >= 1.milliseconds());
53 /// ```
54 pub fn elapsed(self) -> Duration {
55 Self::now() - self
56 }
57 // endregion delegation
58
59 // region: checked arithmetic
60 /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
61 /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
62 /// otherwise.
63 ///
64 /// ```rust
65 /// # use time::{Instant, ext::NumericalDuration};
66 /// let now = Instant::now();
67 /// assert_eq!(now.checked_add(5.seconds()), Some(now + 5.seconds()));
68 /// assert_eq!(now.checked_add((-5).seconds()), Some(now + (-5).seconds()));
69 /// ```
70 pub fn checked_add(self, duration: Duration) -> Option<Self> {
71 if duration.is_zero() {
72 Some(self)
73 } else if duration.is_positive() {
74 self.0.checked_add(duration.unsigned_abs()).map(Self)
75 } else {
76 debug_assert!(duration.is_negative());
77 self.0.checked_sub(duration.unsigned_abs()).map(Self)
78 }
79 }
80
81 /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
82 /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
83 /// otherwise.
84 ///
85 /// ```rust
86 /// # use time::{Instant, ext::NumericalDuration};
87 /// let now = Instant::now();
88 /// assert_eq!(now.checked_sub(5.seconds()), Some(now - 5.seconds()));
89 /// assert_eq!(now.checked_sub((-5).seconds()), Some(now - (-5).seconds()));
90 /// ```
91 pub fn checked_sub(self, duration: Duration) -> Option<Self> {
92 if duration.is_zero() {
93 Some(self)
94 } else if duration.is_positive() {
95 self.0.checked_sub(duration.unsigned_abs()).map(Self)
96 } else {
97 debug_assert!(duration.is_negative());
98 self.0.checked_add(duration.unsigned_abs()).map(Self)
99 }
100 }
101 // endregion checked arithmetic
102
103 /// Obtain the inner [`std::time::Instant`].
104 ///
105 /// ```rust
106 /// # use time::Instant;
107 /// let now = Instant::now();
108 /// assert_eq!(now.into_inner(), now.0);
109 /// ```
110 pub const fn into_inner(self) -> StdInstant {
111 self.0
112 }
113}
114
115// region: trait impls
116impl From<StdInstant> for Instant {
117 fn from(instant: StdInstant) -> Self {
118 Self(instant)
119 }
120}
121
122impl From<Instant> for StdInstant {
123 fn from(instant: Instant) -> Self {
124 instant.0
125 }
126}
127
128impl Sub for Instant {
129 type Output = Duration;
130
131 fn sub(self, other: Self) -> Self::Output {
132 match self.0.cmp(&other.0) {
133 Ordering::Equal => Duration::ZERO,
134 Ordering::Greater => (self.0 - other.0)
135 .try_into()
136 .expect(msg:"overflow converting `std::time::Duration` to `time::Duration`"),
137 Ordering::Less => -Duration::try_from(other.0 - self.0)
138 .expect(msg:"overflow converting `std::time::Duration` to `time::Duration`"),
139 }
140 }
141}
142
143impl Sub<StdInstant> for Instant {
144 type Output = Duration;
145
146 fn sub(self, other: StdInstant) -> Self::Output {
147 self - Self(other)
148 }
149}
150
151impl Sub<Instant> for StdInstant {
152 type Output = Duration;
153
154 fn sub(self, other: Instant) -> Self::Output {
155 Instant(self) - other
156 }
157}
158
159impl Add<Duration> for Instant {
160 type Output = Self;
161
162 /// # Panics
163 ///
164 /// This function may panic if the resulting point in time cannot be represented by the
165 /// underlying data structure.
166 fn add(self, duration: Duration) -> Self::Output {
167 if duration.is_positive() {
168 Self(self.0 + duration.unsigned_abs())
169 } else if duration.is_negative() {
170 #[allow(clippy::unchecked_duration_subtraction)]
171 Self(self.0 - duration.unsigned_abs())
172 } else {
173 debug_assert!(duration.is_zero());
174 self
175 }
176 }
177}
178
179impl Add<Duration> for StdInstant {
180 type Output = Self;
181
182 fn add(self, duration: Duration) -> Self::Output {
183 (Instant(self) + duration).0
184 }
185}
186
187impl Add<StdDuration> for Instant {
188 type Output = Self;
189
190 fn add(self, duration: StdDuration) -> Self::Output {
191 Self(self.0 + duration)
192 }
193}
194
195impl_add_assign!(Instant: Duration, StdDuration);
196impl_add_assign!(StdInstant: Duration);
197
198impl Sub<Duration> for Instant {
199 type Output = Self;
200
201 /// # Panics
202 ///
203 /// This function may panic if the resulting point in time cannot be represented by the
204 /// underlying data structure.
205 fn sub(self, duration: Duration) -> Self::Output {
206 if duration.is_positive() {
207 #[allow(clippy::unchecked_duration_subtraction)]
208 Self(self.0 - duration.unsigned_abs())
209 } else if duration.is_negative() {
210 Self(self.0 + duration.unsigned_abs())
211 } else {
212 debug_assert!(duration.is_zero());
213 self
214 }
215 }
216}
217
218impl Sub<Duration> for StdInstant {
219 type Output = Self;
220
221 fn sub(self, duration: Duration) -> Self::Output {
222 (Instant(self) - duration).0
223 }
224}
225
226impl Sub<StdDuration> for Instant {
227 type Output = Self;
228
229 /// # Panics
230 ///
231 /// This function may panic if the resulting point in time cannot be represented by the
232 /// underlying data structure.
233 fn sub(self, duration: StdDuration) -> Self::Output {
234 #[allow(clippy::unchecked_duration_subtraction)]
235 Self(self.0 - duration)
236 }
237}
238
239impl_sub_assign!(Instant: Duration, StdDuration);
240impl_sub_assign!(StdInstant: Duration);
241
242impl PartialEq<StdInstant> for Instant {
243 fn eq(&self, rhs: &StdInstant) -> bool {
244 self.0.eq(rhs)
245 }
246}
247
248impl PartialEq<Instant> for StdInstant {
249 fn eq(&self, rhs: &Instant) -> bool {
250 self.eq(&rhs.0)
251 }
252}
253
254impl PartialOrd<StdInstant> for Instant {
255 fn partial_cmp(&self, rhs: &StdInstant) -> Option<Ordering> {
256 self.0.partial_cmp(rhs)
257 }
258}
259
260impl PartialOrd<Instant> for StdInstant {
261 fn partial_cmp(&self, rhs: &Instant) -> Option<Ordering> {
262 self.partial_cmp(&rhs.0)
263 }
264}
265
266impl AsRef<StdInstant> for Instant {
267 fn as_ref(&self) -> &StdInstant {
268 &self.0
269 }
270}
271
272impl Borrow<StdInstant> for Instant {
273 fn borrow(&self) -> &StdInstant {
274 &self.0
275 }
276}
277// endregion trait impls
278