Skip to main content

qubit_clock/monotonic/
monotonic_clock.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Defines the monotonic clock capability.
9//!
10//! The [`MonotonicClock`] trait is the injectable source of
11//! [`MonotonicInstant`] values used for timeouts, deadlines, and elapsed-time
12//! measurements. Wall time belongs on [`WallClock`](crate::WallClock) instead.
13
14use std::sync::Arc;
15use std::time::Duration;
16
17use crate::ClockDomain;
18use crate::MonotonicInstant;
19use crate::TimeError;
20use crate::Timer;
21
22/// Provides the current instant in a stable, non-decreasing clock domain.
23///
24/// Implementations return [`MonotonicInstant`] values that never move backward
25/// within one domain. Prefer this trait for timeouts, deadlines, and measuring
26/// elapsed durations. Use [`WallClock`](crate::WallClock) for civil timestamps
27/// that must align with an external calendar clock, which may jump forward or
28/// backward after a system adjustment.
29///
30/// The crate ships several implementations:
31///
32/// - [`StdMonotonicClock`](crate::StdMonotonicClock) — production clock backed
33///   by [`std::time::Instant`]
34/// - [`ManualMonotonicClock`](crate::ManualMonotonicClock) — explicitly
35///   advanced clock for deterministic tests
36/// - `TokioMonotonicClock` — Tokio time-driver clock (requires the `tokio`
37///   feature)
38///
39/// `&T`, `Arc<T>`, and `Box<T>` implement this trait when `T:
40/// MonotonicClock + ?Sized`, so borrowed, shared, and owned trait objects need
41/// no extra adapter.
42///
43/// # Examples
44///
45/// Sample a standard monotonic clock and form a deadline from its instant:
46///
47/// ```
48/// use qubit_clock::{MonotonicClock, StdMonotonicClock};
49/// use std::time::Duration;
50///
51/// let clock = StdMonotonicClock::new();
52/// let start = clock.now();
53/// let deadline = start
54///     .checked_add(Duration::from_millis(10))
55///     .expect("duration should fit");
56/// assert!(deadline.elapsed_since_origin() > start.elapsed_since_origin());
57/// ```
58///
59/// Drive logical time with a manual clock in tests without waiting for real
60/// time:
61///
62/// ```
63/// use qubit_clock::{ManualMonotonicClock, MonotonicClock};
64/// use std::time::Duration;
65///
66/// let clock = ManualMonotonicClock::new();
67/// assert_eq!(Duration::ZERO, clock.now().elapsed_since_origin());
68///
69/// clock
70///     .advance(Duration::from_secs(2))
71///     .expect("manual time should advance");
72/// assert_eq!(Duration::from_secs(2), clock.now().elapsed_since_origin());
73/// ```
74///
75/// Share one clock through a trait object:
76///
77/// ```
78/// use qubit_clock::{ManualMonotonicClock, MonotonicClock};
79/// use std::sync::Arc;
80/// use std::time::Duration;
81///
82/// let clock: Arc<dyn MonotonicClock> = Arc::new(ManualMonotonicClock::new());
83/// let first = clock.now();
84/// let second = clock.now();
85/// assert_eq!(first.domain(), second.domain());
86/// assert_eq!(Duration::ZERO, second.elapsed_since_origin());
87/// ```
88pub trait MonotonicClock: Send + Sync {
89    /// Returns this clock's stable monotonic domain identity.
90    ///
91    /// Unlike [`now()`](Self::now), this method does not sample the current
92    /// time. The returned domain remains unchanged for this clock's lifetime.
93    ///
94    /// # Returns
95    ///
96    /// The domain carried by every instant sampled from this clock.
97    #[must_use = "the clock domain should be used to validate monotonic instants"]
98    fn domain(&self) -> ClockDomain;
99
100    /// Returns the current instant in this clock's domain.
101    ///
102    /// Successive calls on the same clock never return an earlier instant.
103    /// Instants from independently created clock domains must not be mixed.
104    /// Cloned or derived same-domain handles may intentionally report the same
105    /// [`ClockDomain`](crate::ClockDomain).
106    ///
107    /// # Returns
108    ///
109    /// The current domain-scoped monotonic instant.
110    fn now(&self) -> MonotonicInstant;
111
112    /// Fixes a deadline after a relative duration.
113    ///
114    /// This method samples [`now()`](Self::now) exactly once while it runs,
115    /// then adds `duration` to that sampled instant. It does not create a
116    /// timer registration.
117    ///
118    /// # Parameters
119    ///
120    /// * `duration` - Duration from the sampled current instant.
121    ///
122    /// # Returns
123    ///
124    /// A fixed deadline in this clock's domain.
125    ///
126    /// # Errors
127    ///
128    /// Returns [`TimeError::InstantOverflow`] when the resulting deadline
129    /// cannot be represented by [`Duration`].
130    #[inline]
131    fn deadline_after(&self, duration: Duration) -> Result<MonotonicInstant, TimeError> {
132        self.now().checked_add(duration)
133    }
134
135    /// Creates a timer in this clock's exact monotonic domain.
136    ///
137    /// The call borrows rather than consumes the clock. The returned timer
138    /// retains an independent same-domain handle, so callers do not need to
139    /// clone an `Arc` before invoking this method and may continue using or
140    /// drop the original clock afterward.
141    ///
142    /// # Returns
143    ///
144    /// A shared timer whose [`Timer::clock`] reports this clock's domain.
145    #[must_use = "the timer should be retained to register deadlines"]
146    fn new_timer(&self) -> Arc<dyn Timer>;
147}
148
149impl<T> MonotonicClock for &T
150where
151    T: MonotonicClock + ?Sized,
152{
153    /// Delegates the stable domain identity to the borrowed clock.
154    ///
155    /// # Returns
156    ///
157    /// The domain returned by the borrowed clock.
158    #[inline(always)]
159    fn domain(&self) -> ClockDomain {
160        <T as MonotonicClock>::domain(*self)
161    }
162
163    /// Delegates the current instant to the borrowed clock.
164    ///
165    /// # Returns
166    ///
167    /// The current instant returned by the borrowed clock.
168    #[inline(always)]
169    fn now(&self) -> MonotonicInstant {
170        <T as MonotonicClock>::now(*self)
171    }
172
173    /// Delegates relative deadline calculation to the borrowed clock.
174    ///
175    /// # Parameters
176    ///
177    /// * `duration` - Duration from the borrowed clock's sampled current time.
178    ///
179    /// # Returns
180    ///
181    /// The deadline returned by the borrowed clock.
182    ///
183    /// # Errors
184    ///
185    /// Returns any overflow error reported by the borrowed clock.
186    #[inline(always)]
187    fn deadline_after(&self, duration: Duration) -> Result<MonotonicInstant, TimeError> {
188        <T as MonotonicClock>::deadline_after(*self, duration)
189    }
190
191    /// Delegates timer creation without consuming the borrowed clock.
192    ///
193    /// # Returns
194    ///
195    /// A timer in the borrowed clock's exact monotonic domain.
196    #[inline(always)]
197    fn new_timer(&self) -> Arc<dyn Timer> {
198        <T as MonotonicClock>::new_timer(*self)
199    }
200}
201
202impl<T> MonotonicClock for std::sync::Arc<T>
203where
204    T: MonotonicClock + ?Sized,
205{
206    /// Delegates the stable domain identity to the shared clock object.
207    ///
208    /// # Returns
209    ///
210    /// The domain returned by the wrapped clock.
211    #[inline(always)]
212    fn domain(&self) -> ClockDomain {
213        self.as_ref().domain()
214    }
215
216    /// Delegates the current instant to the shared clock object.
217    ///
218    /// # Returns
219    ///
220    /// The current instant returned by the wrapped clock.
221    #[inline(always)]
222    fn now(&self) -> MonotonicInstant {
223        self.as_ref().now()
224    }
225
226    /// Delegates relative deadline calculation to the shared clock object.
227    ///
228    /// # Parameters
229    ///
230    /// * `duration` - Duration from the wrapped clock's sampled current time.
231    ///
232    /// # Returns
233    ///
234    /// The deadline returned by the wrapped clock.
235    ///
236    /// # Errors
237    ///
238    /// Returns any overflow error reported by the wrapped clock.
239    #[inline(always)]
240    fn deadline_after(&self, duration: Duration) -> Result<MonotonicInstant, TimeError> {
241        self.as_ref().deadline_after(duration)
242    }
243
244    /// Delegates timer creation without consuming the shared clock pointer.
245    ///
246    /// # Returns
247    ///
248    /// A timer in the wrapped clock's exact monotonic domain.
249    #[inline(always)]
250    fn new_timer(&self) -> Arc<dyn Timer> {
251        self.as_ref().new_timer()
252    }
253}
254
255impl<T> MonotonicClock for Box<T>
256where
257    T: MonotonicClock + ?Sized,
258{
259    /// Delegates the stable domain identity to the boxed clock object.
260    ///
261    /// # Returns
262    ///
263    /// The domain returned by the wrapped clock.
264    #[inline(always)]
265    fn domain(&self) -> ClockDomain {
266        self.as_ref().domain()
267    }
268
269    /// Delegates the current instant to the boxed clock object.
270    ///
271    /// # Returns
272    ///
273    /// The current instant returned by the wrapped clock.
274    #[inline(always)]
275    fn now(&self) -> MonotonicInstant {
276        self.as_ref().now()
277    }
278
279    /// Delegates relative deadline calculation to the boxed clock object.
280    ///
281    /// # Parameters
282    ///
283    /// * `duration` - Duration from the wrapped clock's sampled current time.
284    ///
285    /// # Returns
286    ///
287    /// The deadline returned by the wrapped clock.
288    ///
289    /// # Errors
290    ///
291    /// Returns any overflow error reported by the wrapped clock.
292    #[inline(always)]
293    fn deadline_after(&self, duration: Duration) -> Result<MonotonicInstant, TimeError> {
294        self.as_ref().deadline_after(duration)
295    }
296
297    /// Delegates timer creation without consuming the boxed clock.
298    ///
299    /// # Returns
300    ///
301    /// A timer in the wrapped clock's exact monotonic domain.
302    #[inline(always)]
303    fn new_timer(&self) -> Arc<dyn Timer> {
304        self.as_ref().new_timer()
305    }
306}