#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RateLimitError {
LimitZero,
RemainingExceedsLimit,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RateLimit {
limit: u64,
remaining: u64,
reset_epoch_seconds: u64,
}
impl RateLimit {
pub const fn new(
limit: u64,
remaining: u64,
reset_epoch_seconds: u64,
) -> Result<Self, RateLimitError> {
if limit == 0 {
return Err(RateLimitError::LimitZero);
}
if remaining > limit {
return Err(RateLimitError::RemainingExceedsLimit);
}
Ok(Self {
limit,
remaining,
reset_epoch_seconds,
})
}
#[must_use]
pub const fn limit(self) -> u64 {
self.limit
}
#[must_use]
pub const fn remaining(self) -> u64 {
self.remaining
}
#[must_use]
pub const fn reset_epoch_seconds(self) -> u64 {
self.reset_epoch_seconds
}
}
#[cfg(test)]
mod tests {
use super::{RateLimit, RateLimitError};
#[test]
fn rejects_incoherent_metadata() {
assert_eq!(RateLimit::new(0, 0, 42), Err(RateLimitError::LimitZero));
assert_eq!(
RateLimit::new(10, 11, 42),
Err(RateLimitError::RemainingExceedsLimit)
);
}
#[test]
fn exposes_coherent_metadata() {
let rate_limit = RateLimit::new(3600, 3599, 42);
assert!(rate_limit.is_ok());
let Ok(rate_limit) = rate_limit else { return };
assert_eq!(rate_limit.limit(), 3600);
assert_eq!(rate_limit.remaining(), 3599);
assert_eq!(rate_limit.reset_epoch_seconds(), 42);
}
}