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    /// fn main() {
28    ///     async_io::block_on(async {
29    ///         let res = async { "meow" }
30    ///             .delay(Duration::from_millis(100))  // longer delay
31    ///             .timeout(Duration::from_millis(50)) // shorter timeout
32    ///             .await;
33    ///         assert_eq!(res.unwrap_err().kind(), io::ErrorKind::TimedOut); // error
34    ///
35    ///         let res = async { "meow" }
36    ///             .delay(Duration::from_millis(50))    // shorter delay
37    ///             .timeout(Duration::from_millis(100)) // longer timeout
38    ///             .await;
39    ///         assert_eq!(res.unwrap(), "meow"); // success
40    ///     });
41    /// }
42    /// ```
43    fn timeout<D>(self, deadline: D) -> Timeout<Self, D::IntoFuture>
44    where
45        Self: Sized,
46        D: IntoFuture,
47    {
48        Timeout::new(self, deadline.into_future())
49    }
50
51    /// Delay resolving the future until the given deadline.
52    ///
53    /// The underlying future will not be polled until the deadline has expired. In addition
54    /// to using a time source as a deadline, any future can be used as a
55    /// deadline too. When used in combination with a multi-consumer channel,
56    /// this method can be used to synchronize the start of multiple futures and streams.
57    ///
58    /// # Example
59    ///
60    /// ```
61    /// use futures_time::prelude::*;
62    /// use futures_time::time::{Instant, Duration};
63    ///
64    /// fn main() {
65    ///     async_io::block_on(async {
66    ///         let now = Instant::now();
67    ///         let delay = Duration::from_millis(100);
68    ///         let _ = async { "meow" }.delay(delay).await;
69    ///         assert!(now.elapsed() >= *delay);
70    ///     });
71    /// }
72    /// ```
73    fn delay<D>(self, deadline: D) -> Delay<Self, D::IntoFuture>
74    where
75        Self: Sized,
76        D: IntoFuture,
77    {
78        Delay::new(self, deadline.into_future())
79    }
80
81    /// Suspend or resume execution of a future.
82    ///
83    /// When this method is called the execution of the future will be put into
84    /// a suspended state until the channel returns `Parker::Unpark` or the
85    /// channel's senders are dropped. The underlying future will not be polled
86    /// while the it is paused.
87    fn park<I>(self, interval: I) -> Park<Self, I::IntoStream>
88    where
89        Self: Sized,
90        I: IntoStream<Item = Parker>,
91    {
92        Park::new(self, interval.into_stream())
93    }
94}
95
96impl<T> FutureExt for T where T: Future {}