use
{
std :: { time::Duration, future::Future, task::{ Poll, Context }, pin::Pin } ,
futures_core :: { future::BoxFuture } ,
pin_project::pin_project,
};
#[ blanket::blanket( derive( Ref, Mut, Rc, Arc, Box ) ) ]
pub trait Timer
{
#[ must_use = "sleep() returns a future, which does nothing unless awaited" ]
fn sleep( &self, dur: Duration ) -> BoxFuture<'static, ()>;
}
pub trait TimerExt: Timer
{
#[ must_use = "timeout() returns a future, which does nothing unless awaited." ]
fn timeout<F: Future>( &self, duration: Duration, future: F ) -> Timeout<F>
{
let sleep_future = self.sleep( duration );
Timeout { future, sleep_future }
}
}
impl<T: Timer> TimerExt for T {}
#[ derive( Copy, Clone, Debug, Eq, PartialEq ) ]
#[allow(clippy::exhaustive_structs)]
pub struct TimeoutError;
impl std::error::Error for TimeoutError {}
impl std::fmt::Display for TimeoutError
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
write!( f, "Timeout expired" )
}
}
impl From<TimeoutError> for std::io::Error
{
fn from( err: TimeoutError ) -> std::io::Error
{
std::io::Error::new( std::io::ErrorKind::TimedOut, err )
}
}
#[pin_project]
pub struct Timeout<T>
{
#[pin] future: T,
sleep_future: BoxFuture<'static, ()>,
}
impl<T> Future for Timeout<T>
where T: Future,
{
type Output = Result< T::Output, TimeoutError >;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>
{
let this = self.project();
if let Poll::Ready(x) = this.future.poll(cx)
{
return Poll::Ready(Ok(x));
}
match this.sleep_future.as_mut().poll(cx)
{
Poll::Pending => Poll::Pending ,
Poll::Ready(()) => Poll::Ready( Err(TimeoutError) ) ,
}
}
}
impl<T> std::fmt::Debug for Timeout<T>
{
fn fmt( &self, f: &mut std::fmt::Formatter<'_> ) -> std::fmt::Result
{
write!( f, "Timeout future" )
}
}