use alloc::boxed::Box;
pub enum InitializationStrategy<T> {
Lazy,
Eager {
initializer: Box<dyn Fn() -> T + Send + Sync>,
},
Custom {
initializer: Box<dyn Fn() -> T + Send + Sync>,
#[allow(clippy::type_complexity)]
reset: Option<Box<dyn Fn(&mut T) + Send + Sync>>,
},
}
impl<T> InitializationStrategy<T> {
pub fn eager(initializer: impl Fn() -> T + Send + Sync + 'static) -> Self {
Self::Eager {
initializer: Box::new(initializer),
}
}
pub fn custom(
initializer: impl Fn() -> T + Send + Sync + 'static,
reset: impl Fn(&mut T) + Send + Sync + 'static,
) -> Self {
Self::Custom {
initializer: Box::new(initializer),
reset: Some(Box::new(reset)),
}
}
pub fn custom_init_only(initializer: impl Fn() -> T + Send + Sync + 'static) -> Self {
Self::Custom {
initializer: Box::new(initializer),
reset: None,
}
}
#[inline]
pub fn is_lazy(&self) -> bool {
matches!(self, InitializationStrategy::Lazy)
}
#[inline]
pub fn is_eager(&self) -> bool {
matches!(self, InitializationStrategy::Eager { .. })
}
pub fn initialize(&self) -> Option<T> {
match self {
InitializationStrategy::Lazy => None,
InitializationStrategy::Eager { initializer } => Some(initializer()),
InitializationStrategy::Custom { initializer, .. } => Some(initializer()),
}
}
pub fn reset(&self, value: &mut T) {
if let InitializationStrategy::Custom {
reset: Some(reset_fn),
..
} = self
{
reset_fn(value);
}
}
}
impl<T> Default for InitializationStrategy<T> {
fn default() -> Self {
Self::Lazy
}
}
impl<T> core::fmt::Debug for InitializationStrategy<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
InitializationStrategy::Lazy => write!(f, "InitializationStrategy::Lazy"),
InitializationStrategy::Eager { .. } => {
write!(f, "InitializationStrategy::Eager {{ .. }}")
}
InitializationStrategy::Custom { reset, .. } => f
.debug_struct("InitializationStrategy::Custom")
.field("has_reset", &reset.is_some())
.finish(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
use alloc::vec::Vec;
#[test]
fn lazy_strategy() {
let strategy = InitializationStrategy::<i32>::Lazy;
assert!(strategy.is_lazy());
assert!(!strategy.is_eager());
assert!(strategy.initialize().is_none());
}
#[test]
fn eager_strategy() {
let strategy = InitializationStrategy::eager(|| 42);
assert!(!strategy.is_lazy());
assert!(strategy.is_eager());
assert_eq!(strategy.initialize(), Some(42));
}
#[test]
fn custom_strategy_with_reset() {
let strategy = InitializationStrategy::custom(|| vec![1, 2, 3], |v| v.clear());
let mut value = strategy.initialize().unwrap();
assert_eq!(value, vec![1, 2, 3]);
value.push(4);
strategy.reset(&mut value);
assert_eq!(value, Vec::<i32>::new());
}
#[test]
fn custom_strategy_without_reset() {
let strategy = InitializationStrategy::custom_init_only(|| 100);
let value = strategy.initialize().unwrap();
assert_eq!(value, 100);
let mut value = 200;
strategy.reset(&mut value);
assert_eq!(value, 200); }
}