Skip to main content

nuclei/time/
timeout.rs

1//! [`Timeout`]: a future that gives up on another one at a deadline.
2
3use core::fmt;
4use core::future::Future;
5use core::pin::Pin;
6use core::task::{Context, Poll};
7use std::time::Duration;
8
9use super::Instant;
10
11use super::error::Elapsed;
12use super::sleep::{Sleep, far_future, sleep_until};
13
14/// Runs `future` for at most `duration`: its output, or [`Elapsed`] if the
15/// time ran out first. The future is polled before the clock is looked at,
16/// so one that is ready at once always wins.
17pub fn timeout<F: Future>(duration: Duration, future: F) -> Timeout<F> {
18    timeout_at(
19        Instant::now()
20            .checked_add(duration)
21            .unwrap_or_else(far_future),
22        future,
23    )
24}
25
26/// Runs `future` until `deadline` at most; see [`timeout`].
27pub fn timeout_at<F: Future>(deadline: impl Into<Instant>, future: F) -> Timeout<F> {
28    Timeout {
29        future,
30        sleep: sleep_until(deadline),
31    }
32}
33
34/// A future with a deadline. Made by [`timeout`] and [`timeout_at`].
35#[must_use = "a timeout does nothing unless awaited"]
36pub struct Timeout<F> {
37    future: F,
38    sleep: Sleep,
39}
40
41impl<F> Timeout<F> {
42    /// The future inside.
43    pub fn get_ref(&self) -> &F {
44        &self.future
45    }
46
47    /// The future inside.
48    pub fn get_mut(&mut self) -> &mut F {
49        &mut self.future
50    }
51
52    /// The future inside, without its deadline.
53    pub fn into_inner(self) -> F {
54        self.future
55    }
56}
57
58impl<F: Future> Future for Timeout<F> {
59    type Output = Result<F::Output, Elapsed>;
60
61    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
62        // SAFETY: the future is pinned structurally and never moved out while
63        // pinned; the sleep is `Unpin`.
64        let this = unsafe { self.get_unchecked_mut() };
65        // SAFETY: as above, the future stays where it is.
66        let future = unsafe { Pin::new_unchecked(&mut this.future) };
67        if let Poll::Ready(output) = future.poll(cx) {
68            return Poll::Ready(Ok(output));
69        }
70        Pin::new(&mut this.sleep)
71            .poll(cx)
72            .map(|()| Err(Elapsed::new()))
73    }
74}
75
76impl<F: fmt::Debug> fmt::Debug for Timeout<F> {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        f.debug_struct("Timeout")
79            .field("future", &self.future)
80            .field("deadline", &self.sleep.deadline())
81            .finish()
82    }
83}