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}