use std::time::Instant;
#[derive(Debug)]
pub struct TokenBucket {
tokens: f64,
max_tokens: f64,
refill_rate: f64,
last_refill: Instant,
}
impl TokenBucket {
pub fn new(max_freq: f64) -> Self {
Self {
tokens: max_freq,
max_tokens: max_freq,
refill_rate: max_freq,
last_refill: Instant::now(),
}
}
pub fn try_acquire(&mut self) -> bool {
self.refill();
if self.tokens >= 1.0 {
self.tokens -= 1.0;
true
} else {
false
}
}
fn refill(&mut self) {
let now = Instant::now();
let elapsed = now.duration_since(self.last_refill).as_secs_f64();
self.tokens = (self.tokens + elapsed * self.refill_rate).min(self.max_tokens);
self.last_refill = now;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_token_bucket_basic() {
let mut bucket = TokenBucket::new(2.0);
assert!(bucket.try_acquire());
assert!(bucket.try_acquire());
assert!(!bucket.try_acquire());
}
#[test]
fn test_token_bucket_refills() {
let mut bucket = TokenBucket::new(100.0);
for _ in 0..100 {
bucket.try_acquire();
}
assert!(!bucket.try_acquire());
bucket.last_refill -= std::time::Duration::from_secs(1);
assert!(bucket.try_acquire());
}
}