use std::collections::BTreeMap;
use super::support_matrix::{TheorySupportMatrix, TheorySupportMatrixRow};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DupKind {
MultiState,
MultiRule,
Other,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ClassifiedDup {
pub triple: (String, String, String),
pub count: usize,
pub kind: DupKind,
}
pub fn classify_dup(rows: &[&TheorySupportMatrixRow]) -> DupKind {
if rows.len() < 2 {
return DupKind::Other;
}
let mut ids = std::collections::BTreeSet::new();
for r in rows {
ids.insert(r.lowering_rule_id.clone().unwrap_or_default());
}
let mut statuses = std::collections::BTreeSet::new();
for r in rows {
statuses.insert(format!("{:?}", r.support_status));
}
if ids.len() == 1 && statuses.len() > 1 {
return DupKind::MultiState;
}
if ids.len() > 1 {
return DupKind::MultiRule;
}
DupKind::Other
}
pub fn matrix_dedup_summary(matrix: &TheorySupportMatrix) -> Vec<ClassifiedDup> {
let mut by_triple: BTreeMap<(String, String, String), Vec<&TheorySupportMatrixRow>> =
BTreeMap::new();
for row in &matrix.rows {
by_triple
.entry((
row.domain.clone(),
row.operator.clone(),
row.backend.clone(),
))
.or_default()
.push(row);
}
let mut out: Vec<ClassifiedDup> = by_triple
.into_iter()
.filter(|(_, rows)| rows.len() > 1)
.map(|(triple, rows)| ClassifiedDup {
triple,
count: rows.len(),
kind: classify_dup(&rows),
})
.collect();
out.sort_by(|a, b| a.triple.0.cmp(&b.triple.0));
out
}
#[cfg(test)]
mod tests {
use super::*;
use crate::verify::support_matrix::{SupportStatus, TheorySupportMatrixRow};
fn row(
domain: &str,
operator: &str,
backend: &str,
lr: Option<&str>,
status: SupportStatus,
) -> TheorySupportMatrixRow {
TheorySupportMatrixRow {
domain: domain.to_string(),
operator: operator.to_string(),
theory_constraints: vec![],
theorem_packages: vec![],
backend: backend.to_string(),
backend_capability: String::new(),
lowering_rule_id: lr.map(String::from),
support_status: status,
fallback_mode: String::new(),
public_api: String::new(),
tests: vec![],
non_claims: vec![],
}
}
#[test]
fn multi_state_classified() {
let r1 = row(
"d",
"op",
"b",
Some("lr1"),
SupportStatus::FeatureGatedPilot,
);
let r2 = row("d", "op", "b", Some("lr1"), SupportStatus::Unavailable);
let rows = vec![&r1, &r2];
assert_eq!(classify_dup(&rows), DupKind::MultiState);
}
#[test]
fn multi_rule_classified() {
let r1 = row("d", "op", "b", Some("lr1"), SupportStatus::Supported);
let r2 = row("d", "op", "b", Some("lr2"), SupportStatus::Supported);
let rows = vec![&r1, &r2];
assert_eq!(classify_dup(&rows), DupKind::MultiRule);
}
#[test]
fn single_row_is_other() {
let r1 = row("d", "op", "b", Some("lr1"), SupportStatus::Supported);
let rows = vec![&r1];
assert_eq!(classify_dup(&rows), DupKind::Other);
}
#[test]
fn matrix_dedup_summary_classifies_correctly() {
let r1 = row(
"d1",
"op",
"b1",
Some("lr1"),
SupportStatus::FeatureGatedPilot,
);
let r2 = row("d1", "op", "b1", Some("lr1"), SupportStatus::Unavailable);
let r3 = row("d2", "op", "b1", Some("lr2"), SupportStatus::Supported);
let r4 = row("d2", "op", "b1", Some("lr3"), SupportStatus::Supported);
let r5 = row("d3", "op", "b2", Some("lr4"), SupportStatus::Supported);
let m = TheorySupportMatrix {
artifact: "test".to_string(),
version: 1,
rows: vec![r1, r2, r3, r4, r5],
};
let summary = matrix_dedup_summary(&m);
assert_eq!(summary.len(), 2);
assert_eq!(summary[0].kind, DupKind::MultiState);
assert_eq!(summary[0].count, 2);
assert_eq!(summary[1].kind, DupKind::MultiRule);
assert_eq!(summary[1].count, 2);
}
}