//! Allows a future to execute for a maximum amount of time. //! //! See [`Timeout`] documentation for more details. //! //! [`Timeout`]: struct@Timeout use std::{ future::Future, pin::Pin, task::{self, Poll}, }; use pin_project_lite::pin_project; use crate::time::{error::Elapsed, sleep_until, Duration, Instant, Sleep}; /// Require a `Future` to complete before the specified duration has elapsed. /// /// If the future completes before the duration has elapsed, then the completed /// value is returned. Otherwise, an error is returned and the future is /// canceled. /// /// # Cancelation /// /// Cancelling a timeout is done by dropping the future. No additional cleanup /// or other work is required. /// /// The original future may be obtained by calling [`Timeout::into_inner`]. This /// consumes the `Timeout`. pub fn timeout(duration: Duration, future: T) -> Timeout where T: Future, { let deadline = Instant::now().checked_add(duration); let delay = match deadline { Some(deadline) => Sleep::new_timeout(deadline), None => Sleep::far_future(), }; Timeout::new_with_delay(future, delay) } /// Require a `Future` to complete before the specified instant in time. /// /// If the future completes before the instant is reached, then the completed /// value is returned. Otherwise, an error is returned. /// /// # Cancelation /// /// Cancelling a timeout is done by dropping the future. No additional cleanup /// or other work is required. /// /// The original future may be obtained by calling [`Timeout::into_inner`]. This /// consumes the `Timeout`. pub fn timeout_at(deadline: Instant, future: T) -> Timeout where T: Future, { let delay = sleep_until(deadline); Timeout { value: future, delay, } } pin_project! { /// Future returned by [`timeout`](timeout) and [`timeout_at`](timeout_at). #[must_use = "futures do nothing unless you `.await` or poll them"] #[derive(Debug)] pub struct Timeout { #[pin] value: T, #[pin] delay: Sleep, } } impl Timeout { pub(crate) fn new_with_delay(value: T, delay: Sleep) -> Timeout { Timeout { value, delay } } /// Gets a reference to the underlying value in this timeout. pub fn get_ref(&self) -> &T { &self.value } /// Gets a mutable reference to the underlying value in this timeout. pub fn get_mut(&mut self) -> &mut T { &mut self.value } /// Consumes this timeout, returning the underlying value. pub fn into_inner(self) -> T { self.value } } impl Future for Timeout where T: Future, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll { let me = self.project(); // First, try polling the future if let Poll::Ready(v) = me.value.poll(cx) { return Poll::Ready(Ok(v)); } // Now check the timer match me.delay.poll(cx) { Poll::Ready(()) => Poll::Ready(Err(Elapsed::new())), Poll::Pending => Poll::Pending, } } }