Skip to main content

orb/
time.rs

1//! Time-related traits and utilities for async operations.
2//!
3//! This module provides traits for working with time in an async context,
4//! including sleeping, timeouts, and periodic timers.
5
6use crate::utils::Cancellable;
7use futures_lite::stream::Stream;
8use std::future::Future;
9use std::pin::Pin;
10use std::task::{Context, Poll};
11use std::time::{Duration, Instant};
12
13/// Trait for async time-related operations.
14///
15/// This trait defines the interface for time-related operations such as
16/// sleeping, creating intervals, and applying timeouts to futures.
17///
18/// # Associated Types
19///
20/// * `Interval` - The type used for periodic timers
21pub trait AsyncTime {
22    /// The type used for periodic timers.
23    type Interval: TimeInterval;
24
25    /// Sleep for the specified duration.
26    ///
27    /// This method returns a future that completes after the specified
28    /// duration has elapsed.
29    ///
30    /// # Parameters
31    ///
32    /// * `d` - The duration to sleep
33    ///
34    /// # Returns
35    ///
36    /// A future that completes after the specified duration
37    fn sleep(d: Duration) -> impl Future + Send;
38
39    /// Create a periodic timer that ticks at the specified interval.
40    ///
41    /// This method creates a timer that repeatedly fires at the specified
42    /// interval, useful for implementing periodic tasks.
43    ///
44    /// # Parameters
45    ///
46    /// * `d` - The interval between ticks
47    ///
48    /// # Returns
49    ///
50    /// An interval object that implements [`TimeInterval`]
51    fn interval(d: Duration) -> Self::Interval;
52
53    /// Apply a timeout to a future.
54    ///
55    /// This method returns a future that completes either when the provided
56    /// future completes or when the specified timeout duration elapses,
57    /// whichever happens first.
58    ///
59    /// # Parameters
60    ///
61    /// * `d` - The timeout duration
62    /// * `func` - The future to apply the timeout to
63    ///
64    /// # Returns
65    ///
66    /// A future that resolves to `Ok` with the result of the original future
67    /// if it completes before the timeout, or `Err(())` if the timeout elapses
68    /// first.
69    #[inline]
70    fn timeout<F>(d: Duration, func: F) -> impl Future<Output = Result<F::Output, ()>> + Send
71    where
72        F: Future + Send,
73    {
74        Cancellable::new(func, Self::sleep(d))
75    }
76}
77
78/// Trait for periodic timers.
79///
80/// This trait defines the interface for periodic timers that can be used
81/// to implement recurring tasks.
82pub trait TimeInterval: Unpin + Send {
83    /// Poll for the next tick.
84    ///
85    /// This method is used internally by the async runtime to check if
86    /// the next timer tick is ready.
87    ///
88    /// # Parameters
89    ///
90    /// * `ctx` - The task context for polling
91    ///
92    /// # Returns
93    ///
94    /// A `Poll` containing the instant when the tick occurred, or `Poll::Pending`
95    /// if the tick is not yet ready.
96    fn poll_tick(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Instant>;
97
98    /// Wait asynchronously for the next tick.
99    ///
100    /// This method returns a future that completes when the next timer tick occurs.
101    ///
102    /// # Returns
103    ///
104    /// A future that resolves to the instant when the tick occurred.
105    fn tick<'a>(&'a mut self) -> TickFuture<'a, Self>
106    where
107        Self: Sized,
108    {
109        TickFuture::new(self)
110    }
111
112    /// Convert this interval into a stream.
113    ///
114    /// This method converts the interval into a stream that yields the
115    /// instant of each tick.
116    ///
117    /// # Returns
118    ///
119    /// A stream that yields the instant of each tick.
120    #[inline(always)]
121    fn into_stream(self) -> IntervalStream<Self>
122    where
123        Self: Sized,
124    {
125        IntervalStream::new(self)
126    }
127}
128
129/// A wrapper that implements `Stream` for a `TimeInterval`.
130///
131/// This struct allows a `TimeInterval` to be used as a `Stream` that
132/// yields the instant of each tick.
133///
134/// # Type Parameters
135///
136/// * `T` - The underlying interval type
137pub struct IntervalStream<T: TimeInterval> {
138    interval: T,
139}
140
141impl<T: TimeInterval> IntervalStream<T> {
142    /// Create a new interval stream.
143    ///
144    /// # Parameters
145    ///
146    /// * `interval` - The interval to wrap
147    ///
148    /// # Returns
149    ///
150    /// A new interval stream
151    pub fn new(interval: T) -> Self {
152        Self { interval }
153    }
154}
155
156impl<T: TimeInterval> Stream for IntervalStream<T> {
157    type Item = Instant;
158
159    fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
160        unsafe { Pin::new_unchecked(&mut self.interval).poll_tick(ctx).map(Some) }
161    }
162}
163
164/// Future for the tick operation.
165///
166/// This future completes when the next timer tick occurs.
167///
168/// # Type Parameters
169///
170/// * `T` - The underlying interval type
171pub struct TickFuture<'a, T: TimeInterval> {
172    interval: &'a mut T,
173}
174
175impl<'a, T: TimeInterval> TickFuture<'a, T> {
176    /// Create a new tick future.
177    ///
178    /// # Parameters
179    ///
180    /// * `interval` - The interval to wait for
181    ///
182    /// # Returns
183    ///
184    /// A new tick future
185    pub fn new(interval: &'a mut T) -> Self {
186        Self { interval }
187    }
188}
189
190impl<'a, T: TimeInterval> Future for TickFuture<'a, T> {
191    type Output = Instant;
192
193    fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
194        unsafe { Pin::new_unchecked(&mut *self.interval).poll_tick(ctx) }
195    }
196}