quota 0.3.2

Fastest Lane-parallel Rate-limiter for Rust
Documentation
use crate::Quota;
use crate::refill_rate::RefillRate;

/// Capacity and refill configuration shared by direct and pooled quota APIs.
///
/// `QuotaPool` folds this policy into precomputed GCRA values. The direct `Quota` counter uses
/// `tick` and `tick_with_interval` when callers want to manually refill a token balance.
#[derive(Clone, Copy, Debug, Default)]
pub struct QuotaPolicy {
    capacity: f64,
    refill_rate_ns: f64,
    refill_interval_ns: u64,
}

impl QuotaPolicy {
    #[inline]
    /// Creates a policy with zero capacity and no refill.
    pub fn new() -> QuotaPolicy {
        QuotaPolicy {
            capacity: 0.0,
            refill_rate_ns: 0.0,
            refill_interval_ns: 0,
        }
    }

    #[inline]
    /// Sets the maximum number of tokens the policy may hold.
    pub fn set_capacity(self, capacity: f64) -> Self {
        Self { capacity, ..self }
    }

    #[inline]
    /// Sets how quickly quota refills over time.
    pub fn set_refill_rate(self, refill_rate: RefillRate) -> Self {
        Self {
            refill_rate_ns: refill_rate.0,
            ..self
        }
    }

    #[inline]
    /// Sets an optional discrete refill interval.
    ///
    /// A zero interval means continuous refill. Nonzero intervals advance refill time in fixed
    /// ticks.
    pub fn set_refill_interval(self, interval: std::time::Duration) -> Self {
        Self {
            refill_interval_ns: interval.as_nanos() as u64,
            ..self
        }
    }

    #[inline]
    /// Applies a continuous refill step to a direct `Quota`.
    pub fn tick(&self, dt_ns: u64, quota: &Quota) {
        let refill_amount = self.refill_rate_ns * dt_ns as f64;
        quota.fill(refill_amount, self.capacity);
    }

    #[inline]
    /// Applies a refill step only after `elapsed_since_refill_ns` reaches the configured interval.
    pub fn tick_with_interval(
        &self,
        dt_ns: u64,
        quota: &Quota,
        elapsed_since_refill_ns: u64,
    ) -> bool {
        if elapsed_since_refill_ns < self.refill_interval_ns {
            return false;
        }
        let refill_amount = self.refill_rate_ns * dt_ns as f64;
        quota.fill(refill_amount, self.capacity);
        true
    }

    #[inline]
    pub(crate) fn capacity(&self) -> f64 {
        self.capacity
    }

    #[inline]
    pub(crate) fn refill_interval_ns(&self) -> u64 {
        self.refill_interval_ns
    }

    #[inline]
    pub(crate) fn refill_rate_ns(&self) -> f64 {
        self.refill_rate_ns
    }
}

#[cfg(test)]
mod tests;