#[path = "../census.rs"]
#[allow(dead_code)] mod census;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::process::ExitCode;
fn main() -> ExitCode {
let Some(path) = std::env::args().nth(1) else {
eprintln!("usage: coverage-probe <functions.txt>");
return ExitCode::FAILURE;
};
let text = match std::fs::read_to_string(&path) {
Ok(t) => t,
Err(e) => {
eprintln!("error: read {path}: {e}");
return ExitCode::FAILURE;
}
};
let mut seen = BTreeSet::new();
let names: Vec<String> = text
.lines()
.map(str::trim)
.filter(|l| !l.is_empty() && !l.starts_with('#'))
.map(|l| l.to_uppercase())
.filter(|l| seen.insert(l.clone()))
.collect();
let unrecognized: BTreeSet<String> = census::probe_support(&names).into_iter().collect();
let mut catalog_recognized = 0u64;
let mut locally_evaluable = 0u64;
let mut policy_limited = 0u64;
let mut matrix: BTreeMap<String, &'static str> = BTreeMap::new();
for name in &names {
let class = if unrecognized.contains(name) {
"unrecognized"
} else if census::policy_limited_literal(name).is_some() {
catalog_recognized += 1;
policy_limited += 1;
"policy_limited"
} else {
catalog_recognized += 1;
locally_evaluable += 1;
"locally_evaluable"
};
matrix.insert(name.clone(), class);
}
let probed: BTreeSet<&str> = names.iter().map(String::as_str).collect();
let policy_detail: Vec<serde_json::Value> = census::POLICY_LIMITED_FUNCTIONS
.iter()
.filter(|(n, _, _)| probed.contains(n))
.map(|(name, literal, reason)| {
serde_json::json!({
"function": name,
"literal": literal,
"reason": reason,
})
})
.collect();
let report = serde_json::json!({
"catalog_size": matrix.len(),
"catalog_recognized": catalog_recognized,
"locally_evaluable": locally_evaluable,
"policy_limited": policy_limited,
"unrecognized": unrecognized,
"policy_limited_detail": policy_detail,
"functions": matrix,
});
match serde_json::to_string_pretty(&report) {
Ok(json) => {
println!("{json}");
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("error: serialize: {e}");
ExitCode::FAILURE
}
}
}