use serde::{Deserialize, Serialize};
use crate::harness::CorpusSummary;
use crate::levels::ComplianceResult;
pub fn to_json(result: &ComplianceResult) -> String {
serde_json::to_string_pretty(result).expect("ComplianceResult serializes to JSON")
}
pub fn badge(result: &ComplianceResult) -> String {
if result.passed() {
format!("ECS-{} COMPLIANT", result.grade)
} else {
"OpenECS NON-COMPLIANT (below alerting floor)".to_string()
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct BandResult {
pub band: String,
pub r: f64,
pub prd: f64,
pub snr: f64,
}
impl BandResult {
pub fn new(band: impl Into<String>, r: f64, prd: f64, snr: f64) -> Self {
Self {
band: band.into(),
r,
prd,
snr,
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct EcsReport {
pub spec_version: String,
pub codec: String,
pub dataset: String,
pub n_files: usize,
pub bit_exact: bool,
pub grade: char,
pub cr: f64,
pub prd: f64,
pub prdn: f64,
pub r: f64,
pub snr_db: f64,
pub qs: f64,
pub per_band: Vec<BandResult>,
pub throughput_mibs: f64,
pub peak_bytes: u64,
pub violations: Vec<String>,
}
impl EcsReport {
pub fn grade_str(&self) -> String {
if self.grade == '\0' {
String::new()
} else {
self.grade.to_string()
}
}
pub fn passed(&self) -> bool {
self.grade != '\0'
}
pub fn to_json(&self) -> String {
serde_json::to_string_pretty(self).expect("EcsReport serializes to JSON")
}
pub fn from_json(s: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(s)
}
pub fn human_table(&self) -> String {
let grade = if self.grade == '\0' {
"— (below floor)".to_string()
} else {
format!("ECS-{}", self.grade)
};
let peak_mib = self.peak_bytes as f64 / (1024.0 * 1024.0);
let mut s = String::new();
s.push_str(&format!(
"OpenECS report — {} on {} ({} file{})\n",
self.codec,
self.dataset,
self.n_files,
if self.n_files == 1 { "" } else { "s" },
));
s.push_str(&format!("{:-<60}\n", ""));
s.push_str(&format!(" Grade : {grade}\n"));
s.push_str(&format!(
" Bit-exact : {}\n",
if self.bit_exact { "yes" } else { "no" }
));
s.push_str(&format!(" CR : {:>10.2} : 1\n", self.cr));
s.push_str(&format!(" PRD : {:>10.3} %\n", self.prd));
s.push_str(&format!(" PRDN : {:>10.3} %\n", self.prdn));
s.push_str(&format!(" R : {:>10.4}\n", self.r));
s.push_str(&format!(" SNR : {:>10.2} dB\n", self.snr_db));
s.push_str(&format!(" Quality score: {:>10.3}\n", self.qs));
s.push_str(&format!(
" Throughput : {:>10.2} MiB/s\n",
self.throughput_mibs
));
s.push_str(&format!(" Peak memory : {peak_mib:>10.2} MiB\n"));
if !self.per_band.is_empty() {
s.push_str(&format!("{:-<60}\n", ""));
s.push_str(&format!(
" {:<8} {:>10} {:>10} {:>10}\n",
"band", "R", "PRD %", "SNR dB"
));
for b in &self.per_band {
s.push_str(&format!(
" {:<8} {:>10.4} {:>10.3} {:>10.2}\n",
b.band, b.r, b.prd, b.snr
));
}
}
if !self.violations.is_empty() {
s.push_str(&format!("{:-<60}\n", ""));
s.push_str(" To climb a tier:\n");
for v in &self.violations {
s.push_str(&format!(" - {v}\n"));
}
}
s
}
}
fn grade_rank(grade: char) -> u8 {
match grade {
'L' => 0,
'N' => 1,
'C' => 2,
'M' => 3,
'A' => 4,
_ => 5, }
}
pub fn leaderboard(reports: &[EcsReport]) -> String {
let mut ranked: Vec<&EcsReport> = reports.iter().collect();
ranked.sort_by(|a, b| {
grade_rank(a.grade)
.cmp(&grade_rank(b.grade))
.then(
b.qs.partial_cmp(&a.qs)
.unwrap_or(std::cmp::Ordering::Equal),
)
.then(
b.cr.partial_cmp(&a.cr)
.unwrap_or(std::cmp::Ordering::Equal),
)
.then_with(|| a.codec.cmp(&b.codec))
});
let mut s = String::new();
s.push_str("OpenECS leaderboard (best first)\n");
s.push_str(&format!("{:=<78}\n", ""));
s.push_str(&format!(
" {:>3} {:<22} {:<14} {:>6} {:>9} {:>8} {:>8}\n",
"#", "codec", "dataset", "grade", "CR", "PRD %", "QS"
));
s.push_str(&format!("{:-<78}\n", ""));
if ranked.is_empty() {
s.push_str(" (no codecs)\n");
return s;
}
for (i, rep) in ranked.iter().enumerate() {
let grade = if rep.grade == '\0' {
"—".to_string()
} else {
format!("ECS-{}", rep.grade)
};
s.push_str(&format!(
" {:>3} {:<22} {:<14} {:>6} {:>9.2} {:>8.3} {:>8.3}\n",
i + 1,
rep.codec,
rep.dataset,
grade,
rep.cr,
rep.prd,
rep.qs,
));
}
s
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct CodecIdentity {
pub name: String,
pub manifest_sha256: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct CorpusIdentity {
pub name: String,
pub version: String,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct EcsSubmission {
pub spec_version: String,
pub codec: CodecIdentity,
pub corpus: CorpusIdentity,
pub reports: Vec<EcsReport>,
pub summary: CorpusSummary,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub task_concordance: Option<serde_json::Value>,
}
impl EcsSubmission {
pub fn new(
codec: CodecIdentity,
corpus: CorpusIdentity,
reports: Vec<EcsReport>,
summary: CorpusSummary,
) -> Self {
Self {
spec_version: crate::SPEC_VERSION.to_string(),
codec,
corpus,
reports,
summary,
task_concordance: None,
}
}
pub fn with_task_concordance(mut self, block: serde_json::Value) -> Self {
self.task_concordance = Some(block);
self
}
pub fn to_json(&self) -> String {
serde_json::to_string_pretty(self).expect("EcsSubmission serializes to JSON")
}
pub fn from_json(s: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(s)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn sample_report() -> EcsReport {
EcsReport {
spec_version: crate::SPEC_VERSION.to_string(),
codec: "lamquant-lossless".to_string(),
dataset: "tuh-eeg-holdout".to_string(),
n_files: 42,
bit_exact: true,
grade: 'L',
cr: 3.71,
prd: 0.0,
prdn: 0.0,
r: 1.0,
snr_db: 120.0,
qs: 3.71,
per_band: vec![
BandResult::new("delta", 1.0, 0.0, 120.0),
BandResult::new("theta", 1.0, 0.0, 120.0),
BandResult::new("alpha", 1.0, 0.0, 120.0),
BandResult::new("beta", 1.0, 0.0, 120.0),
BandResult::new("gamma", 1.0, 0.0, 120.0),
],
throughput_mibs: 88.5,
peak_bytes: 12 * 1024 * 1024,
violations: Vec::new(),
}
}
fn lossy_report() -> EcsReport {
EcsReport {
spec_version: crate::SPEC_VERSION.to_string(),
codec: "neural-lmq".to_string(),
dataset: "tuh-eeg-holdout".to_string(),
n_files: 42,
bit_exact: false,
grade: 'C',
cr: 42.0,
prd: 4.2,
prdn: 4.5,
r: 0.972,
snr_db: 27.6,
qs: 10.0,
per_band: vec![
BandResult::new("delta", 0.99, 3.0, 30.0),
BandResult::new("gamma", 0.90, 12.0, 18.0),
],
throughput_mibs: 14.2,
peak_bytes: 256 * 1024 * 1024,
violations: vec!["CR 42.0 < 100.0".to_string()],
}
}
#[test]
fn report_round_trips_through_json() {
let rep = sample_report();
let json = rep.to_json();
assert!(json.contains("\"codec\""));
assert!(json.contains("lamquant-lossless"));
assert!(json.contains("\"per_band\""));
let back = EcsReport::from_json(&json).expect("valid JSON round-trips");
assert_eq!(back, rep);
}
#[test]
fn char_grade_round_trips() {
let mut rep = sample_report();
rep.grade = '\0';
let back = EcsReport::from_json(&rep.to_json()).expect("round-trips");
assert_eq!(back.grade, '\0');
assert_eq!(back.grade_str(), "");
assert!(!back.passed());
}
#[test]
fn human_table_has_key_fields() {
let t = sample_report().human_table();
assert!(t.contains("lamquant-lossless"));
assert!(t.contains("tuh-eeg-holdout"));
assert!(t.contains("ECS-L"));
assert!(t.contains("delta"));
assert!(t.contains("gamma"));
assert!(t.contains("12.00 MiB"));
}
#[test]
fn human_table_lists_violations() {
let t = lossy_report().human_table();
assert!(t.contains("To climb a tier"));
assert!(t.contains("CR 42.0 < 100.0"));
}
#[test]
fn leaderboard_sorts_by_grade_then_quality() {
let a = sample_report(); let mut b = lossy_report(); b.codec = "codec-b".to_string();
let mut c = lossy_report(); c.codec = "codec-c".to_string();
c.qs = 5.0;
let table = leaderboard(&[c.clone(), b.clone(), a.clone()]);
let pos_a = table.find("lamquant-lossless").unwrap();
let pos_b = table.find("codec-b").unwrap();
let pos_c = table.find("codec-c").unwrap();
assert!(pos_a < pos_b, "L should outrank C");
assert!(pos_a < pos_c, "L should outrank C");
assert!(pos_b < pos_c, "higher QS ranks first within a tier");
assert!(table.contains(" 1 lamquant-lossless"));
}
#[test]
fn leaderboard_empty_is_safe() {
let table = leaderboard(&[]);
assert!(table.contains("OpenECS leaderboard"));
assert!(table.contains("(no codecs)"));
}
}