vexide_async/time.rs
1//! Utilities for tracking time.
2//!
3//! This module provides a types for executing code after a set period of time.
4//!
5//! - [`Sleep`] is a future that does no work and completes at a specific [`Instant`] in time.
6//! - [`sleep`] and [`sleep_until`] provide ways to yield control away from a future for or until a
7//! specific instant in time.
8
9use core::{
10 future::Future,
11 pin::Pin,
12 task::{Context, Poll},
13 time::Duration,
14};
15use std::{task::Waker, time::Instant};
16
17use crate::{executor::EXECUTOR, reactor::Sleeper};
18
19/// A future that will complete after a certain instant is reached in time.
20///
21/// This type is returned by the [`sleep`] and [`sleep_until`] functions.
22#[derive(Debug)]
23#[must_use = "futures do nothing unless you `.await` or poll them"]
24pub struct Sleep {
25 deadline: Instant,
26 registered_waker: Option<Waker>,
27}
28
29impl Future for Sleep {
30 type Output = ();
31
32 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
33 if Instant::now() >= self.deadline {
34 return Poll::Ready(());
35 }
36
37 // Register a waker on the reactor to only poll this future when the deadline passes.
38 //
39 // We should only push to the sleeper queue if we either haven't pushed
40 // (`self.registered.waker == None`) or if !w.will_wake(cx.waker()), meaning the already
41 // registered waker will not wake up the same task as the current waker indicating that the
42 // sleep has potentially been moved across executors.
43 if self
44 .registered_waker
45 .as_ref()
46 .map(|w| !w.will_wake(cx.waker()))
47 .unwrap_or(true)
48 {
49 let this = self.get_mut();
50 this.registered_waker = Some(cx.waker().clone());
51
52 EXECUTOR.with(|ex| {
53 ex.with_reactor(|reactor| {
54 reactor.sleepers.push(Sleeper {
55 deadline: this.deadline,
56 waker: cx.waker().clone(),
57 });
58 });
59 });
60 }
61
62 Poll::Pending
63 }
64}
65
66/// Waits until `duration` has elapsed.
67///
68/// This function returns a future that will complete after the given duration, effectively yielding
69/// the current task for a period of time.
70///
71/// Equivalent to `sleep_until(Instant::now() + duration)`.
72///
73/// # Examples
74///
75/// ```no_run
76/// use std::time::Duration;
77///
78/// use vexide::prelude::*;
79///
80/// #[vexide::main]
81/// async fn main(_peripherals: Peripherals) {
82/// println!("See you in 5 minutes.");
83/// sleep(Duration::from_secs(300)).await;
84/// println!("Hello again!");
85/// }
86/// ```
87pub fn sleep(duration: Duration) -> Sleep {
88 Sleep {
89 deadline: Instant::now() + duration,
90 registered_waker: None,
91 }
92}
93
94/// Waits until `deadline` is reached.
95///
96/// This function returns a future that will complete once a given `Instant` in time has been
97/// reached.
98///
99/// # Examples
100///
101/// ```no_run
102/// use std::time::{Duration, Instant};
103///
104/// use vexide::prelude::*;
105///
106/// #[vexide::main]
107/// async fn main(_peripherals: Peripherals) {
108/// let now = Instant::now();
109/// let deadline = now + Duration::from_secs(2); // 2 seconds in the future
110///
111/// println!("See you in 2 seconds.");
112/// sleep_until(deadline).await;
113/// println!("Hello again!");
114/// }
115/// ```
116pub const fn sleep_until(deadline: Instant) -> Sleep {
117 Sleep {
118 deadline,
119 registered_waker: None,
120 }
121}