kayrx_timer/
interval.rs

1use crate::driver::future::poll_fn;
2use crate::{delay_until, Delay, Duration, Instant};
3
4use std::future::Future;
5use std::pin::Pin;
6use std::task::{Context, Poll};
7
8macro_rules! ready {
9    ($e:expr $(,)?) => {
10        match $e {
11            std::task::Poll::Ready(t) => t,
12            std::task::Poll::Pending => return std::task::Poll::Pending,
13        }
14    };
15}
16
17/// Creates new `Interval` that yields with interval of `duration`. The first
18/// tick completes immediately.
19///
20/// An interval will tick indefinitely. At any time, the `Interval` value can be
21/// dropped. This cancels the interval.
22///
23/// This function is equivalent to `interval_at(Instant::now(), period)`.
24///
25/// # Panics
26///
27/// This function panics if `period` is zero.
28///
29/// # Examples
30///
31/// ```rust
32/// use kayrx_timer::{self, Duration};
33/// use kayrx_karx;
34///
35/// fn main() {
36///          kayrx_karx::exec(async {
37///              let mut interval = timer::interval(Duration::from_millis(10));
38///         
39///              interval.tick().await;
40///              interval.tick().await;
41///              interval.tick().await;
42///         
43///              // approximately 20ms have elapsed.
44///          });
45/// }
46/// ```
47pub fn interval(period: Duration) -> Interval {
48    assert!(period > Duration::new(0, 0), "`period` must be non-zero.");
49
50    interval_at(Instant::now(), period)
51}
52
53/// Creates new `Interval` that yields with interval of `period` with the
54/// first tick completing at `at`.
55///
56/// An interval will tick indefinitely. At any time, the `Interval` value can be
57/// dropped. This cancels the interval.
58///
59/// # Panics
60///
61/// This function panics if `period` is zero.
62///
63/// # Examples
64///
65/// ```
66/// use kayrx_timer::{interval_at, Duration, Instant};
67/// use kayrx_karx;
68///
69/// fn main() {
70///          kayrx_karx::exec(async {
71///              let start = Instant::now() + Duration::from_millis(50);
72///              let mut interval = interval_at(start, Duration::from_millis(10));
73///         
74///              interval.tick().await;
75///              interval.tick().await;
76///              interval.tick().await;
77///         
78///              // approximately 70ms have elapsed.
79///          });
80/// }
81/// ```
82pub fn interval_at(start: Instant, period: Duration) -> Interval {
83    assert!(period > Duration::new(0, 0), "`period` must be non-zero.");
84
85    Interval {
86        delay: delay_until(start),
87        period,
88    }
89}
90
91/// Stream returned by [`interval`](interval) and [`interval_at`](interval_at).
92#[derive(Debug)]
93pub struct Interval {
94    /// Future that completes the next time the `Interval` yields a value.
95    delay: Delay,
96
97    /// The duration between values yielded by `Interval`.
98    period: Duration,
99}
100
101impl Interval {
102    #[doc(hidden)] // TODO: document
103    pub fn poll_tick(&mut self, cx: &mut Context<'_>) -> Poll<Instant> {
104        // Wait for the delay to be done
105        ready!(Pin::new(&mut self.delay).poll(cx));
106
107        // Get the `now` by looking at the `delay` deadline
108        let now = self.delay.deadline();
109
110        // The next interval value is `duration` after the one that just
111        // yielded.
112        let next = now + self.period;
113        self.delay.reset(next);
114
115        // Return the current instant
116        Poll::Ready(now)
117    }
118
119    /// Completes when the next instant in the interval has been reached.
120    ///
121    /// # Examples
122    ///
123    /// ```
124    /// use kayrx_timer;
125    /// use std::time::Duration;
126    /// use kayrx_karx;
127    ///
128    /// fn main() {
129    ///          kayrx_karx::exec(async {
130    ///              let mut interval = timer::interval(Duration::from_millis(10));
131    ///         
132    ///              interval.tick().await;
133    ///              interval.tick().await;
134    ///              interval.tick().await;
135    ///         
136    ///              // approximately 20ms have elapsed.
137    ///          });
138    /// }
139    /// ```
140    #[allow(clippy::should_implement_trait)] 
141    pub async fn tick(&mut self) -> Instant {
142        poll_fn(|cx| self.poll_tick(cx)).await
143    }
144}
145
146impl futures_core::stream::Stream for Interval {
147    type Item = Instant;
148
149    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Instant>> {
150        Poll::Ready(Some(ready!(self.poll_tick(cx))))
151    }
152}