#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Uncertainty {
Confirmed,
Candidate,
Ambiguous,
Unresolved,
Unsupported,
Excluded,
Stale {
reason: String,
},
Incomplete {
reason: String,
},
}
impl Uncertainty {
pub fn reason(&self) -> String {
match self {
Uncertainty::Confirmed => "confirmed".to_string(),
Uncertainty::Candidate => "unrecognised-resolution".to_string(),
Uncertainty::Ambiguous => "compiler-ambiguous".to_string(),
Uncertainty::Unresolved => "compiler-unresolved".to_string(),
Uncertainty::Unsupported => "dynamic-dispatch".to_string(),
Uncertainty::Excluded => "inaccessible".to_string(),
Uncertainty::Stale { reason } => reason.clone(),
Uncertainty::Incomplete { reason } => reason.clone(),
}
}
pub fn is_confirmed(&self) -> bool {
matches!(self, Uncertainty::Confirmed)
}
}
pub fn from_resolution(resolution: &str) -> Uncertainty {
match resolution {
"confirmed" => Uncertainty::Confirmed,
"ambiguous" => Uncertainty::Ambiguous,
"unresolved" => Uncertainty::Unresolved,
"dynamic" => Uncertainty::Unsupported,
"inaccessible" => Uncertainty::Excluded,
_ => Uncertainty::Candidate,
}
}
pub fn from_compilation_state(state: &str, reason: &str) -> Option<Uncertainty> {
match state {
"complete" => None,
"unsupported" => Some(Uncertainty::Unsupported),
_ => Some(Uncertainty::Incomplete {
reason: reason.to_string(),
}),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn recognised_resolutions_map_to_their_own_state() {
assert_eq!(from_resolution("confirmed"), Uncertainty::Confirmed);
assert_eq!(from_resolution("ambiguous"), Uncertainty::Ambiguous);
assert_eq!(from_resolution("unresolved"), Uncertainty::Unresolved);
assert_eq!(from_resolution("dynamic"), Uncertainty::Unsupported);
assert_eq!(from_resolution("inaccessible"), Uncertainty::Excluded);
}
#[test]
fn an_unrecognised_resolution_is_a_candidate_not_a_confirmation() {
assert_eq!(from_resolution("future-outcome"), Uncertainty::Candidate);
assert!(!from_resolution("future-outcome").is_confirmed());
}
#[test]
fn only_confirmed_participates_in_override() {
assert!(Uncertainty::Confirmed.is_confirmed());
assert!(!Uncertainty::Ambiguous.is_confirmed());
assert!(!Uncertainty::Unresolved.is_confirmed());
assert!(!Uncertainty::Unsupported.is_confirmed());
assert!(!Uncertainty::Excluded.is_confirmed());
assert!(!Uncertainty::Candidate.is_confirmed());
assert!(!Uncertainty::Stale {
reason: "x".to_string()
}
.is_confirmed());
assert!(!Uncertainty::Incomplete {
reason: "x".to_string()
}
.is_confirmed());
}
#[test]
fn a_complete_compilation_defers_to_the_occurrence_resolution() {
assert_eq!(from_compilation_state("complete", "complete"), None);
}
#[test]
fn a_partial_or_unsupported_compilation_overrides_the_occurrence() {
assert_eq!(
from_compilation_state("partial", "binding-error"),
Some(Uncertainty::Incomplete {
reason: "binding-error".to_string()
})
);
assert_eq!(
from_compilation_state("unsupported", "no-target"),
Some(Uncertainty::Unsupported)
);
}
#[test]
fn every_state_carries_a_nonempty_reason() {
let states = [
Uncertainty::Confirmed,
Uncertainty::Candidate,
Uncertainty::Ambiguous,
Uncertainty::Unresolved,
Uncertainty::Unsupported,
Uncertainty::Excluded,
Uncertainty::Stale {
reason: "stale-x".to_string(),
},
Uncertainty::Incomplete {
reason: "incomplete-x".to_string(),
},
];
for state in states {
assert!(!state.reason().is_empty());
}
}
}