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 self.waker = Some(cx.waker().clone());
372 embassy_time_driver::schedule_wake(ticks, cx.waker());
373 } else {
374 self.set_never();
375 }
376
377 None
378 } else {
379 Some(when)
380 }
381 }
382
383 fn ticks(instant: &Instant) -> Option<u64> {
384 fn duration_ticks(duration: &Duration) -> Option<u64> {
385 let ticks = duration.as_secs() as u128 * embassy_time_driver::TICK_HZ as u128
386 + duration.subsec_nanos() as u128 * embassy_time_driver::TICK_HZ as u128
387 / 1_000_000_000;
388
389 u64::try_from(ticks).ok()
390 }
391
392 let now = Instant::now();
393 let now_ticks = embassy_time_driver::now();
394
395 if *instant >= now {
396 let dur_ticks = duration_ticks(&instant.duration_since(now));
397
398 dur_ticks.and_then(|dur_ticks| now_ticks.checked_add(dur_ticks))
399 } else {
400 let dur_ticks = duration_ticks(&now.duration_since(*instant));
401
402 dur_ticks.map(|dur_ticks| now_ticks.saturating_sub(dur_ticks))
403 }
404 }
405}
406
407impl Debug for Timer {
408 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
409 f.debug_struct("Timer")
410 .field("start", &self.when.as_ref())
411 .field("period", &self.period)
412 .finish()
413 }
414}
415
416impl Future for Timer {
417 type Output = Instant;
418
419 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
420 let Some(when) = self.fired_at(cx) else {
421 return Poll::Pending;
422 };
423
424 self.set_never();
425
426 Poll::Ready(when)
427 }
428}
429
430#[cfg(feature = "futures-lite")]
431impl futures_lite::Stream for Timer {
432 type Item = Instant;
433
434 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
435 let Some(when) = self.fired_at(cx) else {
436 return Poll::Pending;
437 };
438
439 let next_when = when.checked_add(self.period);
440
441 if let Some(next_when) = next_when {
442 let period = self.period;
443
444 self.set_interval_at(next_when, period);
445 } else {
446 self.set_never();
447 }
448
449 Poll::Ready(Some(when))
450 }
451}