1use super::ArtifactRef;
4use super::index::ArtifactKey;
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::{MemoryError, OwnedMap, OwnedVec, Work};
11
12pub struct ArtifactUse<'certificate, 'document> {
16 artifact: ArtifactRef<'certificate, 'document>,
17 uses: Uses,
18 targets: Option<usize>,
19}
20
21impl<'certificate, 'document> ArtifactUse<'certificate, 'document> {
22 #[must_use]
24 pub fn artifact(&self) -> ArtifactRef<'certificate, 'document> {
25 self.artifact
26 }
27 #[must_use]
29 pub fn uses(&self) -> Uses {
30 self.uses
31 }
32}
33
34pub struct ArtifactUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I> {
38 inputs: &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>,
39 entries: OwnedVec<ArtifactUse<'certificate, 'document>>,
40 targets: OwnedVec<StatusTarget>,
41}
42
43struct StatusTarget {
47 certificate: usize,
48 next: Option<usize>,
49}
50
51impl<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>
52 ArtifactUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>
53{
54 #[must_use]
56 pub fn inputs(
57 &self,
58 ) -> &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>
59 {
60 self.inputs
61 }
62 #[must_use]
64 pub fn entries(&self) -> &[ArtifactUse<'certificate, 'document>] {
65 &self.entries
66 }
67 #[must_use]
74 pub fn targets(&self, ordinal: usize) -> Targets<'_> {
75 Targets {
76 targets: &self.targets,
77 next: self.entries[ordinal].targets,
78 }
79 }
80}
81
82pub struct Targets<'a> {
84 targets: &'a [StatusTarget],
85 next: Option<usize>,
86}
87
88impl Iterator for Targets<'_> {
89 type Item = usize;
90 fn next(&mut self) -> Option<usize> {
91 let target = &self.targets[self.next?];
92 self.next = target.next;
93 Some(target.certificate)
94 }
95}
96
97impl core::iter::FusedIterator for Targets<'_> {}
98
99pub type ArtifactUsesResult<'closure, 'requirements, 'view, 'certificate, 'document, Q, I> = Result<
101 ArtifactUses<
102 'closure,
103 'requirements,
104 'view,
105 'certificate,
106 'document,
107 <Q as Query>::Id,
108 <Q as Query>::Document,
109 <Q as Query>::Generation,
110 I,
111 >,
112 UsesError<<Q as Query>::Id>,
113>;
114
115struct Census<'certificate, 'document, W: Work> {
116 index: OwnedMap<ArtifactKey<'document>, usize, W>,
117 entries: OwnedVec<ArtifactUse<'certificate, 'document>, W>,
118 targets: OwnedVec<StatusTarget, W>,
119}
120
121impl<'certificate, 'document, W: Work> Census<'certificate, 'document, W> {
122 fn record(
123 &mut self,
124 artifact: ArtifactRef<'certificate, 'document>,
125 uses: Uses,
126 work: &W,
127 ) -> Result<usize, MemoryError> {
128 work.charge_work(1)?;
129 let key = artifact.identity();
130 if let Some(&index) = self.index.get(&key, work)? {
131 self.entries[index].uses.merge(uses);
132 return Ok(index);
133 }
134 let index = self.entries.len();
135 self.index.try_insert(key, index)?;
136 self.entries.try_push(ArtifactUse {
137 artifact,
138 uses,
139 targets: None,
140 })?;
141 Ok(index)
142 }
143}
144
145pub fn artifact_uses<'closure, 'requirements, 'view, 'certificate, 'document, Q: Query, I>(
156 authorities: &AuthorityUses<
157 'closure,
158 'requirements,
159 'view,
160 'certificate,
161 'document,
162 Q::Id,
163 Q::Document,
164 Q::Generation,
165 I,
166 >,
167 query: &Q,
168) -> ArtifactUsesResult<'closure, 'requirements, 'view, 'certificate, 'document, Q, I> {
169 let inputs = authorities.inputs();
170 let requirements = inputs.requirements();
171 if requirements.scope().location().snapshot != query.snapshot() {
172 return Err(UsesError::Foreign);
173 }
174 query
175 .admit(requirements.signature(), 1)
176 .map_err(UsesError::Scope)?;
177 let work = query.execution();
178 let resource = |cause| UsesError::Closure(AuthorityClosureError::Resource(cause));
179 let mut census = Census {
180 index: work.map(),
181 entries: work.vector(),
182 targets: work.vector(),
183 };
184 for authority in authorities.entries() {
185 work.charge_work(1).map_err(resource)?;
186 let path = authority.node().statuses.path();
187 let uses = authority.uses();
188 if let Some(certificate) = path.anchor().certificate() {
189 census
190 .record(ArtifactRef::Certificate(certificate), uses, work)
191 .map_err(resource)?;
192 }
193 for member in path.members() {
194 census
195 .record(ArtifactRef::Certificate(member.certificate()), uses, work)
196 .map_err(resource)?;
197 }
198 for input in authority.node().statuses.entries() {
199 work.charge_work(1).map_err(resource)?;
200 let Some(source) = member_source(input) else {
201 continue;
202 };
203 let certificate = census
204 .record(ArtifactRef::Certificate(source.target()), uses, work)
205 .map_err(resource)?;
206 visit_artifacts(source, requirements.signature(), query, |artifact, _, _| {
207 let index = census.record(artifact, uses, work)?;
208 if !matches!(artifact, ArtifactRef::Certificate(_)) {
209 let next = census.entries[index].targets;
210 let target = census.targets.len();
211 census
212 .targets
213 .try_push(StatusTarget { certificate, next })?;
214 census.entries[index].targets = Some(target);
215 }
216 Ok::<_, MemoryError>(())
217 })
218 .map_err(|cause| match cause {
219 ArtifactVisitError::Scope(ScopeError::Resource { cause, .. })
220 | ArtifactVisitError::Visitor(cause) => resource(cause),
221 ArtifactVisitError::Scope(cause) => UsesError::Scope(cause),
222 })?;
223 }
224 }
225 for entry in requirements.entries() {
226 work.charge_work(1).map_err(resource)?;
227 let ParticipantAuthority::Anchor(anchor) = entry.authority() else {
228 continue;
229 };
230 if let Some(certificate) = anchor.anchor().certificate() {
231 census
232 .record(
233 ArtifactRef::Certificate(certificate),
234 Uses::participant(entry.participant()),
235 work,
236 )
237 .map_err(resource)?;
238 }
239 }
240 Ok(ArtifactUses {
241 inputs,
242 entries: census.entries.into_owned(),
243 targets: census.targets.into_owned(),
244 })
245}
246
247#[cfg(test)]
248mod tests;