pub mod gcra;
pub mod leaky_bucket;
pub use self::gcra::*;
pub use self::leaky_bucket::*;
use crate::{clock, InconsistentCapacity, NegativeMultiDecision};
use crate::lib::*;
pub type DefaultAlgorithm = LeakyBucket;
pub trait NonConformance<P: clock::Reference = <clock::DefaultClock as clock::Clock>::Instant> {
fn earliest_possible(&self) -> P;
fn wait_time_from(&self, from: P) -> Duration {
let earliest = self.earliest_possible();
earliest.duration_since(earliest.min(from))
}
}
pub trait Algorithm<P: clock::Reference = <clock::DefaultClock as clock::Clock>::Instant>:
Send + Sync + Sized + fmt::Debug
{
type BucketState: RateLimitState<Self, P>;
type NegativeDecision: PartialEq + fmt::Display + fmt::Debug + Send + Sync;
fn construct(
capacity: NonZeroU32,
cell_weight: NonZeroU32,
per_time_unit: Duration,
) -> Result<Self, InconsistentCapacity>;
fn test_n_and_update(
&self,
state: &Self::BucketState,
n: u32,
at: P,
) -> Result<(), NegativeMultiDecision<Self::NegativeDecision>>;
fn test_and_update(
&self,
state: &Self::BucketState,
at: P,
) -> Result<(), Self::NegativeDecision> {
match self.test_n_and_update(state, 1, at) {
Ok(()) => Ok(()),
Err(NegativeMultiDecision::BatchNonConforming(1, nc)) => Err(nc),
Err(other) => unreachable!(
"BUG: measuring a batch of size 1 reported insufficient capacity: {:?}",
other
),
}
}
}
pub trait RateLimitState<P, I: clock::Reference>: Default + Send + Sync + Eq + fmt::Debug {
fn last_touched(&self, params: &P) -> Option<I>;
}
#[cfg(feature = "std")]
mod std {
use crate::clock;
use evmap::ShallowCopy;
pub trait KeyableRateLimitState<P, I: clock::Reference>:
super::RateLimitState<P, I> + ShallowCopy
{
}
#[cfg(feature = "std")]
impl<T, P, I> KeyableRateLimitState<P, I> for T
where
T: super::RateLimitState<P, I> + ShallowCopy,
I: clock::Reference,
{
}
}
#[cfg(feature = "std")]
pub use self::std::*;