Skip to main content

duckduckgo_core/
clock.rs

1use std::future::Future;
2use std::pin::Pin;
3use std::sync::{Arc, Mutex};
4use std::time::Duration;
5
6use time::OffsetDateTime;
7
8pub type SharedClock = Arc<dyn Clock>;
9
10pub trait Clock: Send + Sync + 'static {
11    fn now(&self) -> OffsetDateTime;
12
13    fn sleep<'a>(&'a self, duration: Duration) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
14}
15
16#[derive(Clone, Copy, Debug, Default)]
17pub struct SystemClock;
18
19impl Clock for SystemClock {
20    fn now(&self) -> OffsetDateTime {
21        OffsetDateTime::now_utc()
22    }
23
24    fn sleep<'a>(&'a self, duration: Duration) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
25        Box::pin(tokio::time::sleep(duration))
26    }
27}
28
29#[derive(Debug)]
30pub struct ManualClock {
31    now: Mutex<OffsetDateTime>,
32}
33
34impl ManualClock {
35    pub fn new(now: OffsetDateTime) -> Self {
36        Self {
37            now: Mutex::new(now),
38        }
39    }
40
41    pub fn advance(&self, duration: Duration) {
42        let delta = time::Duration::try_from(duration).unwrap_or(time::Duration::MAX);
43        let mut now = self.now.lock().expect("manual clock mutex poisoned");
44        *now += delta;
45    }
46
47    pub fn now(&self) -> OffsetDateTime {
48        *self.now.lock().expect("manual clock mutex poisoned")
49    }
50}
51
52impl Clock for ManualClock {
53    fn now(&self) -> OffsetDateTime {
54        Self::now(self)
55    }
56
57    fn sleep<'a>(&'a self, duration: Duration) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
58        Box::pin(async move {
59            self.advance(duration);
60            tokio::task::yield_now().await;
61        })
62    }
63}