1use super::ArtifactRef;
4use super::index::Kind;
5use super::status::{ArtifactVisitError, member_source, visit_artifacts};
6use crate::pki::{
7 AuthorityClosureError, AuthorityUses, ParticipantAuthority, ParticipantClosure, Uses, UsesError,
8};
9use crate::source::{Query, ScopeError};
10use structured_asn1::memory::{HashWork, MapExecution, MemoryError, OwnedMap, OwnedVec, Work};
11
12pub struct ArtifactUse<'certificate, 'document> {
16 artifact: ArtifactRef<'certificate, 'document>,
17 uses: Uses,
18 targets: Option<usize>,
19 next_identity: Option<usize>,
20}
21
22impl<'certificate, 'document> ArtifactUse<'certificate, 'document> {
23 #[must_use]
25 pub fn artifact(&self) -> ArtifactRef<'certificate, 'document> {
26 self.artifact
27 }
28 #[must_use]
30 pub fn uses(&self) -> Uses {
31 self.uses
32 }
33}
34
35pub struct ArtifactUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I> {
39 inputs: &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>,
40 entries: OwnedVec<ArtifactUse<'certificate, 'document>>,
41 targets: OwnedVec<StatusTarget>,
42}
43
44struct StatusTarget {
48 certificate: usize,
49 next: Option<usize>,
50}
51
52impl<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>
53 ArtifactUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>
54{
55 #[must_use]
57 pub fn inputs(
58 &self,
59 ) -> &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>
60 {
61 self.inputs
62 }
63 #[must_use]
65 pub fn entries(&self) -> &[ArtifactUse<'certificate, 'document>] {
66 &self.entries
67 }
68 #[must_use]
75 pub fn targets(&self, ordinal: usize) -> Targets<'_> {
76 Targets {
77 targets: &self.targets,
78 next: self.entries[ordinal].targets,
79 }
80 }
81}
82
83pub struct Targets<'a> {
85 targets: &'a [StatusTarget],
86 next: Option<usize>,
87}
88
89impl Iterator for Targets<'_> {
90 type Item = usize;
91 fn next(&mut self) -> Option<usize> {
92 let target = &self.targets[self.next?];
93 self.next = target.next;
94 Some(target.certificate)
95 }
96}
97
98impl core::iter::FusedIterator for Targets<'_> {}
99
100pub type ArtifactUsesResult<'closure, 'requirements, 'view, 'certificate, 'document, Q, I> = Result<
102 ArtifactUses<
103 'closure,
104 'requirements,
105 'view,
106 'certificate,
107 'document,
108 <Q as Query>::Id,
109 <Q as Query>::Document,
110 <Q as Query>::Generation,
111 I,
112 >,
113 UsesError<<Q as Query>::Id>,
114>;
115
116#[derive(Clone, Copy, PartialEq, Eq, Hash)]
117struct Bucket {
118 kind: Kind,
119 hash: u64,
120}
121impl HashWork for Bucket {
122 fn hash_work(&self) -> Result<u64, MemoryError> {
123 Ok(2)
124 }
125}
126
127struct Census<'certificate, 'document, W: Work> {
128 index: Option<OwnedMap<Bucket, usize, W>>,
129 entries: OwnedVec<ArtifactUse<'certificate, 'document>, W>,
130 targets: OwnedVec<StatusTarget, W>,
131}
132
133impl<'certificate, 'document, W: Work> Census<'certificate, 'document, W> {
134 fn record(
135 &mut self,
136 artifact: ArtifactRef<'certificate, 'document>,
137 uses: Uses,
138 work: &W,
139 ) -> Result<usize, MemoryError> {
140 let scoped = artifact.execution_in(work);
141 scoped.charge_work(1)?;
142 let key = artifact.identity();
143 let hash = self
144 .index
145 .as_ref()
146 .expect("census map restored before every visit")
147 .fingerprint(&key, &scoped)?;
148 self.record_hashed(
149 artifact,
150 uses,
151 work,
152 Bucket {
153 kind: key.kind,
154 hash,
155 },
156 )
157 }
158
159 fn record_hashed(
160 &mut self,
161 artifact: ArtifactRef<'certificate, 'document>,
162 uses: Uses,
163 work: &W,
164 key: Bucket,
165 ) -> Result<usize, MemoryError> {
166 let scoped = artifact.execution_in(work);
167 scoped.charge_work(1)?;
168 let head = self
169 .index
170 .as_ref()
171 .expect("census map restored before every visit")
172 .get(&key, &scoped)?
173 .copied();
174 let mut next = head;
175 while let Some(index) = next {
176 scoped.charge_work(1)?;
177 let stored = self.entries[index].artifact;
178 let original = stored.execution_in(work);
179 original.charge_work(1)?;
180 let first = artifact.identity().bytes;
181 let second = stored.identity().bytes;
182 let equal = if core::ptr::eq(first, second) {
183 true
184 } else if first.len() != second.len() {
185 false
186 } else {
187 let length = u64::try_from(first.len()).map_err(|_| MemoryError::WorkExceeded)?;
191 scoped.charge_work(length)?;
192 original.charge_work(length)?;
193 first == second
194 };
195 if equal {
196 self.entries[index].uses.merge(uses);
197 return Ok(index);
198 }
199 next = self.entries[index].next_identity;
200 }
201 let index = self.entries.len();
202 let original = self
203 .index
204 .take()
205 .expect("census map restored before every visit");
206 let (mut table, previous) = match original.rebind(scoped) {
207 MapExecution::Changed { map, previous } => (map, previous),
208 MapExecution::Foreign { map, .. } => {
209 self.index = Some(map);
210 unreachable!(
211 "one private census is always mutated under its original query account"
212 )
213 }
214 };
215 let inserted = table.try_insert(key, index);
216 self.index = Some(match table.rebind(previous) {
217 MapExecution::Changed { map, .. } => map,
218 MapExecution::Foreign { .. } => {
219 unreachable!("restoration returns the exact previous execution owner")
220 }
221 });
222 inserted?;
223 self.entries.try_push(ArtifactUse {
224 artifact,
225 uses,
226 targets: None,
227 next_identity: head,
228 })?;
229 Ok(index)
230 }
231}
232
233pub fn artifact_uses<'closure, 'requirements, 'view, 'certificate, 'document, Q: Query, I>(
244 authorities: &AuthorityUses<
245 'closure,
246 'requirements,
247 'view,
248 'certificate,
249 'document,
250 Q::Id,
251 Q::Document,
252 Q::Generation,
253 I,
254 >,
255 query: &Q,
256) -> ArtifactUsesResult<'closure, 'requirements, 'view, 'certificate, 'document, Q, I> {
257 let inputs = authorities.inputs();
258 let requirements = inputs.requirements();
259 if requirements.scope().location().snapshot != query.snapshot() {
260 return Err(UsesError::Foreign);
261 }
262 query
263 .admit(requirements.signature(), 1)
264 .map_err(UsesError::Scope)?;
265 let work = query.execution();
266 let resource = |cause| UsesError::Closure(AuthorityClosureError::Resource(cause));
267 let mut census = Census {
268 index: Some(work.map()),
269 entries: work.vector(),
270 targets: work.vector(),
271 };
272 for authority in authorities.entries() {
273 work.charge_work(1).map_err(resource)?;
274 let path = authority.node().statuses.path();
275 let uses = authority.uses();
276 if let Some(certificate) = path.anchor().certificate() {
277 census
278 .record(ArtifactRef::Certificate(certificate), uses, work)
279 .map_err(resource)?;
280 }
281 for member in path.members() {
282 census
283 .record(ArtifactRef::Certificate(member.certificate()), uses, work)
284 .map_err(resource)?;
285 }
286 for input in authority.node().statuses.entries() {
287 work.charge_work(1).map_err(resource)?;
288 let Some(source) = member_source(input) else {
289 continue;
290 };
291 let certificate = census
292 .record(ArtifactRef::Certificate(source.target()), uses, work)
293 .map_err(resource)?;
294 visit_artifacts(source, requirements.signature(), query, |artifact, _, _| {
295 let index = census.record(artifact, uses, work)?;
296 if !matches!(artifact, ArtifactRef::Certificate(_)) {
297 let next = census.entries[index].targets;
298 let target = census.targets.len();
299 census
300 .targets
301 .try_push(StatusTarget { certificate, next })?;
302 census.entries[index].targets = Some(target);
303 }
304 Ok::<_, MemoryError>(())
305 })
306 .map_err(|cause| match cause {
307 ArtifactVisitError::Scope(ScopeError::Resource { cause, .. })
308 | ArtifactVisitError::Visitor(cause) => resource(cause),
309 ArtifactVisitError::Scope(cause) => UsesError::Scope(cause),
310 })?;
311 }
312 }
313 for entry in requirements.entries() {
314 work.charge_work(1).map_err(resource)?;
315 let ParticipantAuthority::Anchor(anchor) = entry.authority() else {
316 continue;
317 };
318 if let Some(certificate) = anchor.anchor().certificate() {
319 census
320 .record(
321 ArtifactRef::Certificate(certificate),
322 Uses::participant(entry.participant()),
323 work,
324 )
325 .map_err(resource)?;
326 }
327 }
328 Ok(ArtifactUses {
329 inputs,
330 entries: census.entries.into_owned(),
331 targets: census.targets.into_owned(),
332 })
333}
334
335#[cfg(test)]
336mod tests;