async_io_mini/timer.rs
1use core::fmt::{self, Debug};
2use core::future::Future;
3use core::pin::Pin;
4use core::task::{Context, Poll, Waker};
5use core::time::Duration;
6
7use std::time::Instant;
8
9/// A future or stream that emits timed events.
10///
11/// Timers are futures that output a single [`Instant`] when they fire.
12///
13/// Timers are also streams that can output [`Instant`]s periodically.
14///
15/// # Precision
16///
17/// There is a limit on the maximum precision that a `Timer` can provide. This limit is
18/// dependent on the current platform and follows the precision provided by the `embassy-time`
19/// crate for that platform; for instance, on Windows, the maximum precision is
20/// about 16 milliseconds. Because of this limit, the timer may sleep for longer than the
21/// requested duration. It will never sleep for less.
22///
23/// On embedded platforms like ESP-IDF, the precision is much higer (up to 1 microsecond),
24/// because the `embassy-time` crate for ESP-IDF uses the ESP-IDF Timer service.
25///
26/// # Examples
27///
28/// Sleep for 1 second:
29///
30/// ```
31/// use async_io_mini::Timer;
32/// use std::time::Duration;
33///
34/// # futures_lite::future::block_on(async {
35/// Timer::after(Duration::from_secs(1)).await;
36/// # });
37/// ```
38///
39/// Timeout after 1 second:
40///
41/// ```
42/// use async_io_mini::Timer;
43/// use futures_lite::FutureExt;
44/// use std::time::Duration;
45///
46/// # futures_lite::future::block_on(async {
47/// let wait = core::future::pending::<Result<(), std::io::Error>>()
48/// .or(async {
49/// Timer::after(Duration::from_secs(1)).await;
50/// Err(std::io::ErrorKind::TimedOut.into())
51/// })
52/// .await?;
53/// # std::io::Result::Ok(()) });
54/// ```
55pub struct Timer {
56 when: Option<Instant>,
57 period: Duration,
58 waker: Option<Waker>,
59}
60
61impl Timer {
62 /// Creates a timer that will never fire.
63 ///
64 /// # Examples
65 ///
66 /// This function may also be useful for creating a function with an optional timeout.
67 ///
68 /// ```
69 /// # futures_lite::future::block_on(async {
70 /// use async_io_mini::Timer;
71 /// use futures_lite::prelude::*;
72 /// use std::time::Duration;
73 ///
74 /// async fn run_with_timeout(timeout: Option<Duration>) {
75 /// let timer = timeout
76 /// .map(|timeout| Timer::after(timeout))
77 /// .unwrap_or_else(Timer::never);
78 ///
79 /// run_lengthy_operation().or(timer).await;
80 /// }
81 /// # // Note that since a Timer as a Future returns an Instant,
82 /// # // this function needs to return an Instant to be used
83 /// # // in "or".
84 /// # async fn run_lengthy_operation() -> std::time::Instant {
85 /// # std::time::Instant::now()
86 /// # }
87 ///
88 /// // Times out after 5 seconds.
89 /// run_with_timeout(Some(Duration::from_secs(5))).await;
90 /// // Does not time out.
91 /// run_with_timeout(None).await;
92 /// # });
93 /// ```
94 pub fn never() -> Timer {
95 let _fix_linking = embassy_time::Timer::after(embassy_time::Duration::from_secs(1));
96
97 Timer {
98 when: None,
99 period: Duration::MAX,
100 waker: None,
101 }
102 }
103
104 /// Creates a timer that emits an event once after the given duration of time.
105 ///
106 /// # Examples
107 ///
108 /// ```
109 /// use async_io_mini::Timer;
110 /// use std::time::Duration;
111 ///
112 /// # futures_lite::future::block_on(async {
113 /// Timer::after(Duration::from_secs(1)).await;
114 /// # });
115 /// ```
116 pub fn after(duration: Duration) -> Timer {
117 let Some(start) = Instant::now().checked_add(duration) else {
118 return Timer::never();
119 };
120
121 Timer::interval_at(start, Duration::MAX)
122 }
123
124 /// Creates a timer that emits an event once at the given time instant.
125 ///
126 /// # Examples
127 ///
128 /// ```
129 /// use async_io_mini::Timer;
130 /// use std::time::{Duration, Instant};
131 ///
132 /// # futures_lite::future::block_on(async {
133 /// let now = Instant::now();
134 /// let when = now + Duration::from_secs(1);
135 /// Timer::at(when).await;
136 /// # });
137 /// ```
138 pub fn at(instant: Instant) -> Timer {
139 Timer::interval_at(instant, Duration::MAX)
140 }
141
142 /// Creates a timer that emits events periodically.
143 ///
144 /// # Examples
145 ///
146 /// ```
147 /// use async_io_mini::Timer;
148 /// use futures_lite::StreamExt;
149 /// use std::time::{Duration, Instant};
150 ///
151 /// # futures_lite::future::block_on(async {
152 /// let period = Duration::from_secs(1);
153 /// Timer::interval(period).next().await;
154 /// # });
155 /// ```
156 pub fn interval(period: Duration) -> Timer {
157 let Some(start) = Instant::now().checked_add(period) else {
158 return Timer::never();
159 };
160
161 Timer::interval_at(start, period)
162 }
163
164 /// Creates a timer that emits events periodically, starting at `start`.
165 ///
166 /// # Examples
167 ///
168 /// ```
169 /// use async_io_mini::Timer;
170 /// use futures_lite::StreamExt;
171 /// use std::time::{Duration, Instant};
172 ///
173 /// # futures_lite::future::block_on(async {
174 /// let start = Instant::now();
175 /// let period = Duration::from_secs(1);
176 /// Timer::interval_at(start, period).next().await;
177 /// # });
178 /// ```
179 pub fn interval_at(start: Instant, period: Duration) -> Timer {
180 if Self::ticks(&start).is_some() {
181 Timer {
182 when: Some(start),
183 period,
184 waker: None,
185 }
186 } else {
187 Timer::never()
188 }
189 }
190
191 /// Indicates whether or not this timer will ever fire.
192 ///
193 /// [`never()`] will never fire, and timers created with [`after()`] or [`at()`] will fire
194 /// if the duration is not too large.
195 ///
196 /// [`never()`]: Timer::never()
197 /// [`after()`]: Timer::after()
198 /// [`at()`]: Timer::at()
199 ///
200 /// # Examples
201 ///
202 /// ```
203 /// # futures_lite::future::block_on(async {
204 /// use async_io_mini::Timer;
205 /// use futures_lite::prelude::*;
206 /// use std::time::Duration;
207 ///
208 /// // `never` will never fire.
209 /// assert!(!Timer::never().will_fire());
210 ///
211 /// // `after` will fire if the duration is not too large.
212 /// assert!(Timer::after(Duration::from_secs(1)).will_fire());
213 /// assert!(!Timer::after(Duration::MAX).will_fire());
214 ///
215 /// // However, once an `after` timer has fired, it will never fire again.
216 /// let mut t = Timer::after(Duration::from_secs(1));
217 /// assert!(t.will_fire());
218 /// (&mut t).await;
219 /// assert!(!t.will_fire());
220 ///
221 /// // Interval timers will fire periodically.
222 /// let mut t = Timer::interval(Duration::from_secs(1));
223 /// assert!(t.will_fire());
224 /// t.next().await;
225 /// assert!(t.will_fire());
226 /// # });
227 /// ```
228 #[inline]
229 pub fn will_fire(&self) -> bool {
230 self.when.is_some()
231 }
232
233 /// Sets the timer to emit an en event once after the given duration of time.
234 ///
235 /// Note that resetting a timer is different from creating a new timer because
236 /// [`set_after()`][`Timer::set_after()`] does not remove the waker associated with the task
237 /// that is polling the timer.
238 ///
239 /// # Examples
240 ///
241 /// ```
242 /// use async_io_mini::Timer;
243 /// use std::time::Duration;
244 ///
245 /// # futures_lite::future::block_on(async {
246 /// let mut t = Timer::after(Duration::from_secs(1));
247 /// t.set_after(Duration::from_millis(100));
248 /// # });
249 /// ```
250 pub fn set_after(&mut self, duration: Duration) {
251 match Instant::now().checked_add(duration) {
252 Some(instant) => self.set_at(instant),
253 // Overflow to never going off.
254 None => self.set_never(),
255 }
256 }
257
258 /// Sets the timer to emit an event once at the given time instant.
259 ///
260 /// Note that resetting a timer is different from creating a new timer because
261 /// [`set_at()`][`Timer::set_at()`] does not remove the waker associated with the task
262 /// that is polling the timer.
263 ///
264 /// # Examples
265 ///
266 /// ```
267 /// use async_io_mini::Timer;
268 /// use std::time::{Duration, Instant};
269 ///
270 /// # futures_lite::future::block_on(async {
271 /// let mut t = Timer::after(Duration::from_secs(1));
272 ///
273 /// let now = Instant::now();
274 /// let when = now + Duration::from_secs(1);
275 /// t.set_at(when);
276 /// # });
277 /// ```
278 pub fn set_at(&mut self, instant: Instant) {
279 let ticks = Self::ticks(&instant);
280
281 if let Some(ticks) = ticks {
282 self.when = Some(instant);
283 self.period = Duration::MAX;
284
285 if let Some(waker) = self.waker.as_ref() {
286 embassy_time_driver::schedule_wake(ticks, waker);
287 }
288 } else {
289 self.set_never();
290 }
291 }
292
293 /// Sets the timer to emit events periodically.
294 ///
295 /// Note that resetting a timer is different from creating a new timer because
296 /// [`set_interval()`][`Timer::set_interval()`] does not remove the waker associated with the
297 /// task that is polling the timer.
298 ///
299 /// # Examples
300 ///
301 /// ```
302 /// use async_io_mini::Timer;
303 /// use futures_lite::StreamExt;
304 /// use std::time::{Duration, Instant};
305 ///
306 /// # futures_lite::future::block_on(async {
307 /// let mut t = Timer::after(Duration::from_secs(1));
308 ///
309 /// let period = Duration::from_secs(2);
310 /// t.set_interval(period);
311 /// # });
312 /// ```
313 pub fn set_interval(&mut self, period: Duration) {
314 match Instant::now().checked_add(period) {
315 Some(instant) => self.set_interval_at(instant, period),
316 // Overflow to never going off.
317 None => self.set_never(),
318 }
319 }
320
321 /// Sets the timer to emit events periodically, starting at `start`.
322 ///
323 /// Note that resetting a timer is different from creating a new timer because
324 /// [`set_interval_at()`][`Timer::set_interval_at()`] does not remove the waker associated with
325 /// the task that is polling the timer.
326 ///
327 /// # Examples
328 ///
329 /// ```
330 /// use async_io_mini::Timer;
331 /// use futures_lite::StreamExt;
332 /// use std::time::{Duration, Instant};
333 ///
334 /// # futures_lite::future::block_on(async {
335 /// let mut t = Timer::after(Duration::from_secs(1));
336 ///
337 /// let start = Instant::now();
338 /// let period = Duration::from_secs(2);
339 /// t.set_interval_at(start, period);
340 /// # });
341 /// ```
342 pub fn set_interval_at(&mut self, start: Instant, period: Duration) {
343 let ticks = Self::ticks(&start);
344
345 if let Some(ticks) = ticks {
346 self.when = Some(start);
347 self.period = period;
348
349 if let Some(waker) = self.waker.as_ref() {
350 embassy_time_driver::schedule_wake(ticks, waker);
351 }
352 } else {
353 // Overflow to never going off.
354 self.set_never();
355 }
356 }
357
358 fn set_never(&mut self) {
359 self.when = None;
360 self.waker = None;
361 self.period = Duration::MAX;
362 }
363
364 fn fired_at(&mut self, cx: &mut Context<'_>) -> Option<Instant> {
365 let when = self.when?;
366
367 if when > Instant::now() {
368 let ticks = Self::ticks(&when);
369
370 if let Some(ticks) = ticks {
371 if self
372 .waker
373 .as_ref()
374 .map(|waker| !waker.will_wake(cx.waker()))
375 .unwrap_or(true)
376 {
377 self.waker = Some(cx.waker().clone());
378 embassy_time_driver::schedule_wake(ticks, cx.waker());
379 }
380 } else {
381 self.set_never();
382 }
383
384 None
385 } else {
386 Some(when)
387 }
388 }
389
390 fn ticks(instant: &Instant) -> Option<u64> {
391 fn duration_ticks(duration: &Duration) -> Option<u64> {
392 let ticks = duration.as_secs() as u128 * embassy_time_driver::TICK_HZ as u128
393 + duration.subsec_nanos() as u128 * embassy_time_driver::TICK_HZ as u128
394 / 1_000_000_000;
395
396 u64::try_from(ticks).ok()
397 }
398
399 let now = Instant::now();
400 let now_ticks = embassy_time_driver::now();
401
402 if *instant >= now {
403 let dur_ticks = duration_ticks(&instant.duration_since(now));
404
405 dur_ticks.and_then(|dur_ticks| now_ticks.checked_add(dur_ticks))
406 } else {
407 let dur_ticks = duration_ticks(&now.duration_since(*instant));
408
409 dur_ticks.map(|dur_ticks| now_ticks.saturating_sub(dur_ticks))
410 }
411 }
412}
413
414impl Debug for Timer {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416 f.debug_struct("Timer")
417 .field("start", &self.when.as_ref())
418 .field("period", &self.period)
419 .finish()
420 }
421}
422
423impl Future for Timer {
424 type Output = Instant;
425
426 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
427 let Some(when) = self.fired_at(cx) else {
428 return Poll::Pending;
429 };
430
431 self.set_never();
432
433 Poll::Ready(when)
434 }
435}
436
437#[cfg(feature = "futures-lite")]
438impl futures_lite::Stream for Timer {
439 type Item = Instant;
440
441 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
442 let Some(when) = self.fired_at(cx) else {
443 return Poll::Pending;
444 };
445
446 let next_when = when.checked_add(self.period);
447
448 if let Some(next_when) = next_when {
449 let period = self.period;
450
451 self.set_interval_at(next_when, period);
452 } else {
453 self.set_never();
454 }
455
456 Poll::Ready(Some(when))
457 }
458}