use std::sync::OnceLock;
use serde::Deserialize;
const TABLE_JSON: &str = include_str!("../data/codes.json");
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct Code {
pub code: String,
pub severity: String,
pub domain: String,
pub summary: String,
}
#[derive(Deserialize)]
struct Table {
codes: Vec<Code>,
}
pub const DOMAINS: [&str; 9] =
["container", "geometry", "images", "labels", "annotations", "transforms", "curation", "integrity", "clinical"];
pub fn all() -> &'static [Code] {
static TABLE: OnceLock<Vec<Code>> = OnceLock::new();
TABLE.get_or_init(|| {
let table: Table = serde_json::from_str(TABLE_JSON).expect("data/codes.json is valid by construction");
table.codes
})
}
pub fn get(code: &str) -> Option<&'static Code> {
all().iter().find(|c| c.code == code)
}
pub fn code(name: &str) -> crate::Result<&'static Code> {
get(name).ok_or_else(|| crate::Error::Key(format!("unknown diagnostic code {name:?}")))
}
pub fn for_domain(domain: &str) -> Vec<&'static Code> {
all().iter().filter(|c| c.domain == domain).collect()
}
pub fn table_json() -> &'static str {
TABLE_JSON
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn table_is_complete_and_well_formed() {
let codes = all();
assert_eq!(codes.len(), 95);
for c in codes {
let expected = if c.code.starts_with('W') { "warning" } else { "error" };
assert_eq!(c.severity, expected, "{}", c.code);
assert!(DOMAINS.contains(&c.domain.as_str()), "{}", c.code);
}
let names: std::collections::BTreeSet<&str> = codes.iter().map(|c| c.code.as_str()).collect();
assert_eq!(names.len(), codes.len(), "a code is listed twice");
}
}