elfo_utils/time/
instant.rs1use std::time::Duration;
8
9use quanta::Clock;
10
11#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
13pub struct Instant(u64 ); impl Instant {
16 #[inline]
18 pub fn now() -> Self {
19 Self(with_clock(|c| c.raw()))
20 }
21
22 pub fn elapsed(&self) -> Duration {
26 Self::now().duration_since(*self)
27 }
28
29 pub fn elapsed_secs_f64(&self) -> f64 {
33 Self::now().secs_f64_since(*self)
34 }
35
36 pub fn elapsed_nanos(&self) -> u64 {
40 Self::now().nanos_since(*self)
41 }
42
43 #[inline]
49 pub fn duration_since(&self, earlier: Self) -> Duration {
50 with_clock(|c| c.delta(earlier.0, self.0))
51 }
52
53 #[inline]
57 pub fn secs_f64_since(&self, earlier: Self) -> f64 {
58 self.nanos_since(earlier) as f64 * 1e-9
59 }
60
61 #[inline]
65 pub fn nanos_since(&self, earlier: Self) -> u64 {
66 with_clock(|c| c.delta_as_nanos(earlier.0, self.0))
67 }
68}
69
70pub(crate) fn nanos_since_unknown_epoch() -> u64 {
71 with_clock(|c| c.delta_as_nanos(0, c.raw()))
72}
73
74fn with_clock<R>(f: impl FnOnce(&Clock) -> R) -> R {
75 use std::sync::OnceLock;
76
77 static CLOCK: OnceLock<Clock> = OnceLock::new();
78
79 #[cfg(any(test, feature = "test-util"))]
80 return mock::CLOCK.with(|c| match c.borrow().as_ref() {
81 Some(c) => f(c),
82 None => f(CLOCK.get_or_init(Clock::new)),
83 });
84
85 #[cfg(not(any(test, feature = "test-util")))]
86 f(CLOCK.get_or_init(Clock::new))
87}
88
89#[cfg(any(test, feature = "test-util"))]
90pub use mock::{with_instant_mock, InstantMock};
91
92#[cfg(any(test, feature = "test-util"))]
93mod mock {
94 use std::cell::RefCell;
95
96 use super::*;
97
98 thread_local! {
99 pub(super) static CLOCK: RefCell<Option<Clock>> = const { RefCell::new(None) };
100 }
101
102 pub fn with_instant_mock<R>(f: impl FnOnce(InstantMock) -> R) -> R {
104 let (clock, mock) = Clock::mock();
105 let mock = InstantMock(mock);
106 CLOCK.with(|c| *c.borrow_mut() = Some(clock));
107 let result = f(mock);
108 CLOCK.with(|c| *c.borrow_mut() = None);
109 result
110 }
111
112 pub struct InstantMock(std::sync::Arc<quanta::Mock>);
114
115 impl InstantMock {
116 pub fn advance(&self, duration: Duration) {
118 self.0.increment(duration);
119 }
120 }
121}