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