use core::time::Duration;
use better_bucket::{Bucket, BucketConfig};
use clock_lib::Clock;
use crate::algorithm::Algorithm;
use crate::decision::Decision;
use crate::quota::Quota;
#[cfg(feature = "algorithms")]
mod fixed_window;
#[cfg(feature = "algorithms")]
mod leaky;
#[cfg(feature = "algorithms")]
mod sliding_counter;
#[cfg(feature = "algorithms")]
mod sliding_log;
#[cfg(feature = "algorithms")]
use self::fixed_window::FixedWindow;
#[cfg(feature = "algorithms")]
use self::leaky::LeakyBucket;
#[cfg(feature = "algorithms")]
use self::sliding_counter::SlidingCounter;
#[cfg(feature = "algorithms")]
use self::sliding_log::SlidingLog;
pub(crate) enum AlgoState<C: Clock> {
TokenBucket(Bucket<C>),
#[cfg(feature = "algorithms")]
LeakyBucket(LeakyBucket),
#[cfg(feature = "algorithms")]
FixedWindow(FixedWindow),
#[cfg(feature = "algorithms")]
SlidingLog(SlidingLog),
#[cfg(feature = "algorithms")]
SlidingCounter(SlidingCounter),
}
impl<C: Clock> AlgoState<C> {
#[cfg_attr(not(feature = "algorithms"), allow(unused_variables))]
pub(crate) fn new(algorithm: Algorithm, quota: &Quota, clock: C, now: Duration) -> Self {
match algorithm {
Algorithm::TokenBucket => Self::TokenBucket(token_bucket(quota, clock)),
#[cfg(feature = "algorithms")]
Algorithm::LeakyBucket => Self::LeakyBucket(LeakyBucket::new(quota, now)),
#[cfg(feature = "algorithms")]
Algorithm::FixedWindow => Self::FixedWindow(FixedWindow::new(quota, now)),
#[cfg(feature = "algorithms")]
Algorithm::SlidingWindowLog => Self::SlidingLog(SlidingLog::new(quota)),
#[cfg(feature = "algorithms")]
Algorithm::SlidingWindowCounter => {
Self::SlidingCounter(SlidingCounter::new(quota, now))
}
}
}
#[cfg_attr(not(feature = "algorithms"), allow(unused_variables))]
pub(crate) fn acquire(&self, n: u32, now: Duration) -> Decision {
match self {
Self::TokenBucket(bucket) => bucket.acquire(n).into(),
#[cfg(feature = "algorithms")]
Self::LeakyBucket(state) => state.acquire(n, now),
#[cfg(feature = "algorithms")]
Self::FixedWindow(state) => state.acquire(n, now),
#[cfg(feature = "algorithms")]
Self::SlidingLog(state) => state.acquire(n, now),
#[cfg(feature = "algorithms")]
Self::SlidingCounter(state) => state.acquire(n, now),
}
}
}
fn token_bucket<C: Clock>(quota: &Quota, clock: C) -> Bucket<C> {
let limit = quota.limit();
let burst = quota.burst();
let period = quota.period();
if limit == 0 || burst == 0 {
return Bucket::per_duration(0, period).with_clock(clock);
}
if burst == limit {
return Bucket::per_duration(limit, period).with_clock(clock);
}
match BucketConfig::new(burst, limit, period, burst) {
Ok(config) => Bucket::from_config(config).with_clock(clock),
Err(_) => Bucket::per_duration(limit, period).with_clock(clock),
}
}