Skip to main content

blockz_futures/
timeout.rs

1//! Futures constrained by time.
2
3use std::future::Future;
4use std::pin::Pin;
5use std::task::Context;
6use std::task::Poll;
7use std::time::Duration;
8use std::time::Instant;
9
10use thiserror::Error;
11
12/// Error type for futures that ran out of time.
13#[derive(Clone, Copy, Debug, Error)]
14#[error("future timed out")]
15pub struct TimedOut(());
16
17/// A future that must complete in a certain time interval.
18#[pin_project]
19pub struct Timeout<F> {
20    #[pin]
21    future: tokio::time::Timeout<F>,
22}
23
24impl<F: Future> Timeout<F> {
25    /// Create a new `Timeout` future.
26    pub fn new(future: F, timeout: Duration) -> Self {
27        Self {
28            future: tokio::time::timeout(timeout, future),
29        }
30    }
31}
32
33impl<F: Future> Future for Timeout<F> {
34    type Output = Result<F::Output, TimedOut>;
35
36    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
37        let this = self.project();
38        let future: Pin<&mut tokio::time::Timeout<F>> = this.future;
39
40        if let Poll::Ready(result) = future.poll(cx) {
41            match result {
42                Ok(out) => Poll::Ready(Ok(out)),
43                Err(_) => Poll::Ready(Err(TimedOut(()))),
44            }
45        } else {
46            Poll::Pending
47        }
48    }
49}
50
51/// A future that must complete before a moment in time.
52#[pin_project]
53pub struct Deadline<F> {
54    #[pin]
55    future: tokio::time::Timeout<F>,
56}
57
58impl<F: Future> Deadline<F> {
59    /// Create a new `Deadline` future.
60    pub fn new(future: F, deadline: Instant) -> Self {
61        Self {
62            future: tokio::time::timeout_at(deadline.into(), future),
63        }
64    }
65}
66
67impl<F: Future> Future for Deadline<F> {
68    type Output = Result<F::Output, TimedOut>;
69
70    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
71        let this = self.project();
72        let future: Pin<&mut tokio::time::Timeout<F>> = this.future;
73
74        if let Poll::Ready(result) = future.poll(cx) {
75            match result {
76                Ok(out) => Poll::Ready(Ok(out)),
77                Err(_) => Poll::Ready(Err(TimedOut(()))),
78            }
79        } else {
80            Poll::Pending
81        }
82    }
83}