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    #[tokio::test]
37    async fn test_eased_interval() {
38        let mut interval =
39            EasedInterval::new(Duration::from_millis(100), Duration::from_millis(50));
40        tokio::select! {
41            _ = interval.tick() => panic!("interval is not expected to tick yet"),
42            _ = time::sleep(Duration::from_millis(50)) => (),
43        };
44        tokio::select! {
45            _ = interval.tick() => (),
46            _ = time::sleep(Duration::from_millis(75)) => panic!("interval was expected to tick"),
47        };
48        tokio::select! {
49            _ = interval.tick() => panic!("interval is not expected to tick yet"),
50            _ = time::sleep(Duration::from_millis(35)) => (),
51        };
52        tokio::select! {
53            _ = interval.tick() => (),
54            _ = time::sleep(Duration::from_millis(25)) => panic!("interval was expected to tick"),
55        };
56        tokio::select! {
57            _ = interval.tick() => (),
58            _ = time::sleep(Duration::from_millis(60)) => panic!("interval was expected to tick"),
59        };
60    }
61}