diff --git a/src/io/timeout.rs b/src/io/timeout.rs index 2d1b29e7..69b6892c 100644 --- a/src/io/timeout.rs +++ b/src/io/timeout.rs @@ -1,6 +1,9 @@ +use std::pin::Pin; +use std::task::{Context, Poll}; use std::time::Duration; -use futures_timer::TryFutureExt; +use futures_core::future::TryFuture; +use futures_timer::Delay; use crate::future::Future; use crate::io; @@ -33,5 +36,48 @@ pub async fn timeout(dur: Duration, f: F) -> io::Result where F: Future>, { - f.timeout(dur).await + let f = TimeoutFuture { + timeout: Delay::new(dur), + future: f, + }; + f.await +} + +// Future returned by the [`io::timeout`](./fn.timeout.html) function. +#[derive(Debug)] +pub struct TimeoutFuture +where + F: Future>, +{ + future: F, + timeout: Delay, +} + +impl TimeoutFuture +where + F: Future>, +{ + pin_utils::unsafe_pinned!(future: F); + pin_utils::unsafe_pinned!(timeout: Delay); +} + +impl Future for TimeoutFuture +where + F: Future>, +{ + type Output = io::Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match self.as_mut().future().try_poll(cx) { + Poll::Pending => {} + other => return other, + } + + if self.timeout().poll(cx).is_ready() { + let err = Err(io::Error::new(io::ErrorKind::TimedOut, "future timed out").into()); + Poll::Ready(err) + } else { + Poll::Pending + } + } }