Skip to main content

uni_btic/
certainty.rs

1use crate::error::BticError;
2
3/// Epistemic certainty of a BTIC bound value.
4///
5/// Certainty is metadata only; it does not affect comparison or ordering.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
7#[repr(u8)]
8pub enum Certainty {
9    /// Bound is known precisely to stated granularity.
10    Definite = 0,
11    /// Bound is estimated; true value may differ by +/-1 unit of granularity.
12    Approximate = 1,
13    /// Bound is weakly estimated; true value may differ significantly.
14    Uncertain = 2,
15    /// Bound is not meaningfully known; stored value is a best guess.
16    Unknown = 3,
17}
18
19impl Certainty {
20    /// Construct from a 2-bit code (0b00..=0b11).
21    pub fn from_code(code: u8) -> Result<Self, BticError> {
22        match code {
23            0 => Ok(Self::Definite),
24            1 => Ok(Self::Approximate),
25            2 => Ok(Self::Uncertain),
26            3 => Ok(Self::Unknown),
27            _ => Err(BticError::ParseError(format!(
28                "certainty code {code} out of range 0..=3"
29            ))),
30        }
31    }
32
33    /// The numeric code for this certainty level.
34    pub fn code(self) -> u8 {
35        self as u8
36    }
37
38    /// Human-readable name.
39    pub fn name(self) -> &'static str {
40        match self {
41            Self::Definite => "definite",
42            Self::Approximate => "approximate",
43            Self::Uncertain => "uncertain",
44            Self::Unknown => "unknown",
45        }
46    }
47
48    /// Returns the least certain of two values (max of the codes).
49    pub fn least_certain(self, other: Self) -> Self {
50        std::cmp::max(self, other)
51    }
52}
53
54impl std::fmt::Display for Certainty {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        f.write_str(self.name())
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn roundtrip_all_codes() {
66        for code in 0..=3u8 {
67            let c = Certainty::from_code(code).unwrap();
68            assert_eq!(c.code(), code);
69        }
70    }
71
72    #[test]
73    fn least_certain_picks_higher() {
74        assert_eq!(
75            Certainty::Definite.least_certain(Certainty::Approximate),
76            Certainty::Approximate
77        );
78        assert_eq!(
79            Certainty::Unknown.least_certain(Certainty::Definite),
80            Certainty::Unknown
81        );
82        assert_eq!(
83            Certainty::Uncertain.least_certain(Certainty::Uncertain),
84            Certainty::Uncertain
85        );
86    }
87}