use core::time::Duration;
use future_form::FutureForm;
#[cfg(feature = "futures-timer")]
use future_form::{Local, Sendable};
use thiserror::Error;
#[cfg(feature = "futures-timer")]
use futures::{
FutureExt,
future::{BoxFuture, Either, LocalBoxFuture, select},
};
#[cfg(feature = "futures-timer")]
use futures_timer::Delay;
pub trait Timeout<K: FutureForm + ?Sized> {
fn timeout<'a, T: 'a>(
&'a self,
dur: Duration,
fut: K::Future<'a, T>,
) -> K::Future<'a, Result<T, TimedOut>>;
}
#[derive(Debug, Clone, Copy, Error, PartialEq, Eq, Hash)]
#[error("Operation timed out")]
pub struct TimedOut;
#[cfg(feature = "futures-timer")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FuturesTimerTimeout;
#[cfg(feature = "futures-timer")]
impl Timeout<Local> for FuturesTimerTimeout {
fn timeout<'a, T: 'a>(
&'a self,
dur: Duration,
fut: LocalBoxFuture<'a, T>,
) -> LocalBoxFuture<'a, Result<T, TimedOut>> {
async move {
match select(fut, Delay::new(dur)).await {
Either::Left((val, _delay)) => Ok(val),
Either::Right(_) => Err(TimedOut),
}
}
.boxed_local()
}
}
#[cfg(feature = "futures-timer")]
impl Timeout<Sendable> for FuturesTimerTimeout {
fn timeout<'a, T: 'a>(
&'a self,
dur: Duration,
fut: BoxFuture<'a, T>,
) -> BoxFuture<'a, Result<T, TimedOut>> {
async move {
match select(fut, Delay::new(dur)).await {
Either::Left((val, _delay)) => Ok(val),
Either::Right(_) => Err(TimedOut),
}
}
.boxed()
}
}