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}