use std::fmt::{self, Display};
use bon::bon;
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub struct Limits {
pub(crate) max_batch_size: usize,
pub(crate) max_key_concurrency: usize,
pub(crate) max_batch_queue_size: usize,
}
#[bon]
impl Limits {
#[builder]
pub fn new(
#[builder(default = 100)]
max_batch_size: usize,
#[builder(default = 10)]
max_key_concurrency: usize,
max_batch_queue_size: Option<usize>,
) -> Self {
assert!(
max_batch_size > 0,
"max_batch_size must be greater than zero"
);
assert!(
max_key_concurrency > 0,
"max_key_concurrency must be greater than zero"
);
let max_batch_queue_size = max_batch_queue_size.unwrap_or(max_key_concurrency * 2);
assert!(
max_batch_queue_size > 0,
"max_batch_queue_size must be greater than zero"
);
Self {
max_batch_size,
max_key_concurrency,
max_batch_queue_size,
}
}
fn max_items_processing_per_key(&self) -> usize {
self.max_batch_size * self.max_key_concurrency
}
fn max_items_queued_per_key(&self) -> usize {
self.max_batch_size * self.max_batch_queue_size
}
pub(crate) fn max_items_in_system_per_key(&self) -> usize {
self.max_items_processing_per_key() + self.max_items_queued_per_key()
}
}
impl Default for Limits {
fn default() -> Self {
Self::builder().build()
}
}
impl Display for Limits {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"batch_size: {}, key_concurrency: {}, queue_size: {}",
self.max_batch_size, self.max_key_concurrency, self.max_batch_queue_size
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_matches_builder_defaults() {
let default = Limits::default();
let built = Limits::builder().build();
assert_eq!(default.max_batch_size, built.max_batch_size);
assert_eq!(default.max_key_concurrency, built.max_key_concurrency);
assert_eq!(default.max_batch_queue_size, built.max_batch_queue_size);
}
#[test]
#[should_panic(expected = "max_batch_size must be greater than zero")]
fn rejects_zero_max_batch_size() {
Limits::builder().max_batch_size(0).build();
}
#[test]
#[should_panic(expected = "max_key_concurrency must be greater than zero")]
fn rejects_zero_max_key_concurrency() {
Limits::builder().max_key_concurrency(0).build();
}
#[test]
#[should_panic(expected = "max_batch_queue_size must be greater than zero")]
fn rejects_zero_max_batch_queue_size() {
Limits::builder().max_batch_queue_size(0).build();
}
#[test]
fn limits_builder_methods() {
let limits = Limits::builder()
.max_batch_size(50)
.max_key_concurrency(5)
.build();
assert_eq!(limits.max_batch_size, 50);
assert_eq!(limits.max_key_concurrency, 5);
}
}