use std::fmt;
use std::sync::atomic::{AtomicU64, Ordering};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Default)]
pub struct AtomicRateMetrics {
allowed: AtomicU64,
limited: AtomicU64,
}
impl AtomicRateMetrics {
pub const fn new() -> Self {
Self {
allowed: AtomicU64::new(0),
limited: AtomicU64::new(0),
}
}
#[inline]
pub fn record_allowed(&self) {
self.allowed.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn record_limited(&self) {
self.limited.fetch_add(1, Ordering::Relaxed);
}
pub fn snapshot(&self) -> RateMetrics {
RateMetrics {
allowed: self.allowed.load(Ordering::Relaxed),
limited: self.limited.load(Ordering::Relaxed),
}
}
pub fn reset(&self) {
self.allowed.store(0, Ordering::Relaxed);
self.limited.store(0, Ordering::Relaxed);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RateMetrics {
pub allowed: u64,
pub limited: u64,
}
impl RateMetrics {
#[inline]
pub fn total_requests(&self) -> u64 {
self.allowed.saturating_add(self.limited)
}
#[inline]
pub fn limited_ratio(&self) -> f64 {
let total = self.total_requests();
if total == 0 {
0.0
} else {
self.limited as f64 / total as f64
}
}
#[inline]
pub fn allowed_ratio(&self) -> f64 {
let total = self.total_requests();
if total == 0 {
1.0
} else {
self.allowed as f64 / total as f64
}
}
}
impl fmt::Display for RateMetrics {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"RateMetrics {{ allowed: {}, limited: {}, throttle_rate: {:.2}% }}",
self.allowed,
self.limited,
self.limited_ratio() * 100.0
)
}
}