use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub(crate) struct CompressionProfile {
pub name: String,
pub mode: ProfileMode,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub(crate) enum ProfileMode {
Stock,
Standard,
Aggressive,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ProfileSelection {
All,
Stock,
Standard,
Aggressive,
}
impl ProfileSelection {
pub(crate) fn parse(value: &str) -> Result<Self, String> {
match value {
"all" => Ok(Self::All),
"stock" => Ok(Self::Stock),
"standard" => Ok(Self::Standard),
"aggressive" => Ok(Self::Aggressive),
_ => Err(format!(
"unknown benchmark config {value:?}; expected stock, standard, aggressive, or all"
)),
}
}
}
impl ProfileMode {
pub(crate) fn label(self) -> &'static str {
match self {
Self::Stock => "stock",
Self::Standard => "standard",
Self::Aggressive => "aggressive",
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct BenchConfig {
pub profiles: Vec<CompressionProfile>,
pub repeats: u32,
pub regression_threshold: f64,
}
impl Default for BenchConfig {
fn default() -> Self {
Self {
profiles: vec![
CompressionProfile {
name: "stock".into(),
mode: ProfileMode::Stock,
},
CompressionProfile {
name: "standard".into(),
mode: ProfileMode::Standard,
},
CompressionProfile {
name: "aggressive".into(),
mode: ProfileMode::Aggressive,
},
],
repeats: 3,
regression_threshold: 0.95,
}
}
}
impl BenchConfig {
pub(crate) fn for_selection(selection: ProfileSelection) -> Self {
let mut config = Self::default();
config.profiles = match selection {
ProfileSelection::All => config.profiles,
ProfileSelection::Stock => vec![profile(ProfileMode::Stock)],
ProfileSelection::Standard => {
vec![profile(ProfileMode::Stock), profile(ProfileMode::Standard)]
}
ProfileSelection::Aggressive => {
vec![
profile(ProfileMode::Stock),
profile(ProfileMode::Aggressive),
]
}
};
config
}
pub(crate) fn single_profile(mode: ProfileMode) -> Self {
Self {
profiles: vec![profile(mode)],
repeats: 1,
regression_threshold: 0.95,
}
}
}
fn profile(mode: ProfileMode) -> CompressionProfile {
CompressionProfile {
name: mode.label().into(),
mode,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_has_three_profiles() {
let cfg = BenchConfig::default();
assert_eq!(cfg.profiles.len(), 3);
assert_eq!(cfg.repeats, 3);
}
#[test]
fn profile_labels() {
assert_eq!(ProfileMode::Stock.label(), "stock");
assert_eq!(ProfileMode::Standard.label(), "standard");
assert_eq!(ProfileMode::Aggressive.label(), "aggressive");
}
#[test]
fn selection_preserves_stock_baseline_for_compressed_profiles() {
let standard = BenchConfig::for_selection(ProfileSelection::Standard);
assert_eq!(standard.profiles.len(), 2);
assert_eq!(standard.profiles[0].mode, ProfileMode::Stock);
assert_eq!(standard.profiles[1].mode, ProfileMode::Standard);
let aggressive = BenchConfig::for_selection(ProfileSelection::Aggressive);
assert_eq!(aggressive.profiles.len(), 2);
assert_eq!(aggressive.profiles[0].mode, ProfileMode::Stock);
assert_eq!(aggressive.profiles[1].mode, ProfileMode::Aggressive);
}
}