use std::time::Duration;
use crate::quota::Nanos;
#[derive(Debug, Clone, Copy)]
pub struct RateLimitInfo {
pub limit: u32,
pub remaining: u32,
pub reset_at: Nanos,
}
#[derive(Debug, Clone, Copy)]
pub struct RateLimited {
pub limit: u32,
pub retry_after: Duration,
pub reset_at: Nanos,
}
pub fn check_gcra(
tat: Option<Nanos>,
now: Nanos,
emission_interval: Nanos,
burst_offset: Nanos,
cost: u32,
) -> Result<(Nanos, RateLimitInfo), RateLimited> {
let limit = (burst_offset / emission_interval) as u32;
let tat = tat.unwrap_or(now);
let increment = emission_interval.saturating_mul(cost as Nanos);
let new_tat = tat.max(now) + increment;
let allow_at = new_tat.saturating_sub(burst_offset);
if allow_at > now {
let retry_after_nanos = allow_at - now;
return Err(RateLimited {
limit,
retry_after: Duration::from_nanos(retry_after_nanos),
reset_at: new_tat,
});
}
let diff = burst_offset.saturating_sub(new_tat.saturating_sub(now));
let remaining = (diff / emission_interval) as u32;
Ok((
new_tat,
RateLimitInfo {
limit,
remaining,
reset_at: new_tat,
},
))
}