use crate::codec_selector::{ColumnProfile, CodecSelector};
use crate::compression::CompressionRegistry;
use crate::decompression::{CodecId, CodecRegistry};
use crate::binary_format::BinaryFormatError;
#[derive(Clone, Debug)]
pub struct RoundTripResult {
pub original_data: Vec<u8>,
pub compressed_data: Vec<u8>,
pub decompressed_data: Vec<u8>,
pub codec: CodecId,
pub compression_ratio: f32,
pub byte_fidelity: bool, pub estimated_ratio: f32, pub ratio_error: f32, }
pub struct RoundTripEngine;
impl RoundTripEngine {
pub fn validate_roundtrip(
data: &[u8],
) -> Result<RoundTripResult, BinaryFormatError> {
let profile = ColumnProfile::analyze(data)
.map_err(|e| BinaryFormatError::InvalidData(e))?;
let codec = CodecSelector::select_optimal_codec(&profile);
let estimated_stats = CodecSelector::estimate_stats(&profile, codec);
let (compressed_data, compression_stats) =
CompressionRegistry::compress(codec, data)?;
let decompressed_data =
CodecRegistry::decompress(codec, &compressed_data)?;
let byte_fidelity = decompressed_data == data;
let actual_ratio = compression_stats.ratio;
let estimated_ratio = estimated_stats.ratio;
let ratio_error = if estimated_ratio > 0.0 {
((actual_ratio - estimated_ratio) / estimated_ratio).abs()
} else {
0.0
};
Ok(RoundTripResult {
original_data: data.to_vec(),
compressed_data,
decompressed_data,
codec,
compression_ratio: actual_ratio,
byte_fidelity,
estimated_ratio,
ratio_error,
})
}
pub fn validate_ratio_accuracy(result: &RoundTripResult, tolerance: f32) -> bool {
result.ratio_error <= tolerance
}
pub fn validate_fidelity(result: &RoundTripResult) -> bool {
result.byte_fidelity && result.decompressed_data == result.original_data
}
pub fn generate_report(result: &RoundTripResult) -> CompressionReport {
let improvement = (1.0 - result.compression_ratio) * 100.0;
let ratio_accuracy = (1.0 - result.ratio_error) * 100.0;
CompressionReport {
original_size: result.original_data.len(),
compressed_size: result.compressed_data.len(),
codec: result.codec,
compression_ratio: result.compression_ratio,
compression_improvement_percent: improvement,
estimated_ratio: result.estimated_ratio,
ratio_error_percent: result.ratio_error * 100.0,
ratio_accuracy_percent: ratio_accuracy,
byte_fidelity: result.byte_fidelity,
compression_efficiency: if result.byte_fidelity {
"✅ PASS".to_string()
} else {
"❌ FAIL".to_string()
},
}
}
pub fn validate_codec_at_scale(
data: &[u8],
codec: CodecId,
) -> Result<Vec<ScaleTest>, BinaryFormatError> {
let mut results = Vec::new();
for multiplier in &[1, 10, 100] {
let mut test_data = Vec::new();
for _ in 0..*multiplier {
test_data.extend_from_slice(data);
}
let _profile = ColumnProfile::analyze(&test_data)
.map_err(|e| BinaryFormatError::InvalidData(e))?;
let (compressed, stats) = CompressionRegistry::compress(codec, &test_data)?;
results.push(ScaleTest {
multiplier: *multiplier,
original_size: test_data.len(),
compressed_size: compressed.len(),
ratio: stats.ratio,
valid: true, });
}
Ok(results)
}
pub fn compare_all_codecs(
data: &[u8],
) -> Result<Vec<CodecComparison>, BinaryFormatError> {
let codecs = vec![
CodecId::RLE,
CodecId::Dictionary,
CodecId::FOR,
CodecId::LZSS,
];
let mut comparisons = Vec::new();
for codec in codecs {
match CompressionRegistry::compress(codec, data) {
Ok((compressed, stats)) => {
comparisons.push(CodecComparison {
codec,
original_size: data.len(),
compressed_size: compressed.len(),
ratio: stats.ratio,
valid: true, });
}
Err(_) => {
comparisons.push(CodecComparison {
codec,
original_size: data.len(),
compressed_size: 0,
ratio: 1.0,
valid: false,
});
}
}
}
comparisons.sort_by(|a, b| {
if a.valid && b.valid {
a.ratio.partial_cmp(&b.ratio).unwrap()
} else if a.valid {
std::cmp::Ordering::Less
} else if b.valid {
std::cmp::Ordering::Greater
} else {
std::cmp::Ordering::Equal
}
});
Ok(comparisons)
}
}
#[derive(Clone, Debug)]
pub struct CompressionReport {
pub original_size: usize,
pub compressed_size: usize,
pub codec: CodecId,
pub compression_ratio: f32,
pub compression_improvement_percent: f32,
pub estimated_ratio: f32,
pub ratio_error_percent: f32,
pub ratio_accuracy_percent: f32,
pub byte_fidelity: bool,
pub compression_efficiency: String,
}
#[derive(Clone, Debug)]
pub struct ScaleTest {
pub multiplier: usize,
pub original_size: usize,
pub compressed_size: usize,
pub ratio: f32,
pub valid: bool,
}
#[derive(Clone, Debug)]
pub struct CodecComparison {
pub codec: CodecId,
pub original_size: usize,
pub compressed_size: usize,
pub ratio: f32,
pub valid: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compression_registry_rle() {
let data = vec![0xAA; 100];
let (compressed, stats) = CompressionRegistry::compress(CodecId::RLE, &data)
.expect("RLE compression should work");
assert!(compressed.len() > 0);
assert!(stats.ratio < 0.5);
}
#[test]
fn test_compression_registry_dict() {
let mut data = Vec::new();
for _ in 0..20 {
data.extend_from_slice(&[1u8, 2, 3, 4, 5]);
}
let (compressed, _stats) = CompressionRegistry::compress(CodecId::Dictionary, &data)
.expect("Dictionary compression should work");
assert!(compressed.len() > 0);
}
#[test]
fn test_compression_registry_lzss() {
let data = b"hello world".to_vec();
let (compressed, _stats) = CompressionRegistry::compress(CodecId::LZSS, &data)
.expect("LZSS compression should work");
assert!(compressed.len() > 0);
}
#[test]
fn test_compression_stats() {
use crate::compression::CompressionStats; let stats = CompressionStats::new(1000, 500);
assert_eq!(stats.ratio, 0.5);
assert_eq!(stats.original_size, 1000);
assert_eq!(stats.compressed_size, 500);
}
#[test]
fn test_comparison_infrastructure_dict_only() {
let data = vec![1u8, 2, 3, 4, 5];
let comparisons = RoundTripEngine::compare_all_codecs(&data).unwrap();
assert_eq!(comparisons.len(), 4);
for comp in comparisons {
assert!(comp.original_size > 0);
assert!(comp.ratio > 0.0);
}
}
#[test]
fn test_scale_testing_infrastructure() {
let data = vec![0x55; 8]; let results = RoundTripEngine::validate_codec_at_scale(&data, CodecId::Dictionary)
.unwrap();
assert_eq!(results.len(), 3);
for test in results {
assert!(test.multiplier > 0);
assert!(test.original_size > 0);
}
}
#[test]
fn test_fidelity_validation_manual() {
let data = vec![1, 2, 3];
let result = RoundTripResult {
original_data: data.clone(),
compressed_data: vec![1],
decompressed_data: data.clone(),
codec: CodecId::RLE,
compression_ratio: 0.5,
byte_fidelity: true,
estimated_ratio: 0.45,
ratio_error: 0.1,
};
assert!(RoundTripEngine::validate_fidelity(&result));
}
#[test]
fn test_ratio_accuracy_check() {
let result = RoundTripResult {
original_data: vec![1, 2, 3],
compressed_data: vec![1],
decompressed_data: vec![1, 2, 3],
codec: CodecId::RLE,
compression_ratio: 0.5,
byte_fidelity: true,
estimated_ratio: 0.5,
ratio_error: 0.0,
};
assert!(RoundTripEngine::validate_ratio_accuracy(&result, 0.01));
}
#[test]
fn test_report_generation() {
let result = RoundTripResult {
original_data: vec![0; 100],
compressed_data: vec![0; 50],
decompressed_data: vec![0; 100],
codec: CodecId::RLE,
compression_ratio: 0.5,
byte_fidelity: true,
estimated_ratio: 0.45,
ratio_error: 0.1,
};
let report = RoundTripEngine::generate_report(&result);
assert_eq!(report.original_size, 100);
assert_eq!(report.compressed_size, 50);
assert!(report.compression_improvement_percent > 40.0);
assert_eq!(report.byte_fidelity, true);
}
#[test]
fn test_codec_registry_availability() {
let data = vec![0xFF; 100];
let (compressed, _) = CompressionRegistry::compress(CodecId::RLE, &data).unwrap();
assert!(compressed.len() > 0);
}
}