• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Allows a future to execute for a maximum amount of time.
2 //!
3 //! See [`Timeout`] documentation for more details.
4 //!
5 //! [`Timeout`]: struct@Timeout
6 
7 use crate::{
8     time::{error::Elapsed, sleep_until, Duration, Instant, Sleep},
9     util::trace,
10 };
11 
12 use pin_project_lite::pin_project;
13 use std::future::Future;
14 use std::pin::Pin;
15 use std::task::{self, Poll};
16 
17 /// Requires a `Future` to complete before the specified duration has elapsed.
18 ///
19 /// If the future completes before the duration has elapsed, then the completed
20 /// value is returned. Otherwise, an error is returned and the future is
21 /// canceled.
22 ///
23 /// # Cancelation
24 ///
25 /// Cancelling a timeout is done by dropping the future. No additional cleanup
26 /// or other work is required.
27 ///
28 /// The original future may be obtained by calling [`Timeout::into_inner`]. This
29 /// consumes the `Timeout`.
30 ///
31 /// # Examples
32 ///
33 /// Create a new `Timeout` set to expire in 10 milliseconds.
34 ///
35 /// ```rust
36 /// use tokio::time::timeout;
37 /// use tokio::sync::oneshot;
38 ///
39 /// use std::time::Duration;
40 ///
41 /// # async fn dox() {
42 /// let (tx, rx) = oneshot::channel();
43 /// # tx.send(()).unwrap();
44 ///
45 /// // Wrap the future with a `Timeout` set to expire in 10 milliseconds.
46 /// if let Err(_) = timeout(Duration::from_millis(10), rx).await {
47 ///     println!("did not receive value within 10 ms");
48 /// }
49 /// # }
50 /// ```
51 #[cfg_attr(tokio_track_caller, track_caller)]
timeout<T>(duration: Duration, future: T) -> Timeout<T> where T: Future,52 pub fn timeout<T>(duration: Duration, future: T) -> Timeout<T>
53 where
54     T: Future,
55 {
56     let location = trace::caller_location();
57 
58     let deadline = Instant::now().checked_add(duration);
59     let delay = match deadline {
60         Some(deadline) => Sleep::new_timeout(deadline, location),
61         None => Sleep::far_future(location),
62     };
63     Timeout::new_with_delay(future, delay)
64 }
65 
66 /// Requires a `Future` to complete before the specified instant in time.
67 ///
68 /// If the future completes before the instant is reached, then the completed
69 /// value is returned. Otherwise, an error is returned.
70 ///
71 /// # Cancelation
72 ///
73 /// Cancelling a timeout is done by dropping the future. No additional cleanup
74 /// or other work is required.
75 ///
76 /// The original future may be obtained by calling [`Timeout::into_inner`]. This
77 /// consumes the `Timeout`.
78 ///
79 /// # Examples
80 ///
81 /// Create a new `Timeout` set to expire in 10 milliseconds.
82 ///
83 /// ```rust
84 /// use tokio::time::{Instant, timeout_at};
85 /// use tokio::sync::oneshot;
86 ///
87 /// use std::time::Duration;
88 ///
89 /// # async fn dox() {
90 /// let (tx, rx) = oneshot::channel();
91 /// # tx.send(()).unwrap();
92 ///
93 /// // Wrap the future with a `Timeout` set to expire 10 milliseconds into the
94 /// // future.
95 /// if let Err(_) = timeout_at(Instant::now() + Duration::from_millis(10), rx).await {
96 ///     println!("did not receive value within 10 ms");
97 /// }
98 /// # }
99 /// ```
timeout_at<T>(deadline: Instant, future: T) -> Timeout<T> where T: Future,100 pub fn timeout_at<T>(deadline: Instant, future: T) -> Timeout<T>
101 where
102     T: Future,
103 {
104     let delay = sleep_until(deadline);
105 
106     Timeout {
107         value: future,
108         delay,
109     }
110 }
111 
112 pin_project! {
113     /// Future returned by [`timeout`](timeout) and [`timeout_at`](timeout_at).
114     #[must_use = "futures do nothing unless you `.await` or poll them"]
115     #[derive(Debug)]
116     pub struct Timeout<T> {
117         #[pin]
118         value: T,
119         #[pin]
120         delay: Sleep,
121     }
122 }
123 
124 impl<T> Timeout<T> {
new_with_delay(value: T, delay: Sleep) -> Timeout<T>125     pub(crate) fn new_with_delay(value: T, delay: Sleep) -> Timeout<T> {
126         Timeout { value, delay }
127     }
128 
129     /// Gets a reference to the underlying value in this timeout.
get_ref(&self) -> &T130     pub fn get_ref(&self) -> &T {
131         &self.value
132     }
133 
134     /// Gets a mutable reference to the underlying value in this timeout.
get_mut(&mut self) -> &mut T135     pub fn get_mut(&mut self) -> &mut T {
136         &mut self.value
137     }
138 
139     /// Consumes this timeout, returning the underlying value.
into_inner(self) -> T140     pub fn into_inner(self) -> T {
141         self.value
142     }
143 }
144 
145 impl<T> Future for Timeout<T>
146 where
147     T: Future,
148 {
149     type Output = Result<T::Output, Elapsed>;
150 
poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output>151     fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
152         let me = self.project();
153 
154         // First, try polling the future
155         if let Poll::Ready(v) = me.value.poll(cx) {
156             return Poll::Ready(Ok(v));
157         }
158 
159         // Now check the timer
160         match me.delay.poll(cx) {
161             Poll::Ready(()) => Poll::Ready(Err(Elapsed::new())),
162             Poll::Pending => Poll::Pending,
163         }
164     }
165 }
166