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 {}