use lib::*;
use {
algorithms::{Algorithm, DefaultAlgorithm},
instant, InconsistentCapacity, NegativeMultiDecision,
};
#[derive(Debug, Clone)]
pub struct DirectRateLimiter<
A: Algorithm<P> = DefaultAlgorithm,
P: instant::Relative = instant::TimeSource,
> {
state: A::BucketState,
algorithm: A,
}
impl<A, P> DirectRateLimiter<A, P>
where
P: instant::Relative,
A: Algorithm<P>,
{
pub fn new(capacity: NonZeroU32, per_time_unit: Duration) -> Self {
DirectRateLimiter {
state: <A as Algorithm<P>>::BucketState::default(),
algorithm: <A as Algorithm<P>>::construct(capacity, nonzero!(1u32), per_time_unit)
.unwrap(),
}
}
pub fn per_second(capacity: NonZeroU32) -> Self {
Self::new(capacity, Duration::from_secs(1))
}
pub fn build_with_capacity(capacity: NonZeroU32) -> Builder<P, A> {
Builder {
capacity,
cell_weight: nonzero!(1u32),
time_unit: Duration::from_secs(1),
end_result: PhantomData,
point_result: PhantomData,
}
}
pub fn check_at(&mut self, at: P) -> Result<(), <A as Algorithm<P>>::NegativeDecision> {
self.algorithm.test_and_update(&self.state, at)
}
pub fn check_n_at(
&mut self,
n: u32,
at: P,
) -> Result<(), NegativeMultiDecision<<A as Algorithm<P>>::NegativeDecision>> {
self.algorithm.test_n_and_update(&self.state, n, at)
}
}
impl<A, P> DirectRateLimiter<A, P>
where
P: instant::Absolute,
A: Algorithm<P>,
{
pub fn check(&mut self) -> Result<(), <A as Algorithm<P>>::NegativeDecision> {
self.algorithm.test_and_update(&self.state, P::now())
}
pub fn check_n(
&mut self,
n: u32,
) -> Result<(), NegativeMultiDecision<<A as Algorithm<P>>::NegativeDecision>> {
self.algorithm.test_n_and_update(&self.state, n, P::now())
}
}
pub struct Builder<P, A>
where
P: instant::Relative,
A: Algorithm<P> + Sized,
{
capacity: NonZeroU32,
cell_weight: NonZeroU32,
time_unit: Duration,
end_result: PhantomData<A>,
point_result: PhantomData<P>,
}
impl<P, A> Builder<P, A>
where
P: instant::Relative,
A: Algorithm<P> + Sized,
{
pub fn cell_weight(
&mut self,
weight: NonZeroU32,
) -> Result<&mut Builder<P, A>, InconsistentCapacity> {
if self.cell_weight > self.capacity {
return Err(InconsistentCapacity::new(self.capacity, self.cell_weight));
}
self.cell_weight = weight;
Ok(self)
}
pub fn per(&mut self, time_unit: Duration) -> &mut Builder<P, A> {
self.time_unit = time_unit;
self
}
pub fn build(&self) -> Result<DirectRateLimiter<A, P>, InconsistentCapacity> {
Ok(DirectRateLimiter {
state: <A as Algorithm<P>>::BucketState::default(),
algorithm: <A as Algorithm<P>>::construct(
self.capacity,
self.cell_weight,
self.time_unit,
)?,
})
}
}