1 | use std::error::Error; |
2 | use std::fmt; |
3 | use std::future::Future; |
4 | use std::pin::Pin; |
5 | use std::time::Duration; |
6 | |
7 | use pin_project_lite::pin_project; |
8 | |
9 | use crate::task::{Context, Poll}; |
10 | use 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 | /// ``` |
32 | pub async fn timeout<F, T>(dur: Duration, f: F) -> Result<T, TimeoutError> |
33 | where |
34 | F: Future<Output = T>, |
35 | { |
36 | TimeoutFuture::new(future:f, dur).await |
37 | } |
38 | |
39 | pin_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 | |
49 | impl<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 | |
59 | impl<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)] |
76 | pub struct TimeoutError { |
77 | _private: (), |
78 | } |
79 | |
80 | impl Error for TimeoutError {} |
81 | |
82 | impl fmt::Display for TimeoutError { |
83 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
84 | "future has timed out" .fmt(f) |
85 | } |
86 | } |
87 | |