use alloc::boxed::Box;
pub enum GrowthStrategy {
None,
Linear {
amount: usize,
},
Exponential {
factor: f64,
},
Custom {
compute: Box<dyn Fn(usize) -> usize + Send + Sync>,
},
}
impl GrowthStrategy {
pub fn compute_growth(&self, current_capacity: usize) -> usize {
match self {
GrowthStrategy::None => 0,
GrowthStrategy::Linear { amount } => *amount,
GrowthStrategy::Exponential { factor } => {
let growth = (current_capacity as f64 * factor) as usize;
growth.saturating_sub(current_capacity).max(1)
}
GrowthStrategy::Custom { compute } => compute(current_capacity),
}
}
#[inline]
pub fn allows_growth(&self) -> bool {
!matches!(self, GrowthStrategy::None)
}
}
impl core::fmt::Debug for GrowthStrategy {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
GrowthStrategy::None => write!(f, "GrowthStrategy::None"),
GrowthStrategy::Linear { amount } => f
.debug_struct("GrowthStrategy::Linear")
.field("amount", amount)
.finish(),
GrowthStrategy::Exponential { factor } => f
.debug_struct("GrowthStrategy::Exponential")
.field("factor", factor)
.finish(),
GrowthStrategy::Custom { .. } => {
write!(f, "GrowthStrategy::Custom {{ .. }}")
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn growth_strategy_none() {
let strategy = GrowthStrategy::None;
assert_eq!(strategy.compute_growth(100), 0);
assert!(!strategy.allows_growth());
}
#[test]
fn growth_strategy_linear() {
let strategy = GrowthStrategy::Linear { amount: 50 };
assert_eq!(strategy.compute_growth(100), 50);
assert_eq!(strategy.compute_growth(0), 50);
assert!(strategy.allows_growth());
}
#[test]
fn growth_strategy_exponential() {
let strategy = GrowthStrategy::Exponential { factor: 2.0 };
assert_eq!(strategy.compute_growth(100), 100); assert_eq!(strategy.compute_growth(50), 50); assert!(strategy.allows_growth());
}
#[test]
fn growth_strategy_custom() {
let strategy = GrowthStrategy::Custom {
compute: Box::new(|current| current / 2),
};
assert_eq!(strategy.compute_growth(100), 50);
assert_eq!(strategy.compute_growth(200), 100);
assert!(strategy.allows_growth());
}
#[test]
fn growth_strategy_exponential_minimum() {
let strategy = GrowthStrategy::Exponential { factor: 2.0 };
assert_eq!(strategy.compute_growth(0), 1);
}
}