Skip to main content

auralis_task/
timer.rs

1//! Timer primitives for the Auralis executor.
2//!
3//! Provides [`sleep`], an async delay future that cooperatively yields
4//! to the executor for the given duration.
5
6use std::future::Future;
7use std::pin::Pin;
8use std::task::{Context, Poll};
9use std::time::Duration;
10
11use crate::executor;
12
13/// A future that completes after a given duration.
14///
15/// Created by [`sleep`].  On first poll it registers a timer with the
16/// executor; subsequent polls return `Ready` once the deadline has passed.
17pub struct SleepFuture {
18    registered: bool,
19    duration_ms: u64,
20}
21
22impl SleepFuture {
23    pub(crate) fn new(duration: Duration) -> Self {
24        Self {
25            registered: false,
26            duration_ms: duration.as_millis() as u64,
27        }
28    }
29}
30
31impl Future for SleepFuture {
32    type Output = ();
33
34    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
35        if !self.registered {
36            self.registered = true;
37
38            // Discover our task id from the executor's thread-local.
39            let task_id = executor::with_current_polling_task(|id| {
40                id.expect("timer::sleep must be called from within an auralis task")
41            });
42
43            // Compute deadline and register with the executor.
44            let now = executor::current_time_ms();
45            let deadline = now.saturating_add(self.duration_ms);
46
47            executor::Executor::schedule_timer(
48                &executor::current_executor_instance(),
49                deadline,
50                task_id,
51            );
52
53            // Re-register the waker so the executor can wake us.
54            cx.waker().wake_by_ref();
55
56            Poll::Pending
57        } else {
58            Poll::Ready(())
59        }
60    }
61}
62
63/// Pause the current task for at least `duration`.
64///
65/// # Panics
66///
67/// Panics if called outside of an auralis task context (i.e. not from
68/// within a future spawned via [`TaskScope::spawn`](crate::TaskScope::spawn)
69/// or [`spawn_global`](crate::spawn_global)).
70///
71/// # Example
72///
73/// ```rust,ignore
74/// use std::time::Duration;
75/// use auralis_task::timer;
76///
77/// scope.spawn(async {
78///     timer::sleep(Duration::from_millis(500)).await;
79///     // ... do something after delay
80/// });
81/// ```
82pub async fn sleep(duration: Duration) {
83    SleepFuture::new(duration).await
84}