use crate::{Clock, Timer};
use futures::future::BoxFuture;
use jiff::Timestamp;
use std::time::Duration;
pub struct WallClock;
impl Clock for WallClock {
fn now(&self) -> Timestamp {
Timestamp::now()
}
}
pub struct TokioTimer;
impl Timer for TokioTimer {
fn sleep(&self, dur: Duration) -> BoxFuture<'static, ()> {
Box::pin(async move {
tokio::time::sleep(dur).await;
})
}
fn next_tick(&self) -> BoxFuture<'static, ()> {
Box::pin(async {
tokio::task::yield_now().await;
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Clock as ClockTrait;
use crate::Timer as TimerTrait;
use std::sync::Arc;
use std::time::Instant;
fn assert_send_sync<T: Send + Sync>() {}
#[test]
fn wall_clock_and_tokio_timer_are_send_sync() {
assert_send_sync::<WallClock>();
assert_send_sync::<TokioTimer>();
}
#[test]
fn now_is_recent() {
let before = Timestamp::now();
let clock = WallClock;
let t = clock.now();
let after = Timestamp::now();
assert!(t >= before - jiff::SignedDuration::from_secs(1));
assert!(t <= after + jiff::SignedDuration::from_secs(1));
}
#[test]
fn now_unix_millis_positive_and_recent() {
let before_ms = Timestamp::now().as_millisecond();
let clock = WallClock;
let ms = clock.now_unix_millis();
let after_ms = Timestamp::now().as_millisecond();
assert!(ms > 0, "unix millis must be positive");
assert!(ms >= before_ms - 100, "must be >= before sample");
assert!(ms <= after_ms + 100, "must be <= after sample");
}
#[tokio::test]
async fn tokio_timer_sleep_completes() {
let timer = TokioTimer;
let start = Instant::now();
timer.sleep(Duration::from_millis(50)).await;
let elapsed = start.elapsed();
assert!(elapsed.as_millis() >= 45, "sleep must take at least 45ms");
assert!(elapsed.as_millis() < 500, "sleep must not take more than 500ms");
}
#[tokio::test]
async fn tokio_timer_next_tick_completes_immediately() {
let timer = TokioTimer;
let start = Instant::now();
timer.next_tick().await;
assert!(start.elapsed().as_millis() < 100);
}
#[test]
fn wall_clock_arc_dyn_dispatch() {
let c: Arc<dyn ClockTrait> = Arc::new(WallClock);
let _ = c.now();
}
#[test]
fn tokio_timer_arc_dyn_dispatch() {
let t: Arc<dyn TimerTrait> = Arc::new(TokioTimer);
let _ = t.sleep(Duration::ZERO);
}
}