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(pub(crate) 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}