use super::Severity;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Tier {
Exact,
Sound,
Complete,
Heuristic,
}
impl Tier {
pub const ALL: [Tier; 4] = [Tier::Exact, Tier::Sound, Tier::Complete, Tier::Heuristic];
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Tier::Exact => "exact",
Tier::Sound => "sound",
Tier::Complete => "complete",
Tier::Heuristic => "heuristic",
}
}
#[must_use]
pub const fn from_str(value: &str) -> Option<Self> {
match value.as_bytes() {
b"exact" => Some(Tier::Exact),
b"sound" => Some(Tier::Sound),
b"complete" => Some(Tier::Complete),
b"heuristic" => Some(Tier::Heuristic),
_ => None,
}
}
#[must_use]
pub const fn admits(self, severity: Severity) -> bool {
!matches!((self, severity), (Tier::Heuristic, Severity::Error))
}
#[must_use]
pub const fn no_false_positives(self) -> bool {
matches!(self, Tier::Exact | Tier::Complete)
}
#[must_use]
pub const fn no_false_negatives(self) -> bool {
matches!(self, Tier::Exact | Tier::Sound)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Domain(&'static str);
impl Domain {
#[must_use]
pub const fn new(statement: &'static str) -> Self {
assert!(
!statement.is_empty(),
"a rule's declared domain must state what the tier's claim ranges over"
);
Self(statement)
}
#[must_use]
pub const fn as_str(self) -> &'static str {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RuleContract {
tier: Tier,
domain: Domain,
severity: Severity,
}
impl RuleContract {
#[must_use]
pub const fn new(tier: Tier, domain: Domain, severity: Severity) -> Self {
assert!(
tier.admits(severity),
"a heuristic rule cannot declare error severity: an error must be a proof"
);
Self {
tier,
domain,
severity,
}
}
#[must_use]
pub const fn tier(self) -> Tier {
self.tier
}
#[must_use]
pub const fn domain(self) -> Domain {
self.domain
}
#[must_use]
pub const fn severity(self) -> Severity {
self.severity
}
#[must_use]
pub const fn clamp(self, configured: Severity) -> Severity {
if self.tier.admits(configured) {
configured
} else {
Severity::Warning
}
}
}