use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DegradationType {
QuantizationStep,
Precision,
SpeedQuality,
SizeQuality,
}
impl std::fmt::Display for DegradationType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DegradationType::QuantizationStep => write!(f, "quantization_step"),
DegradationType::Precision => write!(f, "precision"),
DegradationType::SpeedQuality => write!(f, "speed_quality"),
DegradationType::SizeQuality => write!(f, "size_quality"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DegradationReceipt {
pub degradation_type: DegradationType,
pub degraded_by: f64,
pub bytes_saved: u64,
pub accuracy_impact: f64,
pub source_profile: Option<String>,
pub target_profile: Option<String>,
}
impl DegradationReceipt {
pub fn new(
degradation_type: DegradationType,
degraded_by: f64,
bytes_saved: u64,
accuracy_impact: f64,
) -> Self {
Self {
degradation_type,
degraded_by,
bytes_saved,
accuracy_impact,
source_profile: None,
target_profile: None,
}
}
pub fn with_profiles(mut self, source: impl Into<String>, target: impl Into<String>) -> Self {
self.source_profile = Some(source.into());
self.target_profile = Some(target.into());
self
}
pub fn benefit_cost_ratio(&self) -> f64 {
if self.accuracy_impact == 0.0 {
f64::MAX
} else {
self.bytes_saved as f64 / (self.accuracy_impact * 1000.0)
}
}
pub fn is_acceptable(&self, max_impact: f64) -> bool {
self.accuracy_impact <= max_impact
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn degradation_receipt_creation() {
let receipt = DegradationReceipt::new(DegradationType::QuantizationStep, 0.05, 1024, 0.02);
assert_eq!(receipt.degradation_type, DegradationType::QuantizationStep);
assert!(receipt.is_acceptable(0.1));
assert!(!receipt.is_acceptable(0.01));
}
#[test]
fn benefit_cost_ratio() {
let receipt = DegradationReceipt::new(DegradationType::SizeQuality, 0.1, 5000, 0.05);
let ratio = receipt.benefit_cost_ratio();
assert!(ratio > 0.0);
}
}