futures_time/future/
future_ext.rs

1use core::future::Future;
2
3use crate::channel::Parker;
4use crate::stream::IntoStream;
5
6use super::{Delay, IntoFuture, Park, Timeout};
7
8/// Extend `Future` with time-based operations.
9pub trait FutureExt: Future {
10    /// Return an error if a future does not complete within a given time span.
11    ///
12    /// Typically timeouts are, as the name implies, based on _time_. However
13    /// this method can time out based on any future. This can be useful in
14    /// combination with channels, as it allows (long-lived) futures to be
15    /// cancelled based on some external event.
16    ///
17    /// When a timeout is returned, the future will be dropped and destructors
18    /// will be run.
19    ///
20    /// # Example
21    ///
22    /// ```
23    /// use futures_time::prelude::*;
24    /// use futures_time::time::{Instant, Duration};
25    /// use std::io;
26    ///
27    /// async_io::block_on(async {
28    ///     let res = async { "meow" }
29    ///         .delay(Duration::from_millis(100))  // longer delay
30    ///         .timeout(Duration::from_millis(50)) // shorter timeout
31    ///         .await;
32    ///     assert_eq!(res.unwrap_err().kind(), io::ErrorKind::TimedOut); // error
33    ///
34    ///     let res = async { "meow" }
35    ///         .delay(Duration::from_millis(50))    // shorter delay
36    ///         .timeout(Duration::from_millis(100)) // longer timeout
37    ///         .await;
38    ///     assert_eq!(res.unwrap(), "meow"); // success
39    /// });
40    /// ```
41    fn timeout<D>(self, deadline: D) -> Timeout<Self, D::IntoFuture>
42    where
43        Self: Sized,
44        D: IntoFuture,
45    {
46        Timeout::new(self, deadline.into_future())
47    }
48
49    /// Delay resolving the future until the given deadline.
50    ///
51    /// The underlying future will not be polled until the deadline has expired. In addition
52    /// to using a time source as a deadline, any future can be used as a
53    /// deadline too. When used in combination with a multi-consumer channel,
54    /// this method can be used to synchronize the start of multiple futures and streams.
55    ///
56    /// # Example
57    ///
58    /// ```
59    /// use futures_time::prelude::*;
60    /// use futures_time::time::{Instant, Duration};
61    ///
62    /// async_io::block_on(async {
63    ///     let now = Instant::now();
64    ///     let delay = Duration::from_millis(100);
65    ///     let _ = async { "meow" }.delay(delay).await;
66    ///     assert!(now.elapsed() >= *delay);
67    /// });
68    /// ```
69    fn delay<D>(self, deadline: D) -> Delay<Self, D::IntoFuture>
70    where
71        Self: Sized,
72        D: IntoFuture,
73    {
74        Delay::new(self, deadline.into_future())
75    }
76
77    /// Suspend or resume execution of a future.
78    ///
79    /// When this method is called the execution of the future will be put into
80    /// a suspended state until the channel returns `Parker::Unpark` or the
81    /// channel's senders are dropped. The underlying future will not be polled
82    /// while the it is paused.
83    fn park<I>(self, interval: I) -> Park<Self, I::IntoStream>
84    where
85        Self: Sized,
86        I: IntoStream<Item = Parker>,
87    {
88        Park::new(self, interval.into_stream())
89    }
90}
91
92impl<T> FutureExt for T where T: Future {}