#[derive(Debug, Clone)]
pub struct Config {
pub threshold: u8,
pub min_collapse: usize,
pub normalize_timestamps: bool,
pub normalize_hashes: bool,
pub normalize_ports: bool,
pub normalize_ips: bool,
pub normalize_fqdns: bool,
pub normalize_uuids: bool,
pub normalize_pids: bool,
pub normalize_emails: bool,
pub normalize_paths: bool,
pub normalize_json: bool,
pub normalize_durations: bool,
pub normalize_kubernetes: bool,
pub output_format: String,
pub stats: bool,
pub preserve_color: bool,
pub compact: bool,
pub preflight: bool,
pub summary: bool,
pub essence_mode: bool, pub thread_count: Option<usize>,
pub max_line_length: Option<usize>, pub max_lines: Option<usize>, pub sanitize_pii: bool, pub top_n: Option<usize>, pub stats_json: bool, pub fail_pattern: Option<String>, }
impl Default for Config {
fn default() -> Self {
Self {
threshold: 85,
min_collapse: 3,
normalize_timestamps: true,
normalize_hashes: true,
normalize_ports: true,
normalize_ips: true,
normalize_fqdns: true,
normalize_uuids: true,
normalize_pids: true,
normalize_emails: true,
normalize_paths: true,
normalize_json: true,
normalize_durations: true,
normalize_kubernetes: true,
output_format: "text".to_string(),
stats: true,
preserve_color: false,
compact: true,
preflight: false,
summary: false,
essence_mode: false, thread_count: None,
max_line_length: Some(1024 * 1024), max_lines: None, sanitize_pii: false, top_n: None, stats_json: false, fail_pattern: None, }
}
}
pub fn parse_size_suffix(input: &str) -> Result<usize, String> {
let input = input.trim();
if let Some(num_str) = input.strip_suffix('K').or_else(|| input.strip_suffix('k')) {
num_str
.parse::<usize>()
.map(|n| n * 1024)
.map_err(|_| format!("Invalid number before 'K': {num_str}"))
} else if let Some(num_str) = input.strip_suffix('M').or_else(|| input.strip_suffix('m')) {
num_str
.parse::<usize>()
.map(|n| n * 1024 * 1024)
.map_err(|_| format!("Invalid number before 'M': {num_str}"))
} else if let Some(num_str) = input.strip_suffix('G').or_else(|| input.strip_suffix('g')) {
num_str
.parse::<usize>()
.map(|n| n * 1024 * 1024 * 1024)
.map_err(|_| format!("Invalid number before 'G': {num_str}"))
} else {
input
.parse::<usize>()
.map_err(|_| format!("Invalid number: {input}"))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config_thread_count_is_none() {
let config = Config::default();
assert!(
config.thread_count.is_none(),
"Default thread_count should be None (auto-detect)"
);
}
#[test]
fn test_single_threaded_mode_detection() {
let config = Config {
thread_count: Some(1),
..Default::default()
};
assert_eq!(
config.thread_count,
Some(1),
"Single-threaded mode should be detected via thread_count == Some(1)"
);
}
#[test]
fn test_auto_detect_mode_detection() {
let config = Config::default();
assert!(
config.thread_count.is_none(),
"Auto-detect mode when thread_count is None"
);
}
#[test]
fn test_multi_thread_mode_detection() {
let config = Config {
thread_count: Some(4),
..Default::default()
};
assert_eq!(
config.thread_count,
Some(4),
"Multi-threaded mode with explicit count"
);
}
#[test]
fn test_thread_count_validation() {
let config = Config {
thread_count: Some(0),
..Default::default()
};
assert_eq!(config.thread_count, Some(0));
}
}