use super::{
CompilationDisagreement, CompilationVerdict, CompiledDisagreement, CompiledObservation,
CompiledVerdict, DeclaredBehavior, DeclaredCompilation, DeclaredReadBack, ObservedCompilation,
ObservedMember,
};
pub fn compared_compilation(
observed: &ObservedCompilation,
declared: &DeclaredCompilation,
) -> CompilationVerdict {
match (observed.refusal(), declared.refusal()) {
(None, Some(_)) => {
CompilationVerdict::Deviates(CompilationDisagreement::AcceptedWhereRefusalDeclared)
}
(Some(anchor), None) => {
CompilationVerdict::Deviates(CompilationDisagreement::RefusedWhereAcceptanceDeclared {
observed: anchor.clone(),
})
}
(Some(observed), Some(expected)) if observed.code() != expected.code() => {
CompilationVerdict::Deviates(CompilationDisagreement::ErrorCode {
expected: expected.code().clone(),
observed: observed.code().clone(),
})
}
(Some(observed), Some(expected)) if observed.primary() != expected.primary() => {
CompilationVerdict::Deviates(CompilationDisagreement::PrimarySpan {
expected: expected.primary().clone(),
observed: observed.primary().clone(),
})
}
(None, None) | (Some(_), Some(_)) => CompilationVerdict::Conforms,
}
}
pub fn compared(
observed: &CompiledObservation,
declared: &DeclaredBehavior<'_>,
) -> CompiledVerdict {
match (observed, declared) {
(CompiledObservation::RefusedByCompiler, DeclaredBehavior::RefusedByCompiler) => {
CompiledVerdict::Conforms
}
(CompiledObservation::RefusedByCompiler, DeclaredBehavior::ReadsBack(_)) => {
CompiledVerdict::Deviates(CompiledDisagreement::RefusedWhereAcceptanceDeclared)
}
(CompiledObservation::ReadBack(_), DeclaredBehavior::RefusedByCompiler) => {
CompiledVerdict::Deviates(CompiledDisagreement::AcceptedWhereRefusalDeclared)
}
(CompiledObservation::ReadBack(read), DeclaredBehavior::ReadsBack(expected)) => {
match member_disagreement(read, expected.members()) {
Some(found) => CompiledVerdict::Deviates(found),
None => CompiledVerdict::Conforms,
}
}
}
}
fn member_disagreement(
read: &[ObservedMember],
declared: &[DeclaredReadBack<'_>],
) -> Option<CompiledDisagreement> {
let undeclared = read
.iter()
.find(|member| !declared.iter().any(|expected| expected.name == member.name));
if let Some(member) = undeclared {
return Some(CompiledDisagreement::UnexpectedMember {
member: member.name.clone(),
});
}
if let Some(member) = restated_member(read) {
return Some(CompiledDisagreement::DuplicateMember { member });
}
declared
.iter()
.find_map(|expected| member_value_disagreement(read, expected))
}
fn restated_member(read: &[ObservedMember]) -> Option<String> {
for (position, member) in read.iter().enumerate() {
let restated = read
.iter()
.take(position)
.any(|earlier| earlier.name == member.name);
if restated {
return Some(member.name.clone());
}
}
None
}
fn member_value_disagreement(
read: &[ObservedMember],
expected: &DeclaredReadBack<'_>,
) -> Option<CompiledDisagreement> {
let Some(member) = read.iter().find(|member| member.name == expected.name) else {
return Some(CompiledDisagreement::MissingMember {
member: expected.name.to_owned(),
});
};
if member.value == expected.value {
return None;
}
Some(CompiledDisagreement::MemberValue {
member: expected.name.to_owned(),
})
}