Skip to main content

qubit_clock/
nano_monotonic.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! High-precision monotonic clock implementation.
10//!
11//! This module provides [`NanoMonotonicClock`], a clock implementation that
12//! provides nanosecond-precision monotonic time measurements.
13//!
14//! # Author
15//!
16//! Haixing Hu
17
18use crate::{Clock, NanoClock};
19use chrono::Utc;
20use std::time::{Duration, Instant};
21
22/// A clock implementation that provides nanosecond-precision monotonic time.
23///
24/// This clock combines the monotonic guarantees of
25/// [`MonotonicClock`](crate::MonotonicClock) with the nanosecond precision
26/// of [`NanoClock`]. It uses `std::time::Instant` as its time source and
27/// stores the base time with nanosecond precision.
28///
29/// # Use Cases
30///
31/// - High-precision performance testing
32/// - Microbenchmarking
33/// - Scenarios requiring nanosecond-level time measurements
34///
35/// # Thread Safety
36///
37/// This type is completely thread-safe as all fields are immutable after
38/// creation.
39///
40/// # Examples
41///
42/// ```
43/// use qubit_clock::{NanoClock, NanoMonotonicClock};
44///
45/// let clock = NanoMonotonicClock::new();
46/// let start = clock.nanos();
47///
48/// // Perform some operation
49/// for _ in 0..1000 {
50///     // Some work
51/// }
52///
53/// let elapsed = clock.nanos() - start;
54/// println!("Elapsed: {} ns", elapsed);
55/// ```
56///
57/// # Author
58///
59/// Haixing Hu
60#[derive(Debug, Clone)]
61pub struct NanoMonotonicClock {
62    /// The base instant when this clock was created.
63    instant_base: Instant,
64    /// The system time (seconds part) when this clock was created.
65    system_time_base_seconds: i64,
66    /// The system time (nanoseconds part) when this clock was created.
67    system_time_base_nanos: u32,
68}
69
70impl NanoMonotonicClock {
71    /// Creates a new `NanoMonotonicClock`.
72    ///
73    /// The clock records the current instant and system time (with nanosecond
74    /// precision) as its base point. All subsequent time queries will be
75    /// calculated relative to this base point.
76    ///
77    /// # Returns
78    ///
79    /// A new `NanoMonotonicClock` instance.
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// use qubit_clock::NanoMonotonicClock;
85    ///
86    /// let clock = NanoMonotonicClock::new();
87    /// ```
88    ///
89    #[inline]
90    pub fn new() -> Self {
91        let now = Utc::now();
92        NanoMonotonicClock {
93            instant_base: Instant::now(),
94            system_time_base_seconds: now.timestamp(),
95            system_time_base_nanos: now.timestamp_subsec_nanos(),
96        }
97    }
98
99    /// Returns the elapsed monotonic duration since this clock was created.
100    ///
101    /// This value is based purely on `Instant` and is not affected by system
102    /// time adjustments.
103    ///
104    /// # Returns
105    ///
106    /// The elapsed monotonic duration.
107    ///
108    /// # Examples
109    ///
110    /// ```
111    /// use qubit_clock::NanoMonotonicClock;
112    /// use std::thread;
113    /// use std::time::Duration;
114    ///
115    /// let clock = NanoMonotonicClock::new();
116    /// thread::sleep(Duration::from_millis(10));
117    /// assert!(clock.elapsed() >= Duration::from_millis(10));
118    /// ```
119    #[inline]
120    pub fn elapsed(&self) -> Duration {
121        self.instant_base.elapsed()
122    }
123
124    /// Returns the elapsed monotonic time in nanoseconds since creation.
125    ///
126    /// Unlike [`NanoClock::nanos`](crate::NanoClock::nanos), this value does
127    /// not include a wall-clock epoch anchor and is intended for interval
128    /// measurement.
129    ///
130    /// # Returns
131    ///
132    /// The elapsed monotonic nanoseconds, saturated at `i128::MAX`.
133    ///
134    /// # Examples
135    ///
136    /// ```
137    /// use qubit_clock::NanoMonotonicClock;
138    /// use std::thread;
139    /// use std::time::Duration;
140    ///
141    /// let clock = NanoMonotonicClock::new();
142    /// thread::sleep(Duration::from_millis(10));
143    /// assert!(clock.monotonic_nanos() >= 10_000_000);
144    /// ```
145    #[inline]
146    pub fn monotonic_nanos(&self) -> i128 {
147        let elapsed_nanos = self.elapsed().as_nanos();
148        i128::try_from(elapsed_nanos).unwrap_or(i128::MAX)
149    }
150}
151
152impl Default for NanoMonotonicClock {
153    #[inline]
154    fn default() -> Self {
155        Self::new()
156    }
157}
158
159impl Clock for NanoMonotonicClock {
160    #[inline]
161    fn millis(&self) -> i64 {
162        let millis = self.nanos().div_euclid(1_000_000);
163        i64::try_from(millis).unwrap_or(i64::MAX)
164    }
165}
166
167impl NanoClock for NanoMonotonicClock {
168    #[inline]
169    fn nanos(&self) -> i128 {
170        let elapsed_nanos = self.monotonic_nanos();
171        let base_nanos = (self.system_time_base_seconds as i128) * 1_000_000_000
172            + (self.system_time_base_nanos as i128);
173        base_nanos.saturating_add(elapsed_nanos)
174    }
175}