use crate::Error;
use crate::Octets;
use crate::digest::{DigestBatch, DigestError, DigestMemo, DigestOutput};
use crate::provider::{SignatureAnswer, SignatureProvider};
use crate::stream::{self, Sink, Source, StreamError};
use structured_asn1::memory::{OwnedVec, Work};
use structured_pkix::path::WorkingKey;
pub struct RawRequest<'a, P: SignatureProvider<'a>> {
pub identity: P::SignatureIdentity,
pub key: WorkingKey<'a>,
pub signature: &'a Octets<'a>,
}
#[derive(Debug)]
pub enum PayloadError<E> {
Processing(Error),
Callback(E),
Digest(DigestError<E>),
}
pub type PassError<SE, PE> = StreamError<SE, PayloadError<PE>>;
pub struct PayloadBatch<'a, P: SignatureProvider<'a>> {
digests: DigestBatch<'a, P>,
raw: OwnedVec<P::RawState>,
}
pub struct Completed<'a, P: SignatureProvider<'a>> {
digests: DigestMemo<'a, P>,
raw: OwnedVec<SignatureAnswer>,
}
impl<'a, P: SignatureProvider<'a>> Completed<'a, P> {
#[must_use]
pub fn digests(&self) -> &DigestMemo<'a, P> {
&self.digests
}
#[must_use]
pub fn raw(&self) -> &[SignatureAnswer] {
&self.raw
}
}
impl<'a, P: SignatureProvider<'a>> PayloadBatch<'a, P> {
pub fn prepare<W: Work>(
digests: DigestBatch<'a, P>,
requests: OwnedVec<RawRequest<'a, P>>,
execution: &W,
) -> Result<Self, PayloadError<P::Error>> {
let (field, at) = digests.location();
let refusal = |reason| PayloadError::Processing(Error::resource(reason, field, at));
let mut raw = execution.vector();
raw.try_reserve_exact(requests.len()).map_err(refusal)?;
execution
.charge_work(core::mem::size_of_val(&*requests) as u64)
.map_err(refusal)?;
for request in requests {
execution.charge_work(1).map_err(refusal)?;
let state = digests
.provider()
.start_raw(&request.identity, request.key, request.signature, execution)
.map_err(PayloadError::Callback)?;
raw.try_push(state).map_err(refusal)?;
}
Ok(Self {
digests,
raw: raw.into_owned(),
})
}
pub fn run<S: Source, W: Work>(
mut self,
source: &mut S,
execution: &W,
) -> Result<Completed<'a, P>, PassError<S::Error, P::Error>> {
let (field, at) = self.digests.location();
let refusal = |reason| StreamError::Processing(Error::resource(reason, field, at));
let mut outputs: OwnedVec<DigestOutput<'a, P>, W> = execution.vector();
outputs
.try_reserve_exact(self.digests.len())
.map_err(refusal)?;
let mut answers = execution.vector();
answers.try_reserve_exact(self.raw.len()).map_err(refusal)?;
stream::run(source, &mut PayloadSink(&mut self), execution, field, at)?;
execution
.charge_work(core::mem::size_of_val(&*self.raw) as u64)
.map_err(refusal)?;
let provider = self.digests.provider();
let digests = self
.digests
.finish(outputs, execution)
.map_err(|error| StreamError::Callback(PayloadError::Digest(error)))?;
for state in self.raw {
execution.charge_work(1).map_err(refusal)?;
let answer = provider
.finish_raw(state, execution)
.map_err(|error| StreamError::Callback(PayloadError::Callback(error)))?;
answers.try_push(answer).map_err(refusal)?;
}
Ok(Completed {
digests,
raw: answers.into_owned(),
})
}
}
struct PayloadSink<'s, 'a, P: SignatureProvider<'a>>(&'s mut PayloadBatch<'a, P>);
impl<'a, P: SignatureProvider<'a>> Sink for PayloadSink<'_, 'a, P> {
type Error = PayloadError<P::Error>;
fn write<W: Work>(&mut self, bytes: &[u8], execution: &W) -> Result<(), Self::Error> {
self.0
.digests
.feed(bytes, execution)
.map_err(PayloadError::Digest)?;
let (field, at) = self.0.digests.location();
for state in &mut self.0.raw {
execution
.charge_work(1)
.map_err(|reason| PayloadError::Processing(Error::resource(reason, field, at)))?;
self.0
.digests
.provider()
.update_raw(state, bytes, execution)
.map_err(PayloadError::Callback)?;
}
Ok(())
}
}