common_batcher/
flush_timer.rs1use std::pin::Pin;
16
17use tokio::time::{Instant, Sleep, sleep_until};
18
19#[derive(Default)]
24pub struct FlushTimer {
25 deadline: Option<Instant>,
26 sleep: Option<Pin<Box<Sleep>>>,
27}
28
29impl FlushTimer {
30 pub fn new() -> Self {
32 Self::default()
33 }
34
35 pub fn set_deadline(&mut self, deadline: Option<Instant>) {
41 if self.deadline == deadline {
42 return;
43 }
44 self.deadline = deadline;
45 if let Some(deadline) = deadline {
46 match &mut self.sleep {
47 Some(sleep) => sleep.as_mut().reset(deadline),
48 None => self.sleep = Some(Box::pin(sleep_until(deadline))),
49 }
50 }
51 }
52
53 pub async fn wait(&mut self) {
58 if self.deadline.is_some()
59 && let Some(sleep) = &mut self.sleep
60 {
61 sleep.as_mut().await;
62 } else {
63 std::future::pending::<()>().await;
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use std::future::{Future, poll_fn};
71 use std::task::Poll;
72 use std::time::Duration;
73
74 use super::*;
75
76 async fn is_ready(timer: &mut FlushTimer) -> bool {
77 let wait = timer.wait();
78 tokio::pin!(wait);
79 poll_fn(|cx| Poll::Ready(wait.as_mut().poll(cx).is_ready())).await
80 }
81
82 #[test]
83 fn test_create_without_runtime() {
84 let mut timer = FlushTimer::new();
85 timer.set_deadline(None);
86 assert!(timer.sleep.is_none());
87 }
88
89 #[tokio::test(start_paused = true)]
90 async fn test_deadline_and_cancelled_wait() {
91 let mut timer = FlushTimer::new();
92 assert!(!is_ready(&mut timer).await);
93 let deadline = Instant::now() + Duration::from_millis(10);
94 timer.set_deadline(Some(deadline));
95 assert!(!is_ready(&mut timer).await);
96 tokio::time::advance(Duration::from_millis(9)).await;
97 let sleep = timer.sleep.as_ref().unwrap().as_ref().get_ref() as *const Sleep;
100 timer.set_deadline(Some(deadline));
101 assert_eq!(
102 sleep,
103 timer.sleep.as_ref().unwrap().as_ref().get_ref() as *const Sleep
104 );
105 assert!(!is_ready(&mut timer).await);
106 tokio::time::advance(Duration::from_millis(1)).await;
107 assert!(is_ready(&mut timer).await);
108 }
109
110 #[tokio::test(start_paused = true)]
111 async fn test_disable_and_rearm_reuses_sleep() {
112 let mut timer = FlushTimer::new();
113 timer.set_deadline(Some(Instant::now()));
114 assert!(is_ready(&mut timer).await);
115 let sleep = timer.sleep.as_ref().unwrap().as_ref().get_ref() as *const Sleep;
116 timer.set_deadline(None);
117 assert!(!is_ready(&mut timer).await);
118 assert!(!is_ready(&mut timer).await);
119 timer.set_deadline(Some(Instant::now() + Duration::from_millis(5)));
120 assert_eq!(
121 sleep,
122 timer.sleep.as_ref().unwrap().as_ref().get_ref() as *const Sleep
123 );
124 assert!(!is_ready(&mut timer).await);
125 tokio::time::advance(Duration::from_millis(5)).await;
126 assert!(is_ready(&mut timer).await);
127 }
128
129 #[tokio::test(start_paused = true)]
130 async fn test_change_armed_deadline() {
131 let mut timer = FlushTimer::new();
132 let now = Instant::now();
133 timer.set_deadline(Some(now + Duration::from_millis(5)));
134 assert!(!is_ready(&mut timer).await);
135 timer.set_deadline(Some(now + Duration::from_millis(10)));
136 tokio::time::advance(Duration::from_millis(5)).await;
137 assert!(!is_ready(&mut timer).await);
138 timer.set_deadline(Some(Instant::now()));
139 assert!(is_ready(&mut timer).await);
140 }
141}