time/ext/instant.rs
1use std::time::Instant as StdInstant;
2
3use crate::Duration;
4
5/// Sealed trait to prevent downstream implementations.
6mod sealed {
7 /// A trait that cannot be implemented by downstream users.
8 pub trait Sealed: Sized {}
9 impl Sealed for std::time::Instant {}
10}
11
12/// An extension trait for [`std::time::Instant`] that adds methods for
13/// [`time::Duration`](Duration)s.
14pub trait InstantExt: sealed::Sealed {
15 /// # Panics
16 ///
17 /// This function may panic if the resulting point in time cannot be represented by the
18 /// underlying data structure. See [`InstantExt::checked_add_signed`] for a non-panicking
19 /// version.
20 #[inline]
21 #[track_caller]
22 fn add_signed(self, duration: Duration) -> Self {
23 self.checked_add_signed(duration)
24 .expect("overflow when adding duration to instant")
25 }
26
27 /// # Panics
28 ///
29 /// This function may panic if the resulting point in time cannot be represented by the
30 /// underlying data structure. See [`InstantExt::checked_sub_signed`] for a non-panicking
31 /// version.
32 #[inline]
33 #[track_caller]
34 fn sub_signed(self, duration: Duration) -> Self {
35 self.checked_sub_signed(duration)
36 .expect("overflow when subtracting duration from instant")
37 }
38
39 /// Returns `Some(t)` where `t` is the time `self.checked_add_signed(duration)` if `t` can be
40 /// represented as `Instant` (which means it's inside the bounds of the underlying data
41 /// structure), `None` otherwise.
42 fn checked_add_signed(&self, duration: Duration) -> Option<Self>;
43
44 /// Returns `Some(t)` where `t` is the time `self.checked_sub_signed(duration)` if `t` can be
45 /// represented as `Instant` (which means it's inside the bounds of the underlying data
46 /// structure), `None` otherwise.
47 fn checked_sub_signed(&self, duration: Duration) -> Option<Self>;
48
49 /// Returns the amount of time elapsed from another instant to this one. This will be negative
50 /// if `earlier` is later than `self`.
51 ///
52 /// # Example
53 ///
54 /// ```rust
55 /// # use std::thread::sleep;
56 /// # use std::time::{Duration, Instant};
57 /// # use time::ext::InstantExt;
58 /// let now = Instant::now();
59 /// sleep(Duration::new(1, 0));
60 /// let new_now = Instant::now();
61 /// println!("{:?}", new_now.signed_duration_since(now)); // positive
62 /// println!("{:?}", now.signed_duration_since(new_now)); // negative
63 /// ```
64 fn signed_duration_since(&self, earlier: Self) -> Duration;
65}
66
67impl InstantExt for StdInstant {
68 #[inline]
69 fn checked_add_signed(&self, duration: Duration) -> Option<Self> {
70 if duration.is_positive() {
71 self.checked_add(duration.unsigned_abs())
72 } else if duration.is_negative() {
73 self.checked_sub(duration.unsigned_abs())
74 } else {
75 debug_assert!(duration.is_zero());
76 Some(*self)
77 }
78 }
79
80 #[inline]
81 fn checked_sub_signed(&self, duration: Duration) -> Option<Self> {
82 if duration.is_positive() {
83 self.checked_sub(duration.unsigned_abs())
84 } else if duration.is_negative() {
85 self.checked_add(duration.unsigned_abs())
86 } else {
87 debug_assert!(duration.is_zero());
88 Some(*self)
89 }
90 }
91
92 #[inline]
93 fn signed_duration_since(&self, earlier: Self) -> Duration {
94 if *self > earlier {
95 self.saturating_duration_since(earlier)
96 .try_into()
97 .unwrap_or(Duration::MAX)
98 } else {
99 earlier
100 .saturating_duration_since(*self)
101 .try_into()
102 .map_or(Duration::MIN, |d: Duration| -d)
103 }
104 }
105}