use super::{ArtifactRef, ArtifactUses, Index, IndexError, Occurrence};
use crate::source::{Query, Snapshot};
use crate::timestamp::TimestampScope;
use structured_asn1::memory::{OwnedVec, Work};
pub struct IncorporatedArtifact<'certificate, 'document, N, D, G, P> {
artifact: ArtifactRef<'certificate, 'document>,
occurrence: Option<Occurrence<N, D, G, P>>,
}
impl<'certificate, 'document, N: Copy, D: Copy, G: Copy, P: Copy>
IncorporatedArtifact<'certificate, 'document, N, D, G, P>
{
#[must_use]
pub fn artifact(&self) -> ArtifactRef<'certificate, 'document> {
self.artifact
}
#[must_use]
pub fn occurrence(&self) -> Option<Occurrence<N, D, G, P>> {
self.occurrence
}
}
pub struct Incorporation<'certificate, 'document, N, D, G, P> {
snapshot: Snapshot<D, G>,
signature: N,
entries: OwnedVec<IncorporatedArtifact<'certificate, 'document, N, D, G, P>>,
all_present: bool,
}
impl<'certificate, 'document, N: Copy, D: Copy, G: Copy, P: Copy>
Incorporation<'certificate, 'document, N, D, G, P>
{
#[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, P>] {
&self.entries
}
#[must_use]
pub fn all_present(&self) -> bool {
self.all_present
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IncorporationError<N> {
Scope,
Index(IndexError<N>),
}
pub fn incorporation<'certificate, 'document, N, D, G, P, O, W, Q, I>(
uses: &ArtifactUses<'_, '_, '_, 'certificate, 'document, N, D, G, I>,
index: &Index<'_, N, D, G, P, O, W, I>,
query: &Q,
) -> Result<Incorporation<'certificate, 'document, N, D, G, P>, IncorporationError<N>>
where
N: Copy + Eq,
D: Copy + Eq,
G: Copy + Eq,
P: Copy,
W: Work,
Q: Query<Id = N, Document = D, Generation = G>,
{
let required = uses.inputs().requirements();
let TimestampScope::All(location) = required.scope() else {
return Err(IncorporationError::Scope);
};
if location.snapshot != query.snapshot() {
return Err(IncorporationError::Index(IndexError::Foreign {
signature: required.signature(),
}));
}
index
.require_signature(required.signature(), query)
.map_err(IncorporationError::Index)?;
let resource = |cause| {
IncorporationError::Index(IndexError::Resource {
signature: required.signature(),
cause,
})
};
let mut entries = query.execution().vector();
entries
.try_reserve_exact(uses.entries().len())
.map_err(resource)?;
let mut all_present = true;
for ordinal in 0..uses.entries().len() {
query
.admit(required.signature(), 2)
.map_err(|cause| IncorporationError::Index(IndexError::Scope(cause)))?;
let artifact = uses.entries()[ordinal].artifact();
let mut copies = index
.artifact(artifact, query)
.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(), query)
.map_err(IncorporationError::Index)?;
Ok(Incorporation {
snapshot: location.snapshot,
signature: required.signature(),
entries: entries.into_owned(),
all_present,
})
}