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 if elapsed_nanos > i128::MAX as u128 {
149 i128::MAX
150 } else {
151 elapsed_nanos as i128
152 }
153 }
154}
155
156impl Default for NanoMonotonicClock {
157 #[inline]
158 fn default() -> Self {
159 Self::new()
160 }
161}
162
163impl Clock for NanoMonotonicClock {
164 #[inline]
165 fn millis(&self) -> i64 {
166 let elapsed_millis = self.elapsed().as_millis();
167 let elapsed_millis = if elapsed_millis > i64::MAX as u128 {
168 i64::MAX
169 } else {
170 elapsed_millis as i64
171 };
172 let base_millis =
173 self.system_time_base_seconds * 1000 + (self.system_time_base_nanos / 1_000_000) as i64;
174 base_millis.saturating_add(elapsed_millis)
175 }
176}
177
178impl NanoClock for NanoMonotonicClock {
179 #[inline]
180 fn nanos(&self) -> i128 {
181 let elapsed_nanos = self.monotonic_nanos();
182 let base_nanos = (self.system_time_base_seconds as i128) * 1_000_000_000
183 + (self.system_time_base_nanos as i128);
184 base_nanos.saturating_add(elapsed_nanos)
185 }
186}