use chrono::{DateTime, Utc};
use std::{sync::Arc, time::Duration};
use super::{
artificial::ArtificialClock,
config::ArtificialClockConfig,
controller::ClockController,
inner::ClockInner,
realtime::RealtimeClock,
sleep::{ClockSleep, ClockTimeout},
};
pub use super::sleep::Elapsed;
#[derive(Clone)]
pub struct ClockHandle {
inner: Arc<ClockInner>,
}
impl ClockHandle {
pub fn realtime() -> Self {
Self {
inner: Arc::new(ClockInner::Realtime(RealtimeClock)),
}
}
pub fn artificial(config: ArtificialClockConfig) -> (Self, ClockController) {
let clock = Arc::new(ArtificialClock::new(config));
let handle = Self {
inner: Arc::new(ClockInner::Artificial(Arc::clone(&clock))),
};
let controller = ClockController { clock };
(handle, controller)
}
#[inline]
pub fn now(&self) -> DateTime<Utc> {
match &*self.inner {
ClockInner::Realtime(rt) => rt.now(),
ClockInner::Artificial(clock) => clock.now(),
}
}
pub fn sleep(&self, duration: Duration) -> ClockSleep {
ClockSleep::new(&self.inner, duration)
}
pub fn timeout<F>(&self, duration: Duration, future: F) -> ClockTimeout<F>
where
F: std::future::Future,
{
ClockTimeout::new(&self.inner, duration, future)
}
pub fn is_artificial(&self) -> bool {
matches!(&*self.inner, ClockInner::Artificial(_))
}
#[inline]
pub fn today(&self) -> chrono::NaiveDate {
self.now().date_naive()
}
pub fn artificial_now(&self) -> Option<DateTime<Utc>> {
match &*self.inner {
ClockInner::Realtime(_) => None,
ClockInner::Artificial(clock) => {
if clock.is_realtime() {
None
} else {
Some(clock.now())
}
}
}
}
}
impl std::fmt::Debug for ClockHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &*self.inner {
ClockInner::Realtime(_) => f.debug_struct("ClockHandle::Realtime").finish(),
ClockInner::Artificial(clock) => f
.debug_struct("ClockHandle::Artificial")
.field("now", &clock.now())
.finish(),
}
}
}