use super::{ExplanationIssue, RelatedDisposition, UniversalAnswer};
use crate::identity::{encode_bytes, encode_length};
use crate::kind::{Answer, Disposition, Question};
fn disposition_into(disposition: Disposition, into: &mut Vec<u8>) {
match disposition {
Disposition::Generated { unit } => {
into.push(0);
encode_bytes(unit.as_bytes(), into);
}
Disposition::NotApplicable { because } => {
into.push(1);
encode_bytes(&because.citation_bytes(), into);
}
Disposition::NotRequested { because } => {
into.push(2);
encode_bytes(&because.citation_bytes(), into);
}
Disposition::UnavailableUnderProfile { profile, because } => {
into.push(3);
profile.encode_into(into);
encode_bytes(&because.citation_bytes(), into);
}
}
}
fn related_into(related: &RelatedDisposition, into: &mut Vec<u8>) {
encode_bytes(related.kind.as_bytes(), into);
disposition_into(related.disposition, into);
}
pub(super) fn answer_material(answer: &UniversalAnswer, into: &mut Vec<u8>) {
match answer {
UniversalAnswer::Kind { name } => encode_bytes(name.as_bytes(), into),
UniversalAnswer::Owner { owner } => encode_bytes(&owner.citation_bytes(), into),
UniversalAnswer::CausingDeclarations {
commitment,
dependencies,
} => {
encode_bytes(commitment.as_bytes(), into);
encode_length(dependencies.len(), into);
for dependency in dependencies.iter() {
encode_bytes(dependency.as_bytes(), into);
}
}
UniversalAnswer::Profile { profile } => profile.encode_into(into),
UniversalAnswer::OutputAndDigest { outputs } => {
encode_length(outputs.len(), into);
for row in outputs.iter() {
row.output.encode_into(into);
encode_bytes(row.digest.as_bytes(), into);
}
}
UniversalAnswer::Assumptions { assumptions } => {
encode_length(assumptions.len(), into);
for assumption in assumptions.iter() {
encode_bytes(&assumption.citation_bytes(), into);
}
}
UniversalAnswer::Invalidators { triggers } => {
encode_length(triggers.count(), into);
for trigger in triggers.iter() {
trigger.encode_into(into);
}
}
UniversalAnswer::RelatedDispositions { related } => {
encode_length(related.len(), into);
for accounted in related.iter() {
related_into(accounted, into);
}
}
UniversalAnswer::Repairs { repairs } => {
encode_length(repairs.len(), into);
for repair in repairs.iter() {
encode_bytes(&repair.declared_by.citation_bytes(), into);
}
}
}
}
pub(super) fn seats_into<A: Answer>(answers: &[A], into: &mut Vec<u8>) {
encode_length(answers.len(), into);
for answer in answers {
into.extend_from_slice(&answer.question().slot().to_be_bytes());
answer.encode_into(into);
}
}
impl ExplanationIssue {
#[must_use]
pub fn canonical_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
self.encode_into(&mut bytes);
bytes
}
pub fn encode_into(&self, into: &mut Vec<u8>) {
into.push(self.slot());
let mut material = Vec::new();
self.material_into(&mut material);
encode_bytes(&material, into);
}
fn material_into(&self, into: &mut Vec<u8>) {
match self {
Self::UniversalUnanswered { question } | Self::UniversalAnsweredTwice { question } => {
into.extend_from_slice(&question.slot().to_be_bytes());
}
Self::DeclaredUnanswered { question, slot }
| Self::DeclaredAnsweredTwice { question, slot } => {
encode_bytes(question.as_bytes(), into);
into.extend_from_slice(&slot.to_be_bytes());
}
Self::QuestionOutsideRoster { question } => encode_bytes(question.as_bytes(), into),
Self::SeatBoundExceeded { bound, observed } => {
into.extend_from_slice(&bound.to_be_bytes());
into.extend_from_slice(&observed.to_be_bytes());
}
Self::OutputsBesideTheProof {
expected,
observed,
diverges,
} => {
into.extend_from_slice(&expected.to_be_bytes());
into.extend_from_slice(&observed.to_be_bytes());
into.extend_from_slice(&diverges.to_be_bytes());
}
}
}
}