use std::hash::Hash;
use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Quota {
pub max: usize,
pub per_ms: u64,
pub burst: Option<usize>,
}
impl Quota {
pub const fn new(max: usize, per_ms: u64) -> Self {
Self {
max,
per_ms,
burst: None,
}
}
pub const fn with_burst(max: usize, per_ms: u64, burst: usize) -> Self {
Self {
max,
per_ms,
burst: Some(burst),
}
}
pub const fn per_second(max: usize) -> Self {
Self::new(max, 1000)
}
pub const fn per_minute(max: usize) -> Self {
Self::new(max, 60_000)
}
pub const fn per_hour(max: usize) -> Self {
Self::new(max, 3_600_000)
}
pub const fn per_day(max: usize) -> Self {
Self::new(max, 86_400_000)
}
pub const fn per(&self) -> Duration {
Duration::from_millis(self.per_ms)
}
pub const fn burst(&self) -> usize {
match self.burst {
Some(burst) => burst,
None => self.max,
}
}
pub const fn fingerprint(self) -> QuotaFingerprint {
QuotaFingerprint {
max: self.max,
per_ms: self.per_ms,
burst: self.burst,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct QuotaFingerprint {
pub max: usize,
pub per_ms: u64,
pub burst: Option<usize>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fingerprint_distinguishes_quotas() {
assert_ne!(
Quota::new(1, 1000).fingerprint(),
Quota::new(2, 1000).fingerprint()
);
assert_ne!(
Quota::new(5, 1000).fingerprint(),
Quota::new(5, 2000).fingerprint()
);
assert_ne!(
Quota::with_burst(5, 1000, 10).fingerprint(),
Quota::new(5, 1000).fingerprint()
);
}
#[test]
fn per_second_sets_one_second_period() {
let quota = Quota::per_second(10);
assert_eq!(quota.max, 10);
assert_eq!(quota.per_ms, 1000);
}
}