use serde::Serialize;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum TypeFidelity {
Exact,
Compatible,
LogicalString,
Lossy,
Unsupported,
}
impl TypeFidelity {
pub fn label(self) -> &'static str {
match self {
TypeFidelity::Exact => "exact",
TypeFidelity::Compatible => "compatible",
TypeFidelity::LogicalString => "logical_string",
TypeFidelity::Lossy => "lossy",
TypeFidelity::Unsupported => "unsupported",
}
}
#[allow(dead_code)]
pub fn is_unsafe_for_strict_mode(self) -> bool {
matches!(self, TypeFidelity::Lossy | TypeFidelity::Unsupported)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fidelity_label_round_trips_through_json() {
let cases = [
(TypeFidelity::Exact, "\"exact\""),
(TypeFidelity::Compatible, "\"compatible\""),
(TypeFidelity::LogicalString, "\"logical_string\""),
(TypeFidelity::Lossy, "\"lossy\""),
(TypeFidelity::Unsupported, "\"unsupported\""),
];
for (f, expected_json) in cases {
assert_eq!(
serde_json::to_string(&f).expect("serialize fidelity"),
expected_json,
"JSON shape for {:?} must match label() so CLI --json output is stable",
f
);
assert_eq!(f.label(), expected_json.trim_matches('"'));
}
}
#[test]
fn ordering_is_best_to_worst() {
assert!(TypeFidelity::Exact < TypeFidelity::Compatible);
assert!(TypeFidelity::Compatible < TypeFidelity::LogicalString);
assert!(TypeFidelity::LogicalString < TypeFidelity::Lossy);
assert!(TypeFidelity::Lossy < TypeFidelity::Unsupported);
}
#[test]
fn strict_mode_only_rejects_lossy_and_unsupported() {
assert!(!TypeFidelity::Exact.is_unsafe_for_strict_mode());
assert!(!TypeFidelity::Compatible.is_unsafe_for_strict_mode());
assert!(!TypeFidelity::LogicalString.is_unsafe_for_strict_mode());
assert!(TypeFidelity::Lossy.is_unsafe_for_strict_mode());
assert!(TypeFidelity::Unsupported.is_unsafe_for_strict_mode());
}
}