monoio/time/driver/
sleep.rs

1use std::{
2    future::Future,
3    pin::Pin,
4    task::{self, Poll},
5};
6
7use pin_project_lite::pin_project;
8
9use crate::time::{
10    driver::{Handle, TimerEntry},
11    error::Error,
12    Duration, Instant,
13};
14
15/// Waits until `deadline` is reached.
16///
17/// No work is performed while awaiting on the sleep future to complete. `Sleep`
18/// operates at millisecond granularity and should not be used for tasks that
19/// require high-resolution timers.
20///
21/// To run something regularly on a schedule, see [`interval`].
22///
23/// # Cancellation
24///
25/// Canceling a sleep instance is done by dropping the returned future. No
26/// additional cleanup work is required.
27///
28/// # Examples
29///
30/// Wait 100ms and print "100 ms have elapsed".
31///
32/// ```
33/// use monoio::time::{sleep_until, Duration, Instant};
34///
35/// #[monoio::main(timer_enabled = true)]
36/// async fn main() {
37///     sleep_until(Instant::now() + Duration::from_millis(100)).await;
38///     println!("100 ms have elapsed");
39/// }
40/// ```
41///
42/// See the documentation for the [`Sleep`] type for more examples.
43///
44/// [`Sleep`]: struct@crate::time::Sleep
45/// [`interval`]: crate::time::interval()
46// Alias for old name in 0.x
47#[cfg_attr(docsrs, doc(alias = "delay_until"))]
48pub fn sleep_until(deadline: Instant) -> Sleep {
49    Sleep::new_timeout(deadline)
50}
51
52/// Waits until `duration` has elapsed.
53///
54/// Equivalent to `sleep_until(Instant::now() + duration)`. An asynchronous
55/// analog to `std::thread::sleep`.
56///
57/// No work is performed while awaiting on the sleep future to complete. `Sleep`
58/// operates at millisecond granularity and should not be used for tasks that
59/// require high-resolution timers.
60///
61/// To run something regularly on a schedule, see [`interval`].
62///
63/// The maximum duration for a sleep is 68719476734 milliseconds (approximately
64/// 2.2 years).
65///
66/// # Cancellation
67///
68/// Canceling a sleep instance is done by dropping the returned future. No
69/// additional cleanup work is required.
70///
71/// # Examples
72///
73/// Wait 100ms and print "100 ms have elapsed".
74///
75/// ```
76/// use monoio::time::{sleep, Duration};
77///
78/// #[monoio::main(timer_enabled = true)]
79/// async fn main() {
80///     sleep(Duration::from_millis(100)).await;
81///     println!("100 ms have elapsed");
82/// }
83/// ```
84///
85/// See the documentation for the [`Sleep`] type for more examples.
86///
87/// [`Sleep`]: struct@crate::time::Sleep
88/// [`interval`]: crate::time::interval()
89// Alias for old name in 0.x
90#[cfg_attr(docsrs, doc(alias = "delay_for"))]
91#[cfg_attr(docsrs, doc(alias = "wait"))]
92pub fn sleep(duration: Duration) -> Sleep {
93    match Instant::now().checked_add(duration) {
94        Some(deadline) => sleep_until(deadline),
95        None => sleep_until(Instant::far_future()),
96    }
97}
98
99pin_project! {
100    /// Future returned by [`sleep`](sleep) and [`sleep_until`](sleep_until).
101    ///
102    /// This type does not implement the `Unpin` trait, which means that if you
103    /// use it with [`select!`] or by calling `poll`, you have to pin it first.
104    /// If you use it with `.await`, this does not apply.
105    ///
106    /// # Examples
107    ///
108    /// Wait 100ms and print "100 ms have elapsed".
109    ///
110    /// ```
111    /// use monoio::time::{sleep, Duration};
112    ///
113    /// #[monoio::main(timer_enabled = true)]
114    /// async fn main() {
115    ///     sleep(Duration::from_millis(100)).await;
116    ///     println!("100 ms have elapsed");
117    /// }
118    /// ```
119    ///
120    /// Use with [`select!`]. Pinning the `Sleep` with [`monoio::pin!`] is
121    /// necessary when the same `Sleep` is selected on multiple times.
122    /// ```no_run
123    /// use monoio::time::{self, Duration, Instant};
124    ///
125    /// #[monoio::main(timer_enabled = true)]
126    /// async fn main() {
127    ///     let sleep = time::sleep(Duration::from_millis(10));
128    ///     monoio::pin!(sleep);
129    ///
130    ///     loop {
131    ///         monoio::select! {
132    ///             () = &mut sleep => {
133    ///                 println!("timer elapsed");
134    ///                 sleep.as_mut().reset(Instant::now() + Duration::from_millis(50));
135    ///             },
136    ///         }
137    ///     }
138    /// }
139    /// ```
140    /// Use in a struct with boxing. By pinning the `Sleep` with a `Box`, the
141    /// `HasSleep` struct implements `Unpin`, even though `Sleep` does not.
142    /// ```
143    /// use std::future::Future;
144    /// use std::pin::Pin;
145    /// use std::task::{Context, Poll};
146    /// use monoio::time::Sleep;
147    ///
148    /// struct HasSleep {
149    ///     sleep: Pin<Box<Sleep>>,
150    /// }
151    ///
152    /// impl Future for HasSleep {
153    ///     type Output = ();
154    ///
155    ///     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
156    ///         self.sleep.as_mut().poll(cx)
157    ///     }
158    /// }
159    /// ```
160    /// Use in a struct with pin projection. This method avoids the `Box`, but
161    /// the `HasSleep` struct will not be `Unpin` as a consequence.
162    /// ```
163    /// use std::future::Future;
164    /// use std::pin::Pin;
165    /// use std::task::{Context, Poll};
166    /// use monoio::time::Sleep;
167    /// use pin_project_lite::pin_project;
168    ///
169    /// pin_project! {
170    ///     struct HasSleep {
171    ///         #[pin]
172    ///         sleep: Sleep,
173    ///     }
174    /// }
175    ///
176    /// impl Future for HasSleep {
177    ///     type Output = ();
178    ///
179    ///     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
180    ///         self.project().sleep.poll(cx)
181    ///     }
182    /// }
183    /// ```
184    ///
185    /// [`select!`]: ../macro.select.html
186    /// [`monoio::pin!`]: ../macro.pin.html
187    #[cfg_attr(docsrs, doc(alias = "Delay"))]
188    #[derive(Debug)]
189    #[must_use = "futures do nothing unless you `.await` or poll them"]
190    pub struct Sleep {
191        deadline: Instant,
192
193        // The link between the `Sleep` instance and the timer that drives it.
194        #[pin]
195        entry: TimerEntry,
196    }
197}
198
199impl Sleep {
200    pub(crate) fn new_timeout(deadline: Instant) -> Sleep {
201        let handle = Handle::current();
202        let entry = TimerEntry::new(&handle, deadline);
203
204        Sleep { deadline, entry }
205    }
206
207    pub(crate) fn far_future() -> Sleep {
208        Self::new_timeout(Instant::far_future())
209    }
210
211    /// Returns the instant at which the future will complete.
212    pub fn deadline(&self) -> Instant {
213        self.deadline
214    }
215
216    /// Returns `true` if `Sleep` has elapsed.
217    ///
218    /// A `Sleep` instance is elapsed when the requested duration has elapsed.
219    pub fn is_elapsed(&self) -> bool {
220        self.entry.is_elapsed()
221    }
222
223    /// Resets the `Sleep` instance to a new deadline.
224    ///
225    /// Calling this function allows changing the instant at which the `Sleep`
226    /// future completes without having to create new associated state.
227    ///
228    /// This function can be called both before and after the future has
229    /// completed.
230    ///
231    /// To call this method, you will usually combine the call with
232    /// [`Pin::as_mut`], which lets you call the method without consuming the
233    /// `Sleep` itself.
234    ///
235    /// # Example
236    ///
237    /// ```
238    /// use monoio::time::{Duration, Instant};
239    ///
240    /// # #[monoio::main(timer_enabled = true)]
241    /// # async fn main() {
242    /// let sleep = monoio::time::sleep(Duration::from_millis(10));
243    /// monoio::pin!(sleep);
244    ///
245    /// sleep
246    ///     .as_mut()
247    ///     .reset(Instant::now() + Duration::from_millis(20));
248    /// # }
249    /// ```
250    ///
251    /// See also the top-level examples.
252    ///
253    /// [`Pin::as_mut`]: fn@std::pin::Pin::as_mut
254    pub fn reset(self: Pin<&mut Self>, deadline: Instant) {
255        let me = self.project();
256        me.entry.reset(deadline);
257        *me.deadline = deadline;
258    }
259
260    fn poll_elapsed(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<(), Error>> {
261        let me = self.project();
262        me.entry.poll_elapsed(cx)
263    }
264}
265
266impl Future for Sleep {
267    type Output = ();
268
269    fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
270        // `poll_elapsed` can return an error in two cases:
271        //
272        // - AtCapacity: this is a pathological case where far too many sleep instances have been
273        //   scheduled.
274        // - Shutdown: No timer has been setup, which is a mis-use error.
275        //
276        // Both cases are extremely rare, and pretty accurately fit into
277        // "logic errors", so we just panic in this case. A user couldn't
278        // really do much better if we passed the error onwards.
279        match ready!(self.as_mut().poll_elapsed(cx)) {
280            Ok(()) => Poll::Ready(()),
281            Err(e) => panic!("timer error: {e}"),
282        }
283    }
284}