use std::time::Duration;
use rateguard_core::gcra::MAX_BURST;
use crate::config::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Limit {
count: u32,
period: Period,
burst: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Period {
Second,
Minute,
Hour,
}
impl Period {
fn seconds(self) -> u64 {
match self {
Period::Second => 1,
Period::Minute => 60,
Period::Hour => 3600,
}
}
}
impl Limit {
fn new(count: u32, period: Period) -> Self {
Self {
count,
period,
burst: (count / 20).clamp(1, MAX_BURST),
}
}
pub fn per_second(n: u32) -> Self {
Self::new(n, Period::Second)
}
pub fn per_minute(n: u32) -> Self {
Self::new(n, Period::Minute)
}
pub fn per_hour(n: u32) -> Self {
Self::new(n, Period::Hour)
}
pub fn burst(self, burst: u32) -> Self {
Self {
burst: burst.max(1),
..self
}
}
pub fn count(&self) -> u32 {
self.count
}
pub fn period(&self) -> Duration {
Duration::from_secs(self.period.seconds())
}
pub fn rate_per_sec(&self) -> f64 {
self.count as f64 / self.period.seconds() as f64
}
#[deprecated(since = "0.7.0", note = "use rate_per_sec")]
pub fn rate(&self) -> u32 {
self.rate_per_sec().ceil() as u32
}
pub fn burst_size(&self) -> u32 {
self.burst
}
pub(crate) fn to_core(self) -> Result<rateguard_core::limiter::Limit, Error> {
if self.count == 0 {
return Err(Error::ZeroLimit);
}
let burst = self.burst_size();
if burst > MAX_BURST {
return Err(Error::TooLargeBurst(burst));
}
Ok(rateguard_core::limiter::Limit {
rate: self.rate_per_sec(),
burst,
})
}
}