Skip to main content

moirai_async/timer/
interval.rs

1use std::future::Future;
2use std::pin::Pin;
3use std::task::{Context, Poll};
4use std::time::{Duration, Instant};
5
6use crate::timer::clamped_deadline;
7use crate::timer::delay::Delay;
8
9/// Interval timer for repeated operations
10pub struct Interval {
11    pub(super) next_tick: Instant,
12    pub(super) period: Duration,
13    pub(super) delay: Option<Delay>,
14}
15
16impl Interval {
17    pub(super) fn new(period: Duration) -> Self {
18        let next_tick = clamped_deadline(Instant::now(), period);
19        Self {
20            next_tick,
21            period,
22            delay: None,
23        }
24    }
25
26    pub(super) fn new_at(start: Instant, period: Duration) -> Self {
27        Self {
28            next_tick: start,
29            period,
30            delay: None,
31        }
32    }
33
34    /// Get the next tick time
35    pub fn next_tick(&self) -> Instant {
36        self.next_tick
37    }
38
39    /// Reset the interval to start from now
40    pub fn reset(&mut self) {
41        self.next_tick = clamped_deadline(Instant::now(), self.period);
42        self.delay = None;
43    }
44
45    /// Change the interval period
46    pub fn set_period(&mut self, period: Duration) {
47        self.period = period;
48        self.next_tick = clamped_deadline(Instant::now(), period);
49        self.delay = None;
50    }
51
52    /// Wait for the next tick
53    pub async fn next(&mut self) -> Instant {
54        if self.delay.is_none() {
55            self.delay = Some(Delay::until(self.next_tick));
56        }
57
58        if let Some(delay) = &mut self.delay {
59            delay.await;
60            let tick_time = self.next_tick;
61            self.next_tick = clamped_deadline(self.next_tick, self.period);
62            self.delay = None;
63            tick_time
64        } else {
65            Instant::now()
66        }
67    }
68}
69
70impl Future for Interval {
71    type Output = Instant;
72
73    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
74        if self.delay.is_none() {
75            self.delay = Some(Delay::until(self.next_tick));
76        }
77
78        if let Some(delay) = &mut self.delay {
79            match Pin::new(delay).poll(cx) {
80                Poll::Ready(()) => {
81                    let tick_time = self.next_tick;
82                    let period = self.period;
83                    self.next_tick = clamped_deadline(self.next_tick, period);
84                    self.delay = None;
85                    Poll::Ready(tick_time)
86                }
87                Poll::Pending => Poll::Pending,
88            }
89        } else {
90            Poll::Pending
91        }
92    }
93}