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 #[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}