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}