use chrono::{DateTime, Utc};
use std::{sync::Arc, time::Duration};
use super::{
controller::ClockController,
inner::ClockInner,
manual::ManualClock,
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 manual() -> (Self, ClockController) {
let clock = Arc::new(ManualClock::new());
let handle = Self {
inner: Arc::new(ClockInner::Manual(Arc::clone(&clock))),
};
let controller = ClockController { clock };
(handle, controller)
}
pub fn manual_at(start_at: DateTime<Utc>) -> (Self, ClockController) {
let clock = Arc::new(ManualClock::new_at(start_at));
let handle = Self {
inner: Arc::new(ClockInner::Manual(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::Manual(clock) => clock.now(),
}
}
pub fn sleep(&self, duration: Duration) -> ClockSleep {
ClockSleep::new(&self.inner, duration)
}
pub fn sleep_coalesce(&self, duration: Duration) -> ClockSleep {
ClockSleep::new_coalesceable(&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_manual(&self) -> bool {
matches!(&*self.inner, ClockInner::Manual(_))
}
#[inline]
pub fn today(&self) -> chrono::NaiveDate {
self.now().date_naive()
}
pub fn manual_now(&self) -> Option<DateTime<Utc>> {
match &*self.inner {
ClockInner::Realtime(_) => None,
ClockInner::Manual(clock) => 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::Manual(clock) => f
.debug_struct("ClockHandle::Manual")
.field("now", &clock.now())
.finish(),
}
}
}