use std::{future::Future, pin::Pin, time::Duration};
use chrono::{DateTime, TimeDelta, Utc};
use tokio::time::{sleep, sleep_until, Instant};
use super::{Clock, ClockBase};
#[derive(Debug, Clone)]
pub struct TrueClock;
impl TrueClock {
pub fn new() -> Self {
Self {}
}
}
impl Default for TrueClock {
fn default() -> Self {
Self::new()
}
}
impl ClockBase for TrueClock {
fn now(&self) -> DateTime<Utc> {
Utc::now()
}
}
impl Clock for TrueClock {
fn sleep(&self, delay: TimeDelta) -> Pin<Box<dyn Future<Output = ()> + Send>> {
tracing::trace!("Sleeping for {}", delay.to_string());
Box::pin(sleep(
Duration::from_millis(delay.num_milliseconds() as u64),
))
}
fn sleep_until(&self, deadline: DateTime<Utc>) -> Pin<Box<dyn Future<Output = ()> + Send>> {
tracing::trace!("Sleeping until {}", deadline.to_string());
Box::pin(sleep_until(
Instant::now()
+ deadline
.signed_duration_since(Utc::now())
.to_std()
.unwrap_or_default(),
))
}
fn clone_box(&self) -> Box<dyn Clock> {
Box::new(Self::new())
}
fn synchronize(&self) {}
}
#[cfg(test)]
mod tests {
use chrono::{TimeDelta, Utc};
use super::{Clock as _, ClockBase as _, TrueClock};
const TOLERANCE: TimeDelta = TimeDelta::milliseconds(10);
const DELAY: TimeDelta = TimeDelta::milliseconds(100);
#[tokio::test]
async fn true_clock() {
let clock = TrueClock::new();
assert!(clock.now() - Utc::now() < TOLERANCE);
let before = Utc::now();
clock.sleep(DELAY).await;
let after = Utc::now();
assert!(after - before > DELAY - TOLERANCE);
assert!(after - before < DELAY + TOLERANCE);
assert!(clock.now() - Utc::now() < TOLERANCE);
}
}