use std::time::Duration;
use quanta::Clock;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Instant(u64);
impl Instant {
#[inline]
pub fn now() -> Self {
Self(with_clock(|c| c.raw()))
}
pub fn elapsed(&self) -> Duration {
Self::now().duration_since(*self)
}
#[inline]
pub fn duration_since(&self, earlier: Self) -> Duration {
with_clock(|c| c.delta(earlier.0, self.0))
}
#[inline]
pub fn secs_f64_since(&self, earlier: Self) -> f64 {
self.nanos_since(earlier) as f64 * 1e-9
}
#[inline]
pub fn nanos_since(&self, earlier: Self) -> u64 {
with_clock(|c| c.delta_as_nanos(earlier.0, self.0))
}
}
pub(crate) fn nanos_since_unknown_epoch() -> u64 {
with_clock(|c| c.delta_as_nanos(0, c.raw()))
}
fn with_clock<R>(f: impl FnOnce(&Clock) -> R) -> R {
use std::sync::OnceLock;
static CLOCK: OnceLock<Clock> = OnceLock::new();
#[cfg(any(test, feature = "test-util"))]
return mock::CLOCK.with(|c| match c.borrow().as_ref() {
Some(c) => f(c),
None => f(CLOCK.get_or_init(Clock::new)),
});
#[cfg(not(any(test, feature = "test-util")))]
f(CLOCK.get_or_init(Clock::new))
}
#[cfg(any(test, feature = "test-util"))]
pub use mock::*;
#[cfg(any(test, feature = "test-util"))]
mod mock {
use super::*;
thread_local! {
pub(super) static CLOCK: std::cell::RefCell<Option<Clock>> = std::cell::RefCell::new(None);
}
pub fn with_instant_mock(f: impl FnOnce(InstantMock)) {
let (clock, mock) = Clock::mock();
let mock = InstantMock(mock);
CLOCK.with(|c| *c.borrow_mut() = Some(clock));
f(mock);
}
pub struct InstantMock(std::sync::Arc<quanta::Mock>);
impl InstantMock {
pub fn advance(&self, duration: Duration) {
self.0.increment(duration);
}
}
}