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}