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}