Skip to main content

cratefield_runtime_native/ports/
clock.rs

1//! `Clock` over the system clock, `timeout_any` over `tokio::time` —
2//! the native counterpart of `WorkersClock` (which races `worker::Delay`
3//! because workerd has no tokio timer).
4
5use async_trait::async_trait;
6use futures_core::future::BoxFuture;
7use std::any::Any;
8use std::time::Duration;
9
10/// The system clock on tokio. `now()` reads the wall clock through the
11/// `time` crate (the same path core's `SystemClock` uses, never
12/// `std::time` directly); `timeout_any` abandons the future with
13/// `tokio::time::timeout`, which this runtime can always supply.
14#[derive(Debug, Clone, Copy, Default)]
15pub struct TokioClock;
16
17#[async_trait]
18impl cratefield_core::Clock for TokioClock {
19    fn now(&self) -> time::OffsetDateTime {
20        time::OffsetDateTime::now_utc()
21    }
22
23    async fn timeout_any(
24        &self,
25        fut: BoxFuture<'static, Box<dyn Any + Send>>,
26        after: Duration,
27    ) -> Option<Box<dyn Any + Send>> {
28        tokio::time::timeout(after, fut).await.ok()
29    }
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35    use cratefield_core::Clock as _;
36
37    #[tokio::test]
38    async fn timeout_abandons_a_slow_future() {
39        let slow: BoxFuture<'static, Box<dyn Any + Send>> = Box::pin(async {
40            tokio::time::sleep(Duration::from_secs(30)).await;
41            Box::new(()) as Box<dyn Any + Send>
42        });
43        let started = std::time::Instant::now();
44        let out = TokioClock
45            .timeout_any(slow, Duration::from_millis(20))
46            .await;
47        assert!(out.is_none());
48        assert!(
49            started.elapsed() < Duration::from_secs(5),
50            "abandoned, not awaited"
51        );
52    }
53
54    #[tokio::test]
55    async fn timeout_returns_a_fast_future() {
56        let fast: BoxFuture<'static, Box<dyn Any + Send>> =
57            Box::pin(async { Box::new(7_u32) as Box<dyn Any + Send> });
58        let out = TokioClock.timeout_any(fast, Duration::from_secs(5)).await;
59        let value = out
60            .and_then(|any| any.downcast::<u32>().ok())
61            .map(|boxed| *boxed);
62        assert_eq!(value, Some(7));
63    }
64}