use super::TokenView;
use crate::binary::Location;
use structured_asn1::{
Element, Oid, Reader, Tag,
memory::{MemoryError, OwnedVec, Work},
universal,
};
use structured_cms::signed::OtherRevocationInfo;
use structured_ltv::material::CarriedOrigin;
use structured_pkix::{
crl::CertificateList,
ocsp::{BasicResponse, ResponseBytes},
};
pub struct Carried<T> {
pub origin: CarriedOrigin,
pub value: T,
}
pub struct OtherCarried<'source> {
pub kind: Oid<'source>,
pub value: Element<'source>,
}
pub struct CarriedMaterial<'source, N, D, G> {
pub(crate) view: TokenView<'source, N, D, G>,
crls: OwnedVec<Carried<CertificateList<'source>>>,
responses: OwnedVec<Carried<ResponseBytes<'source>>>,
basic: OwnedVec<Carried<BasicResponse<'source>>>,
other: OwnedVec<Carried<OtherCarried<'source>>>,
}
impl<'source, N, D, G> CarriedMaterial<'source, N, D, G> {
#[must_use]
pub fn crls(&self) -> &[Carried<CertificateList<'source>>] {
&self.crls
}
#[must_use]
pub fn responses(&self) -> &[Carried<ResponseBytes<'source>>] {
&self.responses
}
#[must_use]
pub fn basic_responses(&self) -> &[Carried<BasicResponse<'source>>] {
&self.basic
}
#[must_use]
pub fn other(&self) -> &[Carried<OtherCarried<'source>>] {
&self.other
}
}
#[derive(Debug)]
pub enum CarriedCause {
Encoding(structured_asn1::Error),
Cms(structured_cms::Error),
Pkix(structured_pkix::Error),
Resource(MemoryError),
}
#[derive(Debug)]
pub struct CarriedError<N, D, G> {
pub location: Location<N, D, G>,
pub origin: CarriedOrigin,
pub cause: CarriedCause,
}
impl<'source, N: Copy, D: Copy, G: Copy> TokenView<'source, N, D, G> {
pub fn material_in<'query>(
&self,
operation: &Reader<'query>,
) -> Result<CarriedMaterial<'query, N, D, G>, CarriedError<N, D, G>>
where
'source: 'query,
{
let execution = operation.execution();
let mut crls = execution.vector();
let mut responses = execution.vector();
let mut basic = execution.vector();
let mut other = execution.vector();
if let Some(first) = self.sources().first() {
operation
.charge(self.sources().len() as u64)
.map_err(|cause| CarriedError {
location: first.location(),
origin: CarriedOrigin {
token: 0,
choice: 0,
},
cause: CarriedCause::Encoding(cause),
})?;
}
for token in 0..self.sources().len() {
let source = &self.sources()[token];
let mut choice = 0;
loop {
let origin = CarriedOrigin { token, choice };
let error = |cause| CarriedError {
location: source.location(),
origin,
cause,
};
let message = self.readings()[token].token().message();
let Some(reader) = message
.revocation_reader_in(operation, choice)
.map_err(|cause| error(CarriedCause::Cms(cause)))?
else {
break;
};
let entry = message.revocations()[choice];
if entry.tag() == Tag::constructed(universal::SEQUENCE) {
crls.try_reserve(1)
.map_err(|cause| error(CarriedCause::Resource(cause)))?;
let value = CertificateList::read_element(&reader, &entry)
.map_err(|cause| error(CarriedCause::Pkix(cause)))?;
crls.try_push(Carried { origin, value })
.map_err(|cause| error(CarriedCause::Resource(cause)))?;
} else {
let format = OtherRevocationInfo::read(&reader, &entry)
.map_err(|cause| error(CarriedCause::Cms(cause)))?;
let value = OtherCarried {
kind: format.kind(),
value: format.value(),
};
if let Some(response) = format
.ocsp()
.map_err(|cause| error(CarriedCause::Cms(cause)))?
{
responses
.try_reserve(1)
.map_err(|cause| error(CarriedCause::Resource(cause)))?;
if let Some(value) = response
.basic_in(operation)
.map_err(|cause| error(CarriedCause::Pkix(cause)))?
{
basic
.try_push(Carried { origin, value })
.map_err(|cause| error(CarriedCause::Resource(cause)))?;
}
responses
.try_push(Carried {
origin,
value: response,
})
.map_err(|cause| error(CarriedCause::Resource(cause)))?;
} else {
other
.try_push(Carried { origin, value })
.map_err(|cause| error(CarriedCause::Resource(cause)))?;
}
}
choice += 1;
}
}
Ok(CarriedMaterial {
view: self.reborrow(),
crls: crls.into_owned(),
responses: responses.into_owned(),
basic: basic.into_owned(),
other: other.into_owned(),
})
}
}