mod adaptive;
mod conservative;
mod fixed;
pub use adaptive::*;
pub use conservative::*;
pub use fixed::*;
use crate::config::ConfigOpts;
use crate::metrics::{ChunkMetrics, is_memory_constrained};
pub trait IsStrategy: std::fmt::Debug {
fn initial_chunk_size(&self) -> usize;
fn should_adapt(&self, metrics: &ChunkMetrics) -> bool;
fn adapt_size(&mut self, metrics: &ChunkMetrics, current_size: usize) -> usize;
}
#[derive(Debug, Clone)]
pub enum Strategy {
Static(StaticStrategy),
Adaptive(AdaptiveStrategy),
Conservative(ConservativeStrategy),
}
impl Strategy {
pub fn pick_strategy() -> Strategy {
if crate::metrics::is_memory_constrained() {
Strategy::Conservative(ConservativeStrategy::default())
} else {
Strategy::Adaptive(AdaptiveStrategy::default())
}
}
pub fn from_config(config: &ConfigOpts, size_hint: Option<u64>) -> Self {
if let Some(strategy) = &config.strategy {
return strategy.clone();
}
if config.conservative {
return Strategy::Conservative(ConservativeStrategy::default());
}
if !config.adaptive {
let strat = if let Some(size) = size_hint {
StaticStrategy::optimal_for_file(size)
} else {
StaticStrategy::default()
};
return Strategy::Static(strat);
}
if is_memory_constrained() {
Strategy::Conservative(ConservativeStrategy::default())
} else {
let strat = if let Some(size) = size_hint {
AdaptiveStrategy::optimal_for_file(size)
} else {
AdaptiveStrategy::default()
};
Strategy::Adaptive(strat)
}
}
}
impl Default for Strategy {
fn default() -> Self {
Strategy::Static(StaticStrategy::default())
}
}
impl From<&str> for Strategy {
fn from(value: &str) -> Self {
match value.to_lowercase().as_str() {
"static" => Self::default(),
"adaptive" => Self::Adaptive(AdaptiveStrategy::default()),
"memory" => Self::Conservative(ConservativeStrategy::default()),
_ => Self::default(),
}
}
}
impl IsStrategy for Strategy {
fn should_adapt(&self, metrics: &ChunkMetrics) -> bool {
match self {
Strategy::Static(s) => s.should_adapt(metrics),
Strategy::Adaptive(s) => s.should_adapt(metrics),
Strategy::Conservative(s) => s.should_adapt(metrics),
}
}
fn adapt_size(&mut self, metrics: &ChunkMetrics, current_size: usize) -> usize {
match self {
Strategy::Static(s) => s.adapt_size(metrics, current_size),
Strategy::Adaptive(s) => s.adapt_size(metrics, current_size),
Strategy::Conservative(s) => s.adapt_size(metrics, current_size),
}
}
fn initial_chunk_size(&self) -> usize {
match self {
Strategy::Static(s) => s.initial_chunk_size(),
Strategy::Adaptive(s) => s.initial_chunk_size(),
Strategy::Conservative(s) => s.initial_chunk_size(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strategy_selection() {
let config = ConfigOpts {
adaptive: true,
strategy: Some(Strategy::Adaptive(AdaptiveStrategy::default())),
conservative: false,
..Default::default()
};
let strategy = Strategy::from_config(&config, None);
assert!(matches!(strategy, Strategy::Adaptive(_)));
}
}