async_std/future/
timeout.rs

1use std::error::Error;
2use std::fmt;
3use std::future::Future;
4use std::pin::Pin;
5use std::time::Duration;
6
7use pin_project_lite::pin_project;
8
9use crate::task::{Context, Poll};
10use crate::utils::{timer_after, Timer};
11
12/// Awaits a future or times out after a duration of time.
13///
14/// If you want to await an I/O future consider using
15/// [`io::timeout`](../io/fn.timeout.html) instead.
16///
17/// # Examples
18///
19/// ```
20/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
21/// #
22/// use std::time::Duration;
23///
24/// use async_std::future;
25///
26/// let never = future::pending::<()>();
27/// let dur = Duration::from_millis(5);
28/// assert!(future::timeout(dur, never).await.is_err());
29/// #
30/// # Ok(()) }) }
31/// ```
32pub async fn timeout<F, T>(dur: Duration, f: F) -> Result<T, TimeoutError>
33where
34    F: Future<Output = T>,
35{
36    TimeoutFuture::new(f, dur).await
37}
38
39pin_project! {
40    /// A future that times out after a duration of time.
41    pub struct TimeoutFuture<F> {
42        #[pin]
43        future: F,
44        #[pin]
45        delay: Timer,
46    }
47}
48
49impl<F> TimeoutFuture<F> {
50    #[allow(dead_code)]
51    pub(super) fn new(future: F, dur: Duration) -> TimeoutFuture<F> {
52        TimeoutFuture {
53            future,
54            delay: timer_after(dur),
55        }
56    }
57}
58
59impl<F: Future> Future for TimeoutFuture<F> {
60    type Output = Result<F::Output, TimeoutError>;
61
62    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
63        let this = self.project();
64        match this.future.poll(cx) {
65            Poll::Ready(v) => Poll::Ready(Ok(v)),
66            Poll::Pending => match this.delay.poll(cx) {
67                Poll::Ready(_) => Poll::Ready(Err(TimeoutError { _private: () })),
68                Poll::Pending => Poll::Pending,
69            },
70        }
71    }
72}
73
74/// An error returned when a future times out.
75#[derive(Clone, Copy, Debug, Eq, PartialEq)]
76pub struct TimeoutError {
77    _private: (),
78}
79
80impl Error for TimeoutError {}
81
82impl fmt::Display for TimeoutError {
83    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84        "future has timed out".fmt(f)
85    }
86}