qubit_clock/nano_clock.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! High-precision clock trait providing nanosecond accuracy.
11//!
12//! This module defines the [`NanoClock`] trait, which extends [`Clock`] to
13//! provide nanosecond-precision time measurements.
14//!
15
16use crate::Clock;
17use chrono::{
18 DateTime,
19 Utc,
20};
21
22/// A trait representing a clock with nanosecond precision.
23///
24/// This trait extends [`Clock`] to provide high-precision time measurements
25/// at the nanosecond level. It's useful for performance testing,
26/// microbenchmarking, and scenarios requiring very precise time measurements.
27///
28/// # Note
29///
30/// The nanosecond timestamp is stored as an `i128` to avoid overflow issues.
31///
32/// # Examples
33///
34/// ```
35/// use qubit_clock::{NanoClock, NanoMonotonicClock};
36///
37/// let clock = NanoMonotonicClock::new();
38/// let start = clock.nanos();
39///
40/// // Perform some operation
41/// for _ in 0..1000 {
42/// // Some work
43/// }
44///
45/// let elapsed = clock.nanos() - start;
46/// println!("Elapsed: {} ns", elapsed);
47/// ```
48///
49pub trait NanoClock: Clock {
50 /// Returns the current time as a Unix timestamp in nanoseconds (UTC).
51 ///
52 /// The timestamp represents the number of nanoseconds since the Unix
53 /// epoch (1970-01-01 00:00:00 UTC).
54 ///
55 /// # Returns
56 ///
57 /// The current time as nanoseconds since the Unix epoch.
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// use qubit_clock::{NanoClock, NanoMonotonicClock};
63 ///
64 /// let clock = NanoMonotonicClock::new();
65 /// let nanos = clock.nanos();
66 /// assert!(nanos > 0);
67 /// ```
68 fn nanos(&self) -> i128;
69
70 /// Returns the current time as a `DateTime<Utc>` with nanosecond
71 /// precision.
72 ///
73 /// This method has a default implementation that constructs a
74 /// `DateTime<Utc>` from the result of [`nanos()`](NanoClock::nanos).
75 /// If the nanosecond timestamp is outside chrono's representable range,
76 /// the result is clamped to the nearest representable UTC datetime.
77 ///
78 /// # Returns
79 ///
80 /// The current time as a `DateTime<Utc>` object with nanosecond
81 /// precision.
82 ///
83 /// # Examples
84 ///
85 /// ```
86 /// use qubit_clock::{NanoClock, NanoMonotonicClock};
87 ///
88 /// let clock = NanoMonotonicClock::new();
89 /// let time = clock.time_precise();
90 /// println!("Current time (precise): {}", time);
91 /// ```
92 #[inline]
93 fn time_precise(&self) -> DateTime<Utc> {
94 let nanos = self.nanos();
95 let secs = nanos.div_euclid(1_000_000_000);
96 let nsecs = nanos.rem_euclid(1_000_000_000) as u32;
97 let secs = match i64::try_from(secs) {
98 Ok(value) => value,
99 Err(_) if nanos < 0 => return DateTime::<Utc>::MIN_UTC,
100 Err(_) => return DateTime::<Utc>::MAX_UTC,
101 };
102 DateTime::from_timestamp(secs, nsecs).unwrap_or({
103 if nanos < 0 {
104 DateTime::<Utc>::MIN_UTC
105 } else {
106 DateTime::<Utc>::MAX_UTC
107 }
108 })
109 }
110}