use super::{GrowthStrategy, InitializationStrategy, PoolConfig};
use crate::error::{Error, Result};
use crate::utils::validate_alignment;
use core::mem;
pub struct PoolConfigBuilder<T> {
capacity: Option<usize>,
max_capacity: Option<usize>,
growth_strategy: GrowthStrategy,
alignment: usize,
pre_initialize: bool,
initialization_strategy: InitializationStrategy<T>,
thread_local: bool,
}
impl<T> PoolConfigBuilder<T> {
pub fn new() -> Self {
Self {
capacity: None,
max_capacity: None,
growth_strategy: GrowthStrategy::None,
alignment: mem::align_of::<T>(),
pre_initialize: false,
initialization_strategy: InitializationStrategy::Lazy,
thread_local: false,
}
}
pub fn capacity(mut self, capacity: usize) -> Self {
self.capacity = Some(capacity);
self
}
pub fn max_capacity(mut self, max_capacity: Option<usize>) -> Self {
self.max_capacity = max_capacity;
self
}
pub fn growth_strategy(mut self, strategy: GrowthStrategy) -> Self {
self.growth_strategy = strategy;
self
}
pub fn alignment(mut self, alignment: usize) -> Self {
self.alignment = alignment;
self
}
pub fn pre_initialize(mut self, pre_initialize: bool) -> Self {
self.pre_initialize = pre_initialize;
self
}
pub fn initializer(mut self, initializer: impl Fn() -> T + Send + Sync + 'static) -> Self {
self.initialization_strategy = InitializationStrategy::eager(initializer);
self
}
pub fn reset_fn(
mut self,
initializer: impl Fn() -> T + Send + Sync + 'static,
reset: impl Fn(&mut T) + Send + Sync + 'static,
) -> Self {
self.initialization_strategy = InitializationStrategy::custom(initializer, reset);
self
}
pub fn initialization_strategy(mut self, strategy: InitializationStrategy<T>) -> Self {
self.initialization_strategy = strategy;
self
}
#[cfg(feature = "std")]
pub fn thread_local(mut self, thread_local: bool) -> Self {
self.thread_local = thread_local;
self
}
pub fn build(self) -> Result<PoolConfig<T>> {
let capacity = self
.capacity
.ok_or_else(|| Error::invalid_config("capacity must be specified"))?;
if capacity == 0 {
return Err(Error::invalid_config("capacity must be at least 1"));
}
if let Some(max) = self.max_capacity {
if max < capacity {
return Err(Error::invalid_config("max_capacity must be >= capacity"));
}
}
validate_alignment(self.alignment)?;
let initialization_strategy =
if self.pre_initialize && self.initialization_strategy.is_lazy() {
InitializationStrategy::Lazy } else {
self.initialization_strategy
};
Ok(PoolConfig {
capacity,
max_capacity: self.max_capacity,
growth_strategy: self.growth_strategy,
alignment: self.alignment,
pre_initialize: self.pre_initialize,
initialization_strategy,
thread_local: self.thread_local,
})
}
}
impl<T> Default for PoolConfigBuilder<T> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builder_requires_capacity() {
let result = PoolConfig::<i32>::builder().build();
assert!(result.is_err());
}
#[test]
fn builder_rejects_zero_capacity() {
let result = PoolConfig::<i32>::builder().capacity(0).build();
assert!(result.is_err());
}
#[test]
fn builder_validates_alignment() {
let result = PoolConfig::<i32>::builder()
.capacity(100)
.alignment(7) .build();
assert!(result.is_err());
}
#[test]
fn builder_validates_max_capacity() {
let result = PoolConfig::<i32>::builder()
.capacity(100)
.max_capacity(Some(50)) .build();
assert!(result.is_err());
}
#[test]
fn builder_creates_valid_config() {
let config = PoolConfig::<i32>::builder()
.capacity(100)
.max_capacity(Some(1000))
.alignment(64)
.pre_initialize(true)
.build()
.unwrap();
assert_eq!(config.capacity(), 100);
assert_eq!(config.max_capacity(), Some(1000));
assert_eq!(config.alignment(), 64);
assert!(config.pre_initialize());
}
#[test]
fn builder_with_growth_strategy() {
let config = PoolConfig::<i32>::builder()
.capacity(100)
.growth_strategy(GrowthStrategy::Exponential { factor: 2.0 })
.build()
.unwrap();
assert!(config.growth_strategy().allows_growth());
}
}