use std::collections::VecDeque;
use std::time::{Duration, Instant};
pub struct RateBucket {
events: VecDeque<Instant>,
window: Duration,
capacity: usize,
}
impl RateBucket {
pub fn new(capacity: usize, window: Duration) -> Self {
Self {
events: VecDeque::new(),
window,
capacity,
}
}
pub fn record_and_check(&mut self) -> bool {
let now = Instant::now();
self.evict_old(now);
self.events.push_back(now);
self.events.len() > self.capacity
}
pub fn count(&self) -> usize {
self.events.len()
}
fn evict_old(&mut self, now: Instant) {
while let Some(&front) = self.events.front() {
if now.duration_since(front) > self.window {
self.events.pop_front();
} else {
break;
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bucket_under_capacity_returns_false() {
let mut bucket = RateBucket::new(5, Duration::from_secs(60));
for _ in 0..5 {
assert!(!bucket.record_and_check());
}
}
#[test]
fn bucket_over_capacity_returns_true() {
let mut bucket = RateBucket::new(5, Duration::from_secs(60));
for _ in 0..5 {
bucket.record_and_check();
}
assert!(bucket.record_and_check(), "6th event should exceed cap=5");
}
}