use super::{BasicError, Hint, HintSource, ProcessingResult};
use crate::{
binary::BinaryXml,
certificate,
prepare::Prepared,
validation::{self, ReferenceIdentifier},
xml::Xml,
};
use structured_asn1::{
Reader,
memory::{OwnedVec, Work},
};
pub(super) struct EncodingChecks<N, D, G> {
pub(super) items: OwnedVec<Hint<N, D, G>>,
pub(super) all_conformant: bool,
}
type ResultFor<X> = ProcessingResult<
EncodingChecks<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>,
X,
>;
pub(super) fn check_encodings<X: BinaryXml>(
prepared: &Prepared<X>,
xml: &X,
operation: &Reader<'_>,
) -> ResultFor<X> {
let work = operation.execution();
let signature = prepared.bound().containers().signature();
let mut items = work.vector();
let mut all_conformant = true;
for (index, reference) in prepared.certificates().entries().iter().enumerate() {
let resource = |cause| BasicError::Resource {
node: reference.node(),
cause,
};
work.charge_work(1).map_err(resource)?;
if reference.issuer_serial().is_none() {
continue;
}
items.try_reserve(1).map_err(resource)?;
let hint = certificate::with_issuer_serial(
xml,
prepared.certificates(),
index,
operation,
|reading| Ok::<_, core::convert::Infallible>(reading.into_parts().1),
)
.map_err(BasicError::Hint)?
.ok_or(BasicError::Foreign { signature })?;
if !hint.value.is_empty() {
all_conformant = false;
}
items
.try_push(Hint {
location: hint.location,
faults: hint.value,
source: HintSource::Protected(index),
})
.map_err(resource)?;
}
for (property, references) in prepared.validation_references().iter().enumerate() {
work.charge_work(1).map_err(|cause| BasicError::Resource {
node: references.node(),
cause,
})?;
for (entry, reference) in references.entries().iter().enumerate() {
let resource = |cause| BasicError::Resource {
node: reference.node(),
cause,
};
work.charge_work(1).map_err(resource)?;
if !matches!(
reference.identifier(),
ReferenceIdentifier::Certificate { .. }
) {
continue;
}
items.try_reserve(1).map_err(resource)?;
let hint = validation::with_reference_issuer_serial(
xml,
references,
entry,
operation,
|reading| Ok::<_, core::convert::Infallible>(reading.into_parts().1),
)
.map_err(BasicError::Hint)?
.ok_or(BasicError::Foreign { signature })?;
if !hint.value.is_empty() {
all_conformant = false;
}
items
.try_push(Hint {
location: hint.location,
faults: hint.value,
source: HintSource::ValidationReference { property, entry },
})
.map_err(resource)?;
}
}
Ok(EncodingChecks {
items: items.into_owned(),
all_conformant,
})
}