use crate::lib::*;
use crate::{
algorithms::{Algorithm, DefaultAlgorithm},
clock, InconsistentCapacity, NegativeMultiDecision,
};
#[derive(Debug, Clone)]
pub struct DirectRateLimiter<
A: Algorithm<C::Instant> = DefaultAlgorithm,
C: clock::Clock = clock::DefaultClock,
> {
state: A::BucketState,
algorithm: A,
clock: C,
}
impl<A, C> DirectRateLimiter<A, C>
where
C: clock::Clock,
A: Algorithm<C::Instant>,
{
pub fn new(capacity: NonZeroU32, per_time_unit: Duration) -> Self {
DirectRateLimiter {
state: <A as Algorithm<C::Instant>>::BucketState::default(),
algorithm: <A as Algorithm<C::Instant>>::construct(
capacity,
nonzero!(1u32),
per_time_unit,
)
.unwrap(),
clock: Default::default(),
}
}
pub fn per_second(capacity: NonZeroU32) -> Self {
Self::new(capacity, Duration::from_secs(1))
}
pub fn build_with_capacity(capacity: NonZeroU32) -> Builder<C, A> {
Builder {
capacity,
cell_weight: nonzero!(1u32),
time_unit: Duration::from_secs(1),
end_result: PhantomData,
clock: Default::default(),
}
}
pub fn check_at(
&mut self,
at: C::Instant,
) -> Result<(), <A as Algorithm<C::Instant>>::NegativeDecision> {
self.algorithm.test_and_update(&self.state, at)
}
pub fn check_n_at(
&mut self,
n: u32,
at: C::Instant,
) -> Result<(), NegativeMultiDecision<<A as Algorithm<C::Instant>>::NegativeDecision>> {
self.algorithm.test_n_and_update(&self.state, n, at)
}
pub fn check(&mut self) -> Result<(), <A as Algorithm<C::Instant>>::NegativeDecision> {
self.algorithm
.test_and_update(&self.state, self.clock.now())
}
pub fn check_n(
&mut self,
n: u32,
) -> Result<(), NegativeMultiDecision<<A as Algorithm<C::Instant>>::NegativeDecision>> {
self.algorithm
.test_n_and_update(&self.state, n, self.clock.now())
}
}
pub struct Builder<C, A>
where
C: clock::Clock,
A: Algorithm<C::Instant> + Sized,
{
capacity: NonZeroU32,
cell_weight: NonZeroU32,
time_unit: Duration,
end_result: PhantomData<A>,
clock: C,
}
impl<C, A> Builder<C, A>
where
C: clock::Clock,
A: Algorithm<C::Instant> + Sized,
{
pub fn cell_weight(
&mut self,
weight: NonZeroU32,
) -> Result<&mut Builder<C, 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<C, A> {
self.time_unit = time_unit;
self
}
pub fn using_clock(&mut self, clock: C) -> &mut Builder<C, A> {
self.clock = clock;
self
}
pub fn build(&self) -> Result<DirectRateLimiter<A, C>, InconsistentCapacity> {
Ok(DirectRateLimiter {
state: <A as Algorithm<C::Instant>>::BucketState::default(),
algorithm: <A as Algorithm<C::Instant>>::construct(
self.capacity,
self.cell_weight,
self.time_unit,
)?,
clock: self.clock.clone(),
})
}
}