use std::time::{Duration, Instant as StdInstant};
#[cfg(test)]
use std::sync::Arc;
#[cfg(test)]
use parking_lot::RwLock;
use super::Instant;
#[derive(Default, Clone)]
pub(crate) struct Clock {
ty: ClockType,
}
#[derive(Clone)]
enum ClockType {
Standard { origin: StdInstant },
#[cfg(feature = "quanta")]
Hybrid {
std_origin: StdInstant,
quanta_origin: quanta::Instant,
},
#[cfg(test)]
Mocked { mock: Arc<Mock> },
}
impl Default for ClockType {
fn default() -> Self {
#[cfg(feature = "quanta")]
{
return ClockType::Hybrid {
std_origin: StdInstant::now(),
quanta_origin: quanta::Instant::now(),
};
}
#[allow(unreachable_code)]
ClockType::Standard {
origin: StdInstant::now(),
}
}
}
impl Clock {
#[cfg(test)]
pub(crate) fn mock() -> (Clock, Arc<Mock>) {
let mock = Arc::new(Mock::default());
let clock = Clock {
ty: ClockType::Mocked {
mock: Arc::clone(&mock),
},
};
(clock, mock)
}
pub(crate) fn now(&self) -> Instant {
match &self.ty {
ClockType::Standard { origin } => {
Instant::from_duration_since_clock_start(origin.elapsed())
}
#[cfg(feature = "quanta")]
ClockType::Hybrid { std_origin, .. } => {
Instant::from_duration_since_clock_start(std_origin.elapsed())
}
#[cfg(test)]
ClockType::Mocked { mock } => Instant::from_duration_since_clock_start(mock.elapsed()),
}
}
pub(crate) fn fast_now(&self) -> Instant {
match &self.ty {
#[cfg(feature = "quanta")]
ClockType::Hybrid { quanta_origin, .. } => {
Instant::from_duration_since_clock_start(quanta_origin.elapsed())
}
ClockType::Standard { .. } => self.now(),
#[cfg(test)]
ClockType::Mocked { .. } => self.now(),
}
}
pub(crate) fn to_std_instant(&self, instant: Instant) -> StdInstant {
match &self.ty {
ClockType::Standard { origin } => {
let duration = Duration::from_nanos(instant.as_nanos());
*origin + duration
}
#[cfg(feature = "quanta")]
ClockType::Hybrid { std_origin, .. } => {
let duration = Duration::from_nanos(instant.as_nanos());
*std_origin + duration
}
#[cfg(test)]
ClockType::Mocked { mock } => {
let duration = Duration::from_nanos(instant.as_nanos());
dbg!(mock.origin + duration)
}
}
}
}
#[cfg(test)]
pub(crate) struct Mock {
origin: StdInstant,
now: RwLock<StdInstant>,
}
#[cfg(test)]
impl Default for Mock {
fn default() -> Self {
let origin = StdInstant::now();
Self {
origin,
now: RwLock::new(origin),
}
}
}
#[cfg(test)]
impl Mock {
pub(crate) fn increment(&self, amount: Duration) {
*self.now.write() += amount;
}
pub(crate) fn elapsed(&self) -> Duration {
self.now.read().duration_since(self.origin)
}
}