Skip to main content

relay_server/utils/
sleep_handle.rs

1use std::future::Future;
2use std::pin::Pin;
3use std::task::Poll;
4use std::time::Duration;
5
6use futures::FutureExt;
7use futures::future::FusedFuture;
8
9/// A future wrapper around [`tokio::time::Sleep`].
10///
11/// When initialized with [`SleepHandle::idle`], this future is pending indefinitely every time it
12/// is polled. To initiate a delay, use [`set`](Self::set). After the delay has passed, the future
13/// resolves with `()` **exactly once** and resets to idle. To reset the future while it is
14/// sleeping, use [`reset`](Self::reset).
15#[derive(Debug)]
16pub struct SleepHandle(Option<Pin<Box<tokio::time::Sleep>>>);
17
18impl SleepHandle {
19    /// Creates [`SleepHandle`] and sets its internal state to an indefinitely pending future.
20    pub fn idle() -> Self {
21        Self(None)
22    }
23
24    /// Resets the internal state to an indefinitely pending future.
25    pub fn reset(&mut self) {
26        self.0 = None;
27    }
28
29    /// Sets the internal state to a future that will yield after `duration` time has elapsed.
30    pub fn set(&mut self, duration: Duration) {
31        self.0 = Some(Box::pin(tokio::time::sleep(duration)));
32    }
33
34    /// Primes the internal state like [`Self::set`], only if currently [`Self::idle`].
35    pub fn set_if_idle(&mut self, duration: Duration) {
36        if self.is_idle() {
37            self.set(duration)
38        }
39    }
40
41    /// Checks whether the internal state is currently pending indefinite.
42    pub fn is_idle(&self) -> bool {
43        self.0.is_none()
44    }
45}
46
47impl Future for SleepHandle {
48    type Output = ();
49
50    fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
51        let poll = match &mut self.0 {
52            Some(sleep) => sleep.poll_unpin(cx),
53            None => Poll::Pending,
54        };
55
56        if poll.is_ready() {
57            self.reset();
58        }
59
60        poll
61    }
62}
63
64impl FusedFuture for SleepHandle {
65    fn is_terminated(&self) -> bool {
66        // The handle never terminates, it may be reset or primed at any time.
67        false
68    }
69}