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(future: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: Projection<'_, F> = self.project();
64 match this.future.poll(cx) {
65 Poll::Ready(v: ::Output) => 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}
87