use super::{ArtifactRef, ArtifactUses, Index, IndexError, Occurrence};
use crate::timestamp::TimestampScope;
use crate::xml::{Access, Snapshot, Xml};
use structured_asn1::memory::{OwnedVec, Work};
pub struct IncorporatedArtifact<'certificate, 'document, N, D, G> {
artifact: ArtifactRef<'certificate, 'document>,
occurrence: Option<Occurrence<N, D, G>>,
}
impl<'certificate, 'document, N: Copy, D: Copy, G: Copy>
IncorporatedArtifact<'certificate, 'document, N, D, G>
{
#[must_use]
pub fn artifact(&self) -> ArtifactRef<'certificate, 'document> {
self.artifact
}
#[must_use]
pub fn occurrence(&self) -> Option<Occurrence<N, D, G>> {
self.occurrence
}
}
pub struct Incorporation<'certificate, 'document, N, D, G> {
snapshot: Snapshot<D, G>,
signature: N,
entries: OwnedVec<IncorporatedArtifact<'certificate, 'document, N, D, G>>,
all_present: bool,
}
impl<'certificate, 'document, N: Copy, D: Copy, G: Copy>
Incorporation<'certificate, 'document, N, D, G>
{
#[must_use]
pub fn snapshot(&self) -> Snapshot<D, G> {
self.snapshot
}
#[must_use]
pub fn signature(&self) -> N {
self.signature
}
#[must_use]
pub fn entries(&self) -> &[IncorporatedArtifact<'certificate, 'document, N, D, G>] {
&self.entries
}
#[must_use]
pub fn all_present(&self) -> bool {
self.all_present
}
}
#[derive(Debug)]
pub enum IncorporationError<E, N> {
Scope,
Index(IndexError<E, N>),
}
pub type IncorporationResult<'certificate, 'document, X> = Result<
Incorporation<
'certificate,
'document,
<X as Xml>::Id,
<X as Xml>::Document,
<X as Xml>::Generation,
>,
IncorporationError<<X as Xml>::Error, <X as Xml>::Id>,
>;
pub fn incorporation<'certificate, 'document, X: Xml, W: Work, Q: Work>(
uses: &ArtifactUses<'_, '_, '_, 'certificate, 'document, X::Id, X::Document, X::Generation>,
index: &Index<'_, X::Id, X::Document, X::Generation, W>,
access: &Access<'_, X, Q>,
) -> IncorporationResult<'certificate, 'document, X> {
let required = uses.inputs().requirements();
let TimestampScope::All(location) = required.scope() else {
return Err(IncorporationError::Scope);
};
if location.snapshot != access.snapshot() {
return Err(IncorporationError::Index(IndexError::Foreign {
signature: required.signature(),
}));
}
index
.require_signature(required.signature(), access)
.map_err(IncorporationError::Index)?;
let resource = |cause| {
IncorporationError::Index(IndexError::Resource {
signature: required.signature(),
cause,
})
};
let mut entries = access.execution().vector();
entries
.try_reserve_exact(uses.entries().len())
.map_err(resource)?;
let mut all_present = true;
for ordinal in 0..uses.entries().len() {
access
.query(required.signature(), |_, _, work| Ok(work.charge_work(1)))
.map_err(|cause| IncorporationError::Index(IndexError::Access(cause)))?
.map_err(resource)?;
let artifact = uses.entries()[ordinal].artifact();
let mut copies = index
.artifact(artifact, access)
.map_err(IncorporationError::Index)?;
let occurrence = copies
.next()
.transpose()
.map_err(IncorporationError::Index)?;
if occurrence.is_none() {
all_present = false;
}
entries
.try_push(IncorporatedArtifact {
artifact,
occurrence,
})
.map_err(resource)?;
}
index
.require_signature(required.signature(), access)
.map_err(IncorporationError::Index)?;
Ok(Incorporation {
snapshot: location.snapshot,
signature: required.signature(),
entries: entries.into_owned(),
all_present,
})
}