use core::time::Duration;
use clock_lib::SystemClock;
use crate::bucket::Bucket;
use crate::config::BucketConfig;
use crate::error::BucketError;
#[derive(Debug, Clone, Default)]
#[must_use = "a builder does nothing until `.build()` is called"]
pub struct BucketBuilder {
capacity: u32,
refill_amount: u32,
refill_period: Duration,
initial: Option<u32>,
}
impl BucketBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn capacity(mut self, capacity: u32) -> Self {
self.capacity = capacity;
self
}
pub fn refill(mut self, amount: u32, period: Duration) -> Self {
self.refill_amount = amount;
self.refill_period = period;
self
}
pub fn initial(mut self, initial: u32) -> Self {
self.initial = Some(initial);
self
}
pub fn build(self) -> Result<Bucket<SystemClock>, BucketError> {
let initial = self.initial.unwrap_or(self.capacity);
let config = BucketConfig::new(
self.capacity,
self.refill_amount,
self.refill_period,
initial,
)?;
Ok(Bucket::from_config(config))
}
}
impl Bucket<SystemClock> {
#[must_use = "a builder does nothing until `.build()` is called"]
pub fn builder() -> BucketBuilder {
BucketBuilder::new()
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::BucketBuilder;
use crate::bucket::Bucket;
use crate::error::BucketError;
use core::time::Duration;
#[test]
fn test_builds_configured_bucket() {
let bucket = Bucket::builder()
.capacity(500)
.refill(100, Duration::from_secs(1))
.initial(0)
.build()
.unwrap();
assert_eq!(bucket.capacity(), 500);
assert_eq!(bucket.available(), 0);
assert_eq!(bucket.config().refill_amount(), 100);
}
#[test]
fn test_initial_defaults_to_full() {
let bucket = Bucket::builder()
.capacity(40)
.refill(40, Duration::from_secs(1))
.build()
.unwrap();
assert_eq!(bucket.available(), 40);
}
#[test]
fn test_empty_builder_is_rejected() {
assert_eq!(
BucketBuilder::new().build().unwrap_err(),
BucketError::ZeroCapacity
);
}
#[test]
fn test_missing_refill_is_rejected() {
let err = Bucket::builder().capacity(10).build().unwrap_err();
assert_eq!(err, BucketError::ZeroRefillAmount);
}
#[test]
fn test_zero_period_is_rejected() {
let err = Bucket::builder()
.capacity(10)
.refill(10, Duration::ZERO)
.build()
.unwrap_err();
assert_eq!(err, BucketError::ZeroRefillPeriod);
}
}