use std::{fmt::Debug, time::Duration};
#[cfg(feature = "bevy_runtime_018")]
use bevy_tasks_018 as bevy_tasks;
#[derive(Debug)]
pub struct Elapsed;
pub trait TimeInterface {
type Elapsed: Debug;
fn sleep(duration: Duration) -> impl Future<Output = ()> + Send;
fn timeout<T>(
duration: Duration,
future: impl Future<Output = T> + Send,
) -> impl Future<Output = Result<T, Self::Elapsed>> + Send;
}
#[cfg(any(feature = "futures_runtime", feature = "bevy_runtime"))]
async fn futures_impl<T, RT: TimeInterface>(
duration: Duration,
future: impl Future<Output = T> + Send,
) -> Result<T, Elapsed> {
let sleep = RT::sleep(duration);
futures::pin_mut!(sleep);
futures::pin_mut!(future);
match futures::future::select(sleep, future).await {
futures::future::Either::Left(_) => Err(Elapsed),
futures::future::Either::Right((v, _)) => Ok(v),
}
}
#[cfg(feature = "futures_runtime")]
impl TimeInterface for crate::futures::Runtime {
type Elapsed = Elapsed;
async fn sleep(duration: std::time::Duration) {
async_io::Timer::after(duration).await;
}
fn timeout<T>(
duration: Duration,
future: impl Future<Output = T> + Send,
) -> impl Future<Output = Result<T, Self::Elapsed>> + Send {
futures_impl::<T, Self>(duration, future)
}
}
#[cfg(feature = "tokio_runtime")]
impl TimeInterface for crate::tokio::Runtime {
type Elapsed = tokio::time::error::Elapsed;
fn sleep(duration: std::time::Duration) -> impl Future<Output = ()> + Send {
tokio::time::sleep(duration)
}
fn timeout<T>(
duration: Duration,
future: impl Future<Output = T> + Send,
) -> impl Future<Output = Result<T, Self::Elapsed>> + Send {
tokio::time::timeout(duration, future)
}
}
#[cfg(any(feature = "bevy_runtime", feature = "bevy_runtime_018"))]
impl<TP> TimeInterface for crate::bevy::Runtime<TP>
where
TP: std::ops::Deref<Target = bevy_tasks::TaskPool> + Sync + 'static,
{
type Elapsed = Elapsed;
async fn sleep(duration: std::time::Duration) {
async_io::Timer::after(duration).await;
}
fn timeout<T>(
duration: Duration,
future: impl Future<Output = T> + Send,
) -> impl Future<Output = Result<T, Self::Elapsed>> + Send {
futures_impl::<T, Self>(duration, future)
}
}
#[cfg(test)]
mod test {
use crate::common;
use super::TimeInterface;
use crate::{Config, CreationInterface};
fn test_full_runtime<RT: CreationInterface + TimeInterface>() {
let rt = RT::new(Config::new().prefix("test")).unwrap();
common::test_sleep(&rt);
common::test_timeout(&rt);
}
#[cfg(feature = "futures_runtime")]
#[test]
fn test_futures() {
test_full_runtime::<crate::futures::Runtime>();
}
#[cfg(feature = "tokio_runtime")]
#[test]
fn test_tokio() {
test_full_runtime::<crate::tokio::Runtime>();
}
}