1use std::thread;
39use std::time::Duration;
40use std::time::Instant;
41use std::time::SystemTime;
42
43#[derive(Debug)]
44pub struct ThrottleTimer {
45 maybe_last_called_time: Option<Instant>,
46 total_calls: usize,
47 created_date: SystemTime,
48 max_frequency: Duration,
49 event_name: &'static str,
50}
51
52impl ThrottleTimer {
71 pub fn new(max_frequency: std::time::Duration, event_name: &'static str) -> Self {
72 Self {
73 maybe_last_called_time: None,
74 max_frequency,
75 event_name,
76 total_calls: 0,
77 created_date: SystemTime::now(),
78 }
79 }
80 pub const fn event_name(&self) -> &str {
81 self.event_name
82 }
83 pub const fn total_calls(&self) -> &usize {
84 &self.total_calls
85 }
86 pub const fn max_frequency(&self) -> &Duration {
87 &self.max_frequency
88 }
89 pub const fn created_date(&self) -> SystemTime {
90 self.created_date
91 }
92 pub fn wait_time(&self) -> Duration {
93 match self.maybe_last_called_time {
94 None => Duration::from_secs(0),
95 Some(last_time) => {
96 (self.max_frequency
97 - Instant::now()
98 .duration_since(last_time)
99 .min(self.max_frequency))
100 }
101 }
102 }
103
104 pub fn print_stats(&self) {
106 match self.created_date.elapsed() {
107 Ok(created_time_elapsed) => {
108 println!(
109 "{} called {}/sec, total calls {}, has been running for {:?}",
110 self.event_name,
111 created_time_elapsed.as_secs() / self.total_calls as u64,
112 self.total_calls,
113 created_time_elapsed,
114 );
115 }
116 Err(e) => eprintln!("{:?}", e),
117 }
118 }
119
120 pub fn can_run(&mut self) -> bool {
123 match self.maybe_last_called_time {
124 None => true,
125 Some(last_time) => Instant::now().duration_since(last_time) >= self.max_frequency,
126 }
127 }
128
129 pub fn run_throttle_cb(&mut self, success: &mut FnMut(), throttled: &mut FnMut()) -> bool {
130 let run_flag: bool = self.can_run();
131
132 if run_flag {
133 self.maybe_last_called_time = Some(Instant::now());
134 self.total_calls += 1;
135 success();
136 } else {
137 throttled()
138 }
139 run_flag
140 }
141
142 pub fn run(&mut self, success: &mut FnMut()) -> bool {
145 self.run_throttle_cb(success, &mut || {})
146 }
147
148 pub fn run_wait(&mut self, success: &mut FnMut()) {
151 thread::sleep(self.wait_time());
152 self.run_throttle_cb(success, &mut || {});
153 }
154
155 pub fn run_with_msg(&mut self, success: &mut FnMut()) -> bool {
157 let did_run = self.run(success);
158 if !did_run {
159 println!(
160 "{} throttled, last time {:?}",
161 self.event_name(),
162 Instant::now().duration_since(self.maybe_last_called_time.unwrap())
163 );
164 }
165 did_run
166 }
167}
168
169#[cfg(test)]
170mod test {
171 use super::ThrottleTimer;
172 use std::{thread, time::Duration};
173
174 #[test]
175 fn test_run() {
176 let mut break_timer: ThrottleTimer =
177 ThrottleTimer::new(Duration::from_secs(45_000_u64), &"Break");
178 let run_flag = break_timer.run(&mut || {});
179
180 assert!(run_flag);
182 if run_flag {
183 println!("timer do run flag is set to true")
184 }
185 break_timer.event_name();
186 break_timer.total_calls();
187 break_timer.max_frequency();
188 break_timer.created_date();
189 }
190
191 #[test]
192 fn test_run_with_msg() {
193 let mut break_timer: ThrottleTimer =
194 ThrottleTimer::new(Duration::from_secs(45_000_u64), &"Break");
195 let run_flag = break_timer.run_with_msg(&mut || {});
196
197 assert!(run_flag);
199 }
200
201 #[test]
202 fn test_call_count() {
203 let mut break_timer: ThrottleTimer =
204 ThrottleTimer::new(Duration::from_nanos(1_u64), &"Break");
205
206 for _ in 0..100 {
207 assert_eq!(break_timer.run(&mut || {}), true);
208 thread::sleep(Duration::from_nanos(100_u64));
209 }
210
211 assert_eq!(break_timer.total_calls, 100);
213 break_timer.print_stats();
214 }
215
216 #[test]
217 fn test_can_run() {
218 let mut break_timer: ThrottleTimer =
219 ThrottleTimer::new(Duration::from_secs(1_u64), &"Break");
220
221 assert!(break_timer.run(&mut || {}));
222 for _ in 0..100 {
223 assert!(!break_timer.can_run());
224 assert!(!break_timer.run(&mut || {}));
225 }
226
227 assert_eq!(break_timer.total_calls, 1);
229 break_timer.print_stats();
230 }
231
232 #[test]
233 fn test_print_debug() {
234 println!(
235 "{:?}",
236 ThrottleTimer::new(Duration::from_nanos(1_u64), &"Break")
237 );
238 }
239
240 #[test]
241 fn test_in_loop() {
242 let mut break_timer = ThrottleTimer::new(Duration::from_secs(10_u64), &"Break");
243
244 assert!(break_timer.run(&mut || {}));
246 for _ in 0..100 {
247 assert!(!break_timer.run(&mut || {}));
250 }
251 assert_eq!(break_timer.total_calls(), &1);
252 }
253
254 #[test]
255 fn test_run_wait() {
256 let mut break_timer = ThrottleTimer::new(Duration::from_nanos(10_u64), &"Break");
257
258 break_timer.run_wait(&mut || {});
259 break_timer.run_wait(&mut || {});
260 break_timer.run_wait(&mut || {});
261 assert_eq!(break_timer.total_calls(), &3);
262 }
263
264 #[test]
265 fn test_with_delay() {
266 let mut snack_timer: ThrottleTimer =
267 ThrottleTimer::new(Duration::from_secs(1_u64), &"Snack");
268 let run_flag = snack_timer.run(&mut || {});
269
270 assert!(run_flag);
272
273 let run_flag2 = snack_timer.run_with_msg(&mut || {});
274
275 assert_eq!(run_flag2, false);
277
278 thread::sleep(snack_timer.max_frequency);
279 assert!(snack_timer.run(&mut || {}));
280 thread::sleep(Duration::from_millis(100_u64));
281 assert!(!snack_timer.run(&mut || {}));
282 thread::sleep(Duration::from_secs(1_u64));
283 assert!(snack_timer.run(&mut || {}));
284 }
285}