use async_trait::async_trait;
use futures_core::future::BoxFuture;
use std::any::Any;
use std::time::Duration;
#[async_trait]
pub trait Clock: Send + Sync {
fn now(&self) -> time::OffsetDateTime;
async fn timeout_any(
&self,
fut: BoxFuture<'static, Box<dyn Any + Send>>,
after: Duration,
) -> Option<Box<dyn Any + Send>> {
let _ = after;
Some(fut.await)
}
}
pub async fn timeout<T: Send + 'static>(
clock: &dyn Clock,
fut: impl Future<Output = T> + Send + 'static,
after: Duration,
) -> Option<T> {
let boxed: BoxFuture<'static, Box<dyn Any + Send>> =
Box::pin(async move { Box::new(fut.await) as Box<dyn Any + Send> });
match clock.timeout_any(boxed, after).await {
Some(any) => any.downcast::<T>().ok().map(|v| *v),
None => None,
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct SystemClock;
#[async_trait]
impl Clock for SystemClock {
fn now(&self) -> time::OffsetDateTime {
time::OffsetDateTime::now_utc()
}
}