1use ring_vec::RingVec;
2use std::time::{Duration, Instant};
3
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub struct RateLimit {
7 pub count: usize,
8 pub period: Duration,
9}
10
11impl RateLimit {
12 pub fn new(count: usize, period: Duration) -> Option<RateLimit> {
15 if count > 0 {
16 Some(RateLimit { count, period })
17 } else {
18 None
19 }
20 }
21}
22
23pub struct RateLimiter {
26 pub limit: RateLimit,
27 readings: RingVec<Instant>,
28}
29
30impl RateLimiter {
31 pub fn new(limit: RateLimit) -> RateLimiter {
33 RateLimiter { limit, readings: RingVec::new(limit.count) }
34 }
35
36 pub fn new_preallocated(limit: RateLimit) -> RateLimiter {
39 RateLimiter { limit, readings: RingVec::new_preallocated(limit.count) }
40 }
41
42 pub fn check(&mut self) -> bool { self.check_at(Instant::now()) }
46
47 pub fn check_at(&mut self, instant: Instant) -> bool {
52 if self.readings.push(instant).is_ok() { return true; }
53 let reclaimed = self.sweep(instant);
54 if reclaimed {
55 self.readings.push(instant).unwrap();
56 }
57 reclaimed
58 }
59
60 pub fn sweep(&mut self, instant: Instant) -> bool {
63 let bench = instant - self.limit.period;
64 let mut reclaimed = false;
65 while let Some(x) = self.readings.peek() {
66 if *x < bench {
67 reclaimed = true;
68 self.readings.pop();
69 } else { break; }
70 }
71 reclaimed
72 }
73}