Skip to main content

clock_lib/
monotonic.rs

1//! Monotonic clock readings.
2//!
3//! Monotonic time never goes backwards. It is the right tool for measuring
4//! elapsed time: rate limiting, timeouts, benchmarks, retry backoff. The
5//! absolute value of a [`Monotonic`] reading carries no calendar meaning —
6//! it is only useful as a delta against another [`Monotonic`] from the same
7//! process.
8//!
9//! For calendar timestamps, use [`Wall`](crate::Wall) instead.
10
11#[cfg(feature = "std")]
12use std::time::Instant;
13
14/// A captured monotonic instant.
15///
16/// `Monotonic` wraps a single sample of the operating system's monotonic
17/// clock. Two readings can be compared to recover the [`Duration`] between
18/// them with [`duration_since`](Monotonic::duration_since) or the safer
19/// [`checked_duration_since`](Monotonic::checked_duration_since).
20///
21/// `Monotonic` and [`Wall`](crate::Wall) are deliberately distinct types
22/// with no cross-type arithmetic. The compiler will reject any attempt to
23/// mix them — that separation is the central design choice of this crate.
24///
25/// Construct one with [`Monotonic::now`] or the crate-level
26/// [`now`](crate::now) shortcut.
27///
28/// [`Duration`]: core::time::Duration
29///
30/// # Examples
31///
32/// ```
33/// use clock_lib::Monotonic;
34///
35/// let start = Monotonic::now();
36/// // ... do some work ...
37/// let took = start.elapsed();
38/// assert!(took.as_nanos() < u128::MAX);
39/// ```
40#[cfg(feature = "std")]
41#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
42#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
43pub struct Monotonic(Instant);
44
45#[cfg(feature = "std")]
46impl Monotonic {
47    /// Captures the current monotonic time from the operating system.
48    ///
49    /// This is the constructor for [`Monotonic`]. The crate-level
50    /// [`now`](crate::now) function is a one-line shortcut for the same
51    /// thing.
52    ///
53    /// # Examples
54    ///
55    /// ```
56    /// use clock_lib::Monotonic;
57    ///
58    /// let t = Monotonic::now();
59    /// # let _ = t;
60    /// ```
61    #[inline]
62    #[must_use]
63    pub fn now() -> Self {
64        Self(Instant::now())
65    }
66
67    /// Returns the [`Duration`](core::time::Duration) elapsed since this
68    /// reading was captured.
69    ///
70    /// Equivalent to `Monotonic::now().duration_since(self)`.
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// use clock_lib::Monotonic;
76    ///
77    /// let t = Monotonic::now();
78    /// let _ = t.elapsed();
79    /// ```
80    #[inline]
81    #[must_use]
82    pub fn elapsed(self) -> core::time::Duration {
83        self.0.elapsed()
84    }
85
86    /// Returns the [`Duration`](core::time::Duration) between two readings.
87    ///
88    /// # Panics
89    ///
90    /// Panics if `earlier` is later than `self`. Prefer
91    /// [`checked_duration_since`](Monotonic::checked_duration_since) or
92    /// [`saturating_duration_since`](Monotonic::saturating_duration_since)
93    /// when the ordering is not guaranteed by construction.
94    ///
95    /// # Examples
96    ///
97    /// ```
98    /// use clock_lib::Monotonic;
99    ///
100    /// let earlier = Monotonic::now();
101    /// let later = Monotonic::now();
102    /// let _delta = later.duration_since(earlier);
103    /// ```
104    #[inline]
105    #[must_use]
106    pub fn duration_since(self, earlier: Self) -> core::time::Duration {
107        self.0.duration_since(earlier.0)
108    }
109
110    /// Returns `Some(duration)` if `self >= earlier`, otherwise `None`.
111    ///
112    /// The non-panicking counterpart to
113    /// [`duration_since`](Monotonic::duration_since).
114    ///
115    /// # Examples
116    ///
117    /// ```
118    /// use clock_lib::Monotonic;
119    ///
120    /// let earlier = Monotonic::now();
121    /// let later = Monotonic::now();
122    /// assert!(later.checked_duration_since(earlier).is_some());
123    /// ```
124    #[inline]
125    #[must_use]
126    pub fn checked_duration_since(self, earlier: Self) -> Option<core::time::Duration> {
127        self.0.checked_duration_since(earlier.0)
128    }
129
130    /// Returns the duration since `earlier`, saturating at zero when
131    /// `earlier` is later than `self`.
132    ///
133    /// # Examples
134    ///
135    /// ```
136    /// use clock_lib::Monotonic;
137    ///
138    /// let a = Monotonic::now();
139    /// let b = Monotonic::now();
140    /// // Regardless of which is later, this never panics.
141    /// let _ = a.saturating_duration_since(b);
142    /// ```
143    #[inline]
144    #[must_use]
145    pub fn saturating_duration_since(self, earlier: Self) -> core::time::Duration {
146        self.0.saturating_duration_since(earlier.0)
147    }
148}