uefi_async/nano_alloc/time.rs
1use crate::{tick, FREQ};
2use alloc::boxed::Box;
3use core::pin::Pin;
4use core::task::{Context, Poll};
5
6/// A wrapper that adds a time limit to a `Future`.
7///
8/// If the internal future does not complete before the deadline (in hardware ticks),
9/// it returns `Err(())`. Otherwise, it returns `Ok(Output)`.
10///
11/// # Examples
12///
13/// ```rust,no_run
14/// use uefi_async::nano_alloc::time::Timeout;
15///
16/// async fn calc_1() {}
17/// async fn calc_2() {
18/// match Box::pin(calc_2()).timeout(Duration::from_secs(2).as_secs()).await { _ => () }
19/// match Timeout::new_pin(Box::pin(calc_2()), 500).await { _ => () }
20/// match Timeout::new(calc_1(), 300).await { _ => () }
21/// match calc_2().timeout(500).await { Ok(_) => {}, Err(_) => {} }
22/// }
23/// ```
24pub struct Timeout<'bemly_, Content> {
25 future: Pin<Box<dyn Future<Output = Content> + 'bemly_>>,
26 deadline: u64,
27}
28
29impl<'bemly_, Content> Timeout<'bemly_, Content> {
30 /// Creates a new `Timeout` by pinning the provided future to the heap.
31 ///
32 /// `ticks` is the relative duration from the current time.
33 #[inline]
34 pub fn new(future: impl Future<Output = Content> + 'bemly_, ticks: u64) -> Self {
35 Self { future: Box::pin(future), deadline: tick().saturating_add(ticks) }
36 }
37
38 /// Creates a new `Timeout` from an already pinned future.
39 ///
40 /// Useful when the future is already boxed or has a complex lifetime.
41 #[inline(always)]
42 pub fn new_pin(future: Pin<Box<dyn Future<Output = Content> + 'bemly_>>, ticks: u64) -> Self {
43 Self { future, deadline: tick().saturating_add(ticks) }
44 }
45}
46
47impl<'bemly_, Content> Future for Timeout<'bemly_, Content> {
48 /// Returns `Ok(T)` if finished in time, or `Err(())` if the deadline is exceeded.
49 type Output = Result<Content, ()>;
50
51 fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
52 // Check if the current hardware tick has passed the deadline
53 if tick() >= self.deadline { return Poll::Ready(Err(())) }
54
55 // Poll the inner pinned future
56 match self.future.as_mut().poll(cx) {
57 Poll::Ready(val) => Poll::Ready(Ok(val)),
58 Poll::Pending => Poll::Pending,
59 }
60 }
61}
62/// An extension trait to provide the `.timeout()` method for all `Future` types.
63pub trait _Timeout<'bemly_>: Future + Sized {
64 /// Wraps the future in a `Timeout` with the specified duration in hardware ticks.
65 fn timeout(self, duration_ticks: u64) -> Timeout<'bemly_, Self::Output> where Self: 'bemly_ {
66 Timeout::new(self, duration_ticks)
67 }
68}
69impl<F: Future + Sized> _Timeout<'_> for F {}
70
71/// A high-precision asynchronous timer based on hardware ticks.
72///
73/// `WaitTimer` leverages the CPU's Time Stamp Counter (TSC) to provide non-blocking
74/// delays ranging from picoseconds to years. It implements the [`Future`] trait,
75/// allowing the executor to suspend tasks until the specified hardware deadline is reached.
76///
77/// # Precision and Accuracy
78/// The timer relies on the calibrated frequency stored in `FREQ`. Accuracy is
79/// determined by the sampling quality during `init_clock_freq()`.
80///
81/// # Examples
82///
83/// Using the builder-style methods:
84/// ```rust,no_run
85/// async fn delay_example() {
86/// // Create a timer for 500 milliseconds
87/// WaitTimer::from_ms(500).await;
88/// }
89/// ```
90///
91/// Using the [`_WaitTimer`] extension trait for a more expressive DSL:
92/// ```rust,no_run
93/// use uefi_async::nano_alloc::time::{WaitTimer, _WaitTimer};
94///
95/// async fn blink_led_task() {
96/// loop {
97/// // Highly readable duration syntax
98/// 1.s().await; // Wait 1 second
99/// 500.ms().await; // Wait 500 milliseconds
100/// 20.fps().await; // Wait for 1 frame duration at 20 FPS (50ms)
101///
102/// // Precise sub-microsecond timing
103/// 10.us().await; // 10 microseconds
104/// 80.ps().await; // 80 picoseconds (Note: Dependent on CPU Ghz)
105///
106/// // Long-term scheduling
107/// 2.hour().await;
108/// 1.day().await;
109/// }
110/// }
111/// ```
112#[derive(Debug)]
113pub struct WaitTimer(u64);
114
115impl WaitTimer {
116 /// Constructs a timer that expires at an absolute hardware tick count.
117 #[inline(always)]
118 pub fn until(deadline: u64) -> Self { Self(deadline) }
119
120 /// Constructs a timer that expires after a relative number of ticks from now.
121 #[inline(always)]
122 pub fn after(ticks_to_wait: u64) -> Self { Self(tick().wrapping_add(ticks_to_wait)) }
123
124 /// Checks if the current hardware tick has reached or exceeded the deadline.
125 ///
126 /// This uses a direct comparison, assuming the timer is polled frequently
127 /// enough to handle 64-bit tick overflows (which take centuries on modern CPUs).
128 #[inline(always)]
129 pub fn is_expired(&self) -> bool { tick() >= self.0 }
130
131 #[inline(always)]
132 pub fn from_year(y: u64) -> Self { Self::after(y.saturating_mul(FREQ.hz().saturating_mul(31536000))) }
133
134 #[inline(always)]
135 pub fn from_month(m: u64) -> Self { Self::after(m.saturating_mul(FREQ.hz() * 2592000)) }
136
137 #[inline(always)]
138 pub fn from_week(w: u64) -> Self { Self::after(w.saturating_mul(FREQ.hz() * 604800)) }
139
140 #[inline(always)]
141 pub fn from_day(d: u64) -> Self { Self::after(d.saturating_mul(FREQ.hz() * 86400)) }
142
143 #[inline(always)]
144 pub fn from_hour(h: u64) -> Self { Self::after(h.saturating_mul(FREQ.hz() * 3600)) }
145
146 #[inline(always)]
147 pub fn from_min(min: u64) -> Self { Self::after(min.saturating_mul(FREQ.hz() * 60)) }
148
149 #[inline(always)]
150 pub fn from_s(hz: u64) -> Self { Self::after(hz.saturating_mul(FREQ.hz())) }
151
152 #[inline(always)]
153 pub fn from_ms(ms: u64) -> Self { Self::after(ms.saturating_mul(FREQ.ms())) }
154
155 #[inline(always)]
156 pub fn from_us(us: u64) -> Self { Self::after(us.saturating_mul(FREQ.us())) }
157
158 #[inline(always)]
159 pub fn from_ns(ns: u64) -> Self { Self::after(ns.saturating_mul(FREQ.ns())) }
160
161 #[inline(always)]
162 pub fn from_ps(ps: u64) -> Self { Self::after(ps.saturating_mul(FREQ.ps())) }
163
164 #[inline(always)]
165 pub fn from_fps(fps: u64) -> Self { Self::after(FREQ.hz() / fps.max(1)) }
166}
167
168impl Future for WaitTimer {
169 type Output = ();
170
171 fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> {
172 if self.is_expired() { Poll::Ready(()) } else { Poll::Pending }
173 }
174}
175
176/// Extension trait providing a fluent API for creating [`WaitTimer`] instances
177/// directly from unsigned 64-bit integers.
178///
179/// This trait is exclusively implemented for `u64` to ensure stable type inference
180/// when using numeric literals (e.g., `500.ms().await`).
181pub trait _WaitTimer: Into<u64> + Sized {
182 /// Creates a timer for the specified number of years.
183 #[inline(always)]
184 fn year(self) -> WaitTimer { WaitTimer::from_year(self.into()) }
185
186 /// Creates a timer for the specified number of months.
187 #[inline(always)]
188 fn month(self) -> WaitTimer { WaitTimer::from_month(self.into()) }
189
190 /// Creates a timer for the specified number of weeks.
191 #[inline(always)]
192 fn week(self) -> WaitTimer { WaitTimer::from_week(self.into()) }
193
194 /// Creates a timer for the specified number of days.
195 #[inline(always)]
196 fn day(self) -> WaitTimer { WaitTimer::from_day(self.into()) }
197
198 /// Creates a timer for the specified number of hours.
199 #[inline(always)]
200 fn hour(self) -> WaitTimer { WaitTimer::from_hour(self.into()) }
201
202 /// Creates a timer for the specified number of minutes.
203 #[inline(always)]
204 fn mins(self) -> WaitTimer { WaitTimer::from_min(self.into()) }
205
206 /// Creates a timer for the specified number of seconds.
207 #[inline(always)]
208 fn s(self) -> WaitTimer { WaitTimer::from_s(self.into()) }
209
210 /// Creates a timer based on Frequency (Hz).
211 /// Represented as the period: 1 second / frequency.
212 #[inline(always)]
213 fn hz(self) -> WaitTimer { WaitTimer::from_s(self.into()) }
214
215 /// Creates a timer for the specified number of milliseconds (10^-3 s).
216 #[inline(always)]
217 fn ms(self) -> WaitTimer { WaitTimer::from_ms(self.into()) }
218
219 /// Creates a timer for the specified number of microseconds (10^-6 s).
220 #[inline(always)]
221 fn us(self) -> WaitTimer { WaitTimer::from_us(self.into()) }
222
223 /// Creates a timer for the specified number of nanoseconds (10^-9 s).
224 #[inline(always)]
225 fn ns(self) -> WaitTimer { WaitTimer::from_ns(self.into()) }
226
227 /// Creates a timer for the specified number of picoseconds (10^-12 s).
228 #[inline(always)]
229 fn ps(self) -> WaitTimer { WaitTimer::from_ps(self.into()) }
230
231 /// Creates a timer based on Frames Per Second (FPS).
232 /// Used for synchronizing game loops or rendering intervals.
233 #[inline(always)]
234 fn fps(self) -> WaitTimer { WaitTimer::from_fps(self.into()) }
235}
236/// Implement only for u64 to provide a concrete base for numeric literals.
237/// Only one primitive type is allowed; otherwise, the rustc_infer cannot deduce it.
238impl _WaitTimer for u64 {}