use super::ArtifactRef;
use super::index::Kind;
use super::status::{ArtifactVisitError, member_source, visit_artifacts};
use crate::pki::{
AuthorityClosureError, AuthorityUses, ParticipantAuthority, ParticipantClosure, Uses, UsesError,
};
use crate::source::{Query, ScopeError};
use structured_asn1::memory::{HashWork, MapExecution, MemoryError, OwnedMap, OwnedVec, Work};
pub struct ArtifactUse<'certificate, 'document> {
artifact: ArtifactRef<'certificate, 'document>,
uses: Uses,
targets: Option<usize>,
next_identity: Option<usize>,
}
impl<'certificate, 'document> ArtifactUse<'certificate, 'document> {
#[must_use]
pub fn artifact(&self) -> ArtifactRef<'certificate, 'document> {
self.artifact
}
#[must_use]
pub fn uses(&self) -> Uses {
self.uses
}
}
pub struct ArtifactUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I> {
inputs: &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>,
entries: OwnedVec<ArtifactUse<'certificate, 'document>>,
targets: OwnedVec<StatusTarget>,
}
struct StatusTarget {
certificate: usize,
next: Option<usize>,
}
impl<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>
ArtifactUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>
{
#[must_use]
pub fn inputs(
&self,
) -> &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>
{
self.inputs
}
#[must_use]
pub fn entries(&self) -> &[ArtifactUse<'certificate, 'document>] {
&self.entries
}
#[must_use]
pub fn targets(&self, ordinal: usize) -> Targets<'_> {
Targets {
targets: &self.targets,
next: self.entries[ordinal].targets,
}
}
}
pub struct Targets<'a> {
targets: &'a [StatusTarget],
next: Option<usize>,
}
impl Iterator for Targets<'_> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
let target = &self.targets[self.next?];
self.next = target.next;
Some(target.certificate)
}
}
impl core::iter::FusedIterator for Targets<'_> {}
pub type ArtifactUsesResult<'closure, 'requirements, 'view, 'certificate, 'document, Q, I> = Result<
ArtifactUses<
'closure,
'requirements,
'view,
'certificate,
'document,
<Q as Query>::Id,
<Q as Query>::Document,
<Q as Query>::Generation,
I,
>,
UsesError<<Q as Query>::Id>,
>;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
struct Bucket {
kind: Kind,
hash: u64,
}
impl HashWork for Bucket {
fn hash_work(&self) -> Result<u64, MemoryError> {
Ok(2)
}
}
struct Census<'certificate, 'document, W: Work> {
index: Option<OwnedMap<Bucket, usize, W>>,
entries: OwnedVec<ArtifactUse<'certificate, 'document>, W>,
targets: OwnedVec<StatusTarget, W>,
}
impl<'certificate, 'document, W: Work> Census<'certificate, 'document, W> {
fn record(
&mut self,
artifact: ArtifactRef<'certificate, 'document>,
uses: Uses,
work: &W,
) -> Result<usize, MemoryError> {
let scoped = artifact.execution_in(work);
scoped.charge_work(1)?;
let key = artifact.identity();
let hash = self
.index
.as_ref()
.expect("census map restored before every visit")
.fingerprint(&key, &scoped)?;
self.record_hashed(
artifact,
uses,
work,
Bucket {
kind: key.kind,
hash,
},
)
}
fn record_hashed(
&mut self,
artifact: ArtifactRef<'certificate, 'document>,
uses: Uses,
work: &W,
key: Bucket,
) -> Result<usize, MemoryError> {
let scoped = artifact.execution_in(work);
scoped.charge_work(1)?;
let head = self
.index
.as_ref()
.expect("census map restored before every visit")
.get(&key, &scoped)?
.copied();
let mut next = head;
while let Some(index) = next {
scoped.charge_work(1)?;
let stored = self.entries[index].artifact;
let original = stored.execution_in(work);
original.charge_work(1)?;
let first = artifact.identity().bytes;
let second = stored.identity().bytes;
let equal = if core::ptr::eq(first, second) {
true
} else if first.len() != second.len() {
false
} else {
let length = u64::try_from(first.len()).map_err(|_| MemoryError::WorkExceeded)?;
scoped.charge_work(length)?;
original.charge_work(length)?;
first == second
};
if equal {
self.entries[index].uses.merge(uses);
return Ok(index);
}
next = self.entries[index].next_identity;
}
let index = self.entries.len();
let original = self
.index
.take()
.expect("census map restored before every visit");
let (mut table, previous) = match original.rebind(scoped) {
MapExecution::Changed { map, previous } => (map, previous),
MapExecution::Foreign { map, .. } => {
self.index = Some(map);
unreachable!(
"one private census is always mutated under its original query account"
)
}
};
let inserted = table.try_insert(key, index);
self.index = Some(match table.rebind(previous) {
MapExecution::Changed { map, .. } => map,
MapExecution::Foreign { .. } => {
unreachable!("restoration returns the exact previous execution owner")
}
});
inserted?;
self.entries.try_push(ArtifactUse {
artifact,
uses,
targets: None,
next_identity: head,
})?;
Ok(index)
}
}
pub fn artifact_uses<'closure, 'requirements, 'view, 'certificate, 'document, Q: Query, I>(
authorities: &AuthorityUses<
'closure,
'requirements,
'view,
'certificate,
'document,
Q::Id,
Q::Document,
Q::Generation,
I,
>,
query: &Q,
) -> ArtifactUsesResult<'closure, 'requirements, 'view, 'certificate, 'document, Q, I> {
let inputs = authorities.inputs();
let requirements = inputs.requirements();
if requirements.scope().location().snapshot != query.snapshot() {
return Err(UsesError::Foreign);
}
query
.admit(requirements.signature(), 1)
.map_err(UsesError::Scope)?;
let work = query.execution();
let resource = |cause| UsesError::Closure(AuthorityClosureError::Resource(cause));
let mut census = Census {
index: Some(work.map()),
entries: work.vector(),
targets: work.vector(),
};
for authority in authorities.entries() {
work.charge_work(1).map_err(resource)?;
let path = authority.node().statuses.path();
let uses = authority.uses();
if let Some(certificate) = path.anchor().certificate() {
census
.record(ArtifactRef::Certificate(certificate), uses, work)
.map_err(resource)?;
}
for member in path.members() {
census
.record(ArtifactRef::Certificate(member.certificate()), uses, work)
.map_err(resource)?;
}
for input in authority.node().statuses.entries() {
work.charge_work(1).map_err(resource)?;
let Some(source) = member_source(input) else {
continue;
};
let certificate = census
.record(ArtifactRef::Certificate(source.target()), uses, work)
.map_err(resource)?;
visit_artifacts(source, requirements.signature(), query, |artifact, _, _| {
let index = census.record(artifact, uses, work)?;
if !matches!(artifact, ArtifactRef::Certificate(_)) {
let next = census.entries[index].targets;
let target = census.targets.len();
census
.targets
.try_push(StatusTarget { certificate, next })?;
census.entries[index].targets = Some(target);
}
Ok::<_, MemoryError>(())
})
.map_err(|cause| match cause {
ArtifactVisitError::Scope(ScopeError::Resource { cause, .. })
| ArtifactVisitError::Visitor(cause) => resource(cause),
ArtifactVisitError::Scope(cause) => UsesError::Scope(cause),
})?;
}
}
for entry in requirements.entries() {
work.charge_work(1).map_err(resource)?;
let ParticipantAuthority::Anchor(anchor) = entry.authority() else {
continue;
};
if let Some(certificate) = anchor.anchor().certificate() {
census
.record(
ArtifactRef::Certificate(certificate),
Uses::participant(entry.participant()),
work,
)
.map_err(resource)?;
}
}
Ok(ArtifactUses {
inputs,
entries: census.entries.into_owned(),
targets: census.targets.into_owned(),
})
}
#[cfg(test)]
mod tests;