use super::{DECLARED_QUESTION_LIMIT, ExplanationIssue, UniversalAnswer, UniversalQuestion};
use crate::kind::{Answer, Kind, Question};
fn answered<Q: Question>(answers: &[Q::Answer], question: Q) -> usize {
answers
.iter()
.filter(|answer| answer.question() == question)
.count()
}
fn universal_coverage(answers: &[UniversalAnswer], issues: &mut Vec<ExplanationIssue>) {
for question in <UniversalQuestion as Question>::ALL {
let count = answered::<UniversalQuestion>(answers, *question);
if count == 0 {
issues.push(ExplanationIssue::UniversalUnanswered {
question: *question,
});
} else if count > 1 {
issues.push(ExplanationIssue::UniversalAnsweredTwice {
question: *question,
});
}
}
}
fn declared_coverage<K: Kind>(
answers: &[<K::Question as Question>::Answer],
issues: &mut Vec<ExplanationIssue>,
) {
let roster = <K::Question as Question>::ALL;
if roster.len() > DECLARED_QUESTION_LIMIT {
issues.push(ExplanationIssue::SeatBoundExceeded {
bound: u64::try_from(DECLARED_QUESTION_LIMIT).unwrap_or(u64::MAX),
observed: u64::try_from(roster.len()).unwrap_or(u64::MAX),
});
}
for question in roster {
let count = answered::<K::Question>(answers, *question);
if count == 0 {
issues.push(ExplanationIssue::DeclaredUnanswered {
question: question.name(),
slot: question.slot(),
});
} else if count > 1 {
issues.push(ExplanationIssue::DeclaredAnsweredTwice {
question: question.name(),
slot: question.slot(),
});
}
}
for answer in answers {
let question = answer.question();
if !roster.contains(&question) {
issues.push(ExplanationIssue::QuestionOutsideRoster {
question: question.name(),
});
}
}
}
pub(super) fn coverage_issues<K: Kind>(
universal: &[UniversalAnswer],
declared: &[<K::Question as Question>::Answer],
) -> Vec<ExplanationIssue> {
let mut issues: Vec<ExplanationIssue> = Vec::new();
universal_coverage(universal, &mut issues);
declared_coverage::<K>(declared, &mut issues);
issues
}