use std::time::Duration;
#[inline]
pub(crate) fn monotonic_nanos() -> u64 {
#[cfg(not(feature = "precise-timing"))]
{
use std::sync::OnceLock;
static EPOCH: OnceLock<coarsetime::Instant> = OnceLock::new();
let epoch = EPOCH.get_or_init(coarsetime::Instant::now);
let elapsed: Duration = epoch.elapsed().into();
elapsed.as_nanos() as u64
}
#[cfg(feature = "precise-timing")]
{
use std::sync::OnceLock;
static EPOCH: OnceLock<std::time::Instant> = OnceLock::new();
let epoch = EPOCH.get_or_init(std::time::Instant::now);
epoch.elapsed().as_nanos() as u64
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Instant(Inner);
#[cfg(not(feature = "precise-timing"))]
type Inner = coarsetime::Instant;
#[cfg(feature = "precise-timing")]
type Inner = std::time::Instant;
impl Instant {
#[inline]
pub(crate) fn now() -> Self {
Self(Inner::now())
}
#[inline]
pub(crate) fn elapsed(&self) -> Duration {
#[cfg(not(feature = "precise-timing"))]
{
self.0.elapsed().into()
}
#[cfg(feature = "precise-timing")]
{
self.0.elapsed()
}
}
#[inline]
pub(crate) fn duration_since(&self, earlier: Instant) -> Duration {
#[cfg(not(feature = "precise-timing"))]
{
self.0.duration_since(earlier.0).into()
}
#[cfg(feature = "precise-timing")]
{
self.0.duration_since(earlier.0)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn elapsed_returns_non_zero_after_spin_wait() {
let start = Instant::now();
let mut sum = 0u64;
for i in 0..100_000 {
sum = sum.wrapping_add(i);
}
std::hint::black_box(sum);
let elapsed = start.elapsed();
assert!(elapsed.as_nanos() < u128::MAX);
}
#[test]
fn duration_since_earlier_is_non_negative() {
let earlier = Instant::now();
let mut sum = 0u64;
for i in 0..100_000 {
sum = sum.wrapping_add(i);
}
std::hint::black_box(sum);
let later = Instant::now();
let dur = later.duration_since(earlier);
assert!(dur.as_nanos() < u128::MAX);
}
#[test]
fn duration_since_self_is_zero() {
let t = Instant::now();
let dur = t.duration_since(t);
assert_eq!(dur, Duration::ZERO);
}
#[test]
fn instant_is_copy_and_clone() {
let t = Instant::now();
let t2 = t;
let t3 = t;
assert_eq!(t2.duration_since(t3), Duration::ZERO);
}
#[test]
fn instant_debug_format_is_non_empty() {
let t = Instant::now();
let debug = format!("{:?}", t);
assert!(!debug.is_empty());
}
#[test]
fn monotonic_nanos_increases() {
let a = monotonic_nanos();
std::hint::black_box(0u64);
let b = monotonic_nanos();
assert!(b >= a);
}
}