use chrono::{DateTime, TimeDelta, Utc};
use std::time::Duration;
use tokio::time::{Instant, sleep, sleep_until};
use crate::{
clock::{ClockFactory, NoRemote},
core::CoreResult,
};
use super::{Clock, ClockBase};
pub struct TrueClockFactory {}
impl ClockFactory for TrueClockFactory {
type _Clock = TrueClock;
fn build(self) -> CoreResult<(Option<NoRemote>, TrueClock)> {
Ok((None, TrueClock::new()))
}
}
#[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 {
const NAME: &'static str = "TrueClock";
fn now(&self) -> DateTime<Utc> {
Utc::now()
}
}
impl Clock for TrueClock {
type Remote = NoRemote;
async fn sleep(&self, delay: TimeDelta) {
tracing::trace!("Sleeping for {}", delay.to_string());
sleep(Duration::from_millis(delay.num_milliseconds() as u64)).await
}
async fn sleep_until(&self, deadline: DateTime<Utc>) {
tracing::trace!("Sleeping until {}", deadline.to_string());
sleep_until(
Instant::now()
+ deadline
.signed_duration_since(Utc::now())
.to_std()
.unwrap_or_default(),
)
.await
}
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);
}
}