apt_swarm/
timers.rs

1use tokio::time::{self, Duration, Instant, Interval};
2
3pub struct EasedInterval {
4    started: Option<Instant>,
5    delay: Duration,
6    interval: Interval,
7}
8
9impl EasedInterval {
10    pub fn new(delay: Duration, interval: Duration) -> Self {
11        Self {
12            started: Some(Instant::now()),
13            delay,
14            interval: time::interval(interval),
15        }
16    }
17
18    pub async fn tick(&mut self) {
19        if let Some(started) = &self.started {
20            let elapsed = Instant::now().duration_since(*started);
21            if let Some(remaining) = self.delay.checked_sub(elapsed) {
22                time::sleep(remaining).await;
23            }
24            self.started = None;
25            self.interval.reset();
26        } else {
27            self.interval.tick().await;
28        }
29    }
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35
36    // this test is somewhat flakey, don't run it by default
37    #[ignore]
38    #[tokio::test]
39    async fn test_eased_interval() {
40        let mut interval =
41            EasedInterval::new(Duration::from_millis(100), Duration::from_millis(50));
42        tokio::select! {
43            _ = interval.tick() => panic!("interval is not expected to tick yet"),
44            _ = time::sleep(Duration::from_millis(50)) => (),
45        };
46        tokio::select! {
47            _ = interval.tick() => (),
48            _ = time::sleep(Duration::from_millis(75)) => panic!("interval was expected to tick"),
49        };
50        tokio::select! {
51            _ = interval.tick() => panic!("interval is not expected to tick yet"),
52            _ = time::sleep(Duration::from_millis(35)) => (),
53        };
54        tokio::select! {
55            _ = interval.tick() => (),
56            _ = time::sleep(Duration::from_millis(25)) => panic!("interval was expected to tick"),
57        };
58        tokio::select! {
59            _ = interval.tick() => (),
60            _ = time::sleep(Duration::from_millis(60)) => panic!("interval was expected to tick"),
61        };
62    }
63}