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}