use crate::{Error, Result};
use quanta::Clock;
use std::sync::OnceLock;
use std::time::{SystemTime, UNIX_EPOCH};
struct ClockBase {
base_wall_nanos: u128,
base_quanta_raw: u64,
}
static CLOCK: OnceLock<Clock> = OnceLock::new();
static CLOCK_BASE: OnceLock<ClockBase> = OnceLock::new();
pub fn now_nanos() -> Result<u128> {
let clock = CLOCK.get_or_init(Clock::new);
let clock_base = CLOCK_BASE.get_or_init(|| {
let wall_nanos = get_wall_clock_nanos().unwrap_or(0);
let quanta_raw = clock.raw();
ClockBase {
base_wall_nanos: wall_nanos,
base_quanta_raw: quanta_raw,
}
});
let current_quanta_raw = clock.raw();
let elapsed_nanos = clock.delta_as_nanos(clock_base.base_quanta_raw, current_quanta_raw);
Ok(clock_base.base_wall_nanos + u128::from(elapsed_nanos))
}
fn get_wall_clock_nanos() -> Result<u128> {
let duration = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|_| Error::SystemTimeError)?;
Ok(u128::from(duration.as_secs()) * 1_000_000_000 + u128::from(duration.subsec_nanos()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_nanosecond_precision() {
let mut has_non_zero_nanos = false;
let mut last_three_digits_seen = std::collections::HashSet::new();
for _ in 0..1000 {
let nanos = now_nanos().unwrap();
let last_three_digits = nanos % 1000;
last_three_digits_seen.insert(last_three_digits);
if last_three_digits != 0 {
has_non_zero_nanos = true;
}
}
assert!(
has_non_zero_nanos,
"Expected nanosecond precision with quanta, but all samples were rounded to microseconds"
);
assert!(
last_three_digits_seen.len() > 10,
"Expected variety in nanosecond digits, but only saw {} unique values: {:?}",
last_three_digits_seen.len(),
last_three_digits_seen
);
}
}