Skip to main content

structured_asic/xml/producer/
signed.rs

1//! Owning signature production and actual original-member resource receipts.
2
3use super::{Error, Source, Types};
4use crate::{
5    content::Content,
6    error::{Error as ArchiveError, resource},
7    uri::{self, Part},
8    zip::{Archive, Member, MemberId, ReadFailure},
9};
10use core::future::Future;
11use structured_asn1::{
12    memory::{MemoryError, OwnedVec, Work},
13    range::RangeSource,
14};
15use structured_xades::{
16    attributes::AttributeXml,
17    binary::OwnedBinaryXml,
18    binding::{Coverage, Status},
19    reference::{Completeness, Descriptor, Parent, ReferenceXml, VisitError},
20    scalar::{ScalarXml, UriXml},
21    xml::{Access, AccessError, Snapshot, Xml},
22};
23
24/// Closed receipt for one actual complete original CRC-checked input.
25/// This attests acquisition, not that an XML reference consumed these bytes.
26/// The trusted XML owner must establish that latter association from its actual
27/// verified operation, not by comparing a filename or attaching an arbitrary ID.
28pub struct Resource<'v, 's, S: RangeSource> {
29    member: Member<'v, 's, S>,
30}
31impl<S: RangeSource> Resource<'_, '_, S> {
32    /// Exact original input occurrence, independently of URI spelling.
33    #[must_use]
34    pub fn member(&self) -> MemberId<S::Document, S::Generation> {
35        self.member.id()
36    }
37}
38
39/// Complete funded input and its closed original-source receipt.
40pub struct Loaded<'v, 's, S: RangeSource> {
41    content: Content<'v, 's, S>,
42}
43impl<'v, 's, S: RangeSource> Loaded<'v, 's, S> {
44    /// Transfers the same allocation to the XML owner, without a copy or new
45    /// capacity charge. Keep the receipt with the actual parsing/verification
46    /// state that consumes it; it is not a replay or signature capability.
47    pub fn into_parts(self) -> (OwnedVec<u8>, Resource<'v, 's, S>) {
48        let (member, bytes) = self.content.into_parts();
49        (bytes, Resource { member })
50    }
51}
52
53/// Exact resource lookup preserves negative/ambiguous inputs without selection.
54pub enum Lookup<'v, 's, S: RangeSource> {
55    /// One actual complete original input was acquired.
56    Loaded(Loaded<'v, 's, S>),
57    /// URI selects the containing XML, not another member.
58    SameDocument(Part),
59    /// Query/fragment selects less than the complete member.
60    Part(Part),
61    /// A package root is not a file resource.
62    Root,
63    /// No exact original member has this name.
64    Missing,
65    /// Several original members have exactly this name.
66    Ambiguous,
67    /// Completed lexical/package interpretation failed.
68    Negative(uri::Negative),
69}
70
71/// The core's original archive resource boundary. It is passed to the owning
72/// XML producer, never assembled from separately parsed snapshots. XML Base,
73/// transforms and selected policy remain with that XML owner.
74pub struct Resources<'v, 's, S: RangeSource> {
75    archive: &'v Archive<'s, S>,
76    base: MemberId<S::Document, S::Generation>,
77}
78impl<'v, 's, S: RangeSource> Resources<'v, 's, S> {
79    /// Actual original signature file whose input was moved to this producer.
80    #[must_use]
81    pub fn base(&self) -> MemberId<S::Document, S::Generation> {
82        self.base
83    }
84    /// Resolves an XML-owner selected lexical reference against its ACTUAL
85    /// original containing member, then transfers complete EOF/CRC-checked
86    /// bytes. The caller's current Work is narrowed by the producing session.
87    ///
88    /// # Panics
89    /// An internal immutable name-catalogue invariant fails if its unique
90    /// original candidate cannot be selected from that same catalogue.
91    pub async fn load<W: Work>(
92        &self,
93        base: MemberId<S::Document, S::Generation>,
94        uri: &str,
95        work: &W,
96    ) -> Result<Lookup<'v, 's, S>, ReadFailure<S::Error, S::Document, S::Generation>> {
97        let execution = self.archive.session().query(work);
98        let fail = |cause| ReadFailure::Processing {
99            member: base,
100            cause,
101        };
102        let base = self.archive.original(base, &execution).map_err(fail)?;
103        let target = uri::resolve(base.name(), uri, &execution)
104            .map_err(|cause| fail(resource(base.central_span(), cause)))?;
105        let names = match target {
106            uri::Target::Negative(cause) => return Ok(Lookup::Negative(cause)),
107            uri::Target::SameDocument(part) => return Ok(Lookup::SameDocument(part)),
108            uri::Target::Root(_) => return Ok(Lookup::Root),
109            uri::Target::Member {
110                name,
111                part: Part::Whole,
112            } => self.archive.find(name.as_ref(), &execution).map_err(fail)?,
113            uri::Target::Member { part, .. } => return Ok(Lookup::Part(part)),
114        };
115        if names.is_empty() {
116            return Ok(Lookup::Missing);
117        }
118        if names.len() != 1 {
119            return Ok(Lookup::Ambiguous);
120        }
121        let member = names
122            .member(0, &execution)
123            .map_err(fail)?
124            .expect("one exact original candidate");
125        let content = member.content(&execution).await?;
126        Ok(Lookup::Loaded(Loaded { content }))
127    }
128}
129
130/// One actual verified direct or signed-Manifest instruction. Missing inputs
131/// remain None, independently of catalogue completeness and reference status.
132pub struct MemberReference<'a, 'v, 's, N, S: RangeSource> {
133    /// Actual original verified instruction and its authenticated parent.
134    pub descriptor: Descriptor<'a, N>,
135    /// Actual input consumed by that operation, not a URI-to-ID assertion.
136    pub resource: Option<&'a Resource<'v, 's, S>>,
137}
138
139/// Extends the XML owner's existing verified reference catalogue with the
140/// actual resources it consumed. Include every original detached instruction,
141/// failed and missing inputs, and authenticated Manifest parents. Complete
142/// means the complete catalogue, never just successfully acquired inputs.
143pub trait MemberReferences<'v, 's, S: RangeSource>: ReferenceXml {
144    /// Visits the existing operation, without reparsing or reverification.
145    fn visit_member_references<VE, W: Work>(
146        &self,
147        snapshot: Snapshot<Self::Document, Self::Generation>,
148        signature: Self::Id,
149        work: &W,
150        visitor: impl for<'a> FnMut(MemberReference<'a, 'v, 's, Self::Id, S>) -> Result<(), VE>,
151    ) -> Result<Completeness<Self::Id>, VisitError<Self::Error, VE>>;
152}
153
154/// Owning XML verification state. Its immutable view borrows this actual state
155/// through the entire asynchronous visitor; no self-reference is required.
156pub trait SignatureParsed<'v, 's, S: RangeSource>: Types {
157    /// One actual document and verified-operation view, including all negatives.
158    type View<'a>: Xml<
159            Id = Self::Id,
160            Document = Self::Document,
161            Generation = Self::Generation,
162            Error = Self::Error,
163        > + ScalarXml
164        + AttributeXml
165        + UriXml
166        + OwnedBinaryXml
167        + MemberReferences<'v, 's, S>
168    where
169        Self: 'a;
170    /// Borrows existing state without parse, verify, clone or source acquisition.
171    fn view(&self) -> Self::View<'_>;
172    /// Actual whole-document root, never a detached Signature subtree.
173    fn root(&self) -> Self::Id;
174}
175
176/// Separate capability from structural manifest parsing. A synchronous scoped
177/// `VerifiedSession` adapter alone cannot implement this owning async contract.
178pub trait SignatureFactory<'v, 's, S: RangeSource>: Types {
179    /// Owns the funded input, AST, request, budgets and verification evidence.
180    type Parsed<'a, W: Work + 'a>: SignatureParsed<
181            'v,
182            's,
183            S,
184            Id = Self::Id,
185            Document = Self::Document,
186            Generation = Self::Generation,
187            Error = Self::Error,
188        >
189    where
190        Self: 'a,
191        'v: 'a,
192        's: 'a,
193        's: 'v,
194        S: 's + 'v + 'a;
195    /// Produces one owning state from exactly these complete original bytes.
196    /// All allocations/callbacks retain current and producing admission, and
197    /// all original policy, verification and resource causes remain typed.
198    fn parse_signed<'a, W: Work + 'a>(
199        &'a self,
200        input: OwnedVec<u8>,
201        resources: &'a Resources<'v, 's, S>,
202        work: &'a W,
203    ) -> impl Future<Output = Result<Self::Parsed<'a, W>, Self::Error>> + 'a
204    where
205        'v: 'a,
206        's: 'a,
207        's: 'v,
208        S: 's + 'v + 'a;
209}
210
211/// Fixed-output async continuation, independent of temporary document lifetimes.
212pub trait SignatureVisitor<'v, 's, F: Types + ?Sized, S: RangeSource> {
213    /// Independently retained output, not a borrow of the temporary view/state.
214    type Output;
215    /// Original visitor cause, including its resource/processing classification.
216    type Error;
217    /// Runs with the actual owning verification state alive through await.
218    fn visit<X, W: Work>(
219        self,
220        source: Source<'_, 'v, 's, X, S, W>,
221    ) -> impl Future<Output = Result<Self::Output, Self::Error>>
222    where
223        X: Xml<Id = F::Id, Document = F::Document, Generation = F::Generation, Error = F::Error>
224            + ScalarXml
225            + AttributeXml
226            + UriXml
227            + OwnedBinaryXml
228            + MemberReferences<'v, 's, S>;
229}
230
231impl<'v, 's, S: RangeSource> Content<'v, 's, S> {
232    /// Moves the actual complete original member into owning XML verification,
233    /// then keeps its view/state/source/current operation alive through await.
234    /// No separately parsed snapshot can be attached to this source receipt.
235    pub async fn with_signed_xml<
236        F: SignatureFactory<'v, 's, S>,
237        V: SignatureVisitor<'v, 's, F, S>,
238        W: Work,
239    >(
240        self,
241        factory: &F,
242        visitor: V,
243        work: &W,
244    ) -> Result<
245        V::Output,
246        Error<
247            ReadFailure<S::Error, S::Document, S::Generation>,
248            F::Error,
249            V::Error,
250            AccessError<F::Error, F::Id>,
251        >,
252    > {
253        let archive = self.member().archive();
254        let execution = archive.session().query(work);
255        let (member, input) = self.into_parts();
256        let failure = |cause| {
257            Error::Input(ReadFailure::Processing {
258                member: member.id(),
259                cause,
260            })
261        };
262        archive
263            .admit(&execution, member.central_span())
264            .map_err(failure)?;
265        let resources = Resources {
266            archive,
267            base: member.id(),
268        };
269        let document = factory
270            .parse_signed(input, &resources, &execution)
271            .await
272            .map_err(Error::Produce)?;
273        let root = document.root();
274        let xml = document.view();
275        let snapshot = xml.snapshot();
276        let access = Access::new(&xml, snapshot, &execution);
277        access.inspect(root, |_| ()).map_err(Error::Xml)?;
278        archive
279            .admit(&execution, member.central_span())
280            .map_err(failure)?;
281        let result = visitor
282            .visit(Source {
283                member: &member,
284                xml: &xml,
285                root,
286                snapshot,
287                execution: &execution,
288            })
289            .await
290            .map_err(Error::Visit)?;
291        access.inspect(root, |_| ()).map_err(Error::Xml)?;
292        archive
293            .admit(&execution, member.central_span())
294            .map_err(failure)?;
295        Ok(result)
296    }
297}
298impl<'v, 's, S: RangeSource> Member<'v, 's, S> {
299    /// Complete EOF/CRC acquisition followed by the same owning signature path.
300    pub async fn with_signed_xml<
301        F: SignatureFactory<'v, 's, S>,
302        V: SignatureVisitor<'v, 's, F, S>,
303        W: Work,
304    >(
305        &self,
306        factory: &F,
307        visitor: V,
308        work: &W,
309    ) -> Result<
310        V::Output,
311        Error<
312            ReadFailure<S::Error, S::Document, S::Generation>,
313            F::Error,
314            V::Error,
315            AccessError<F::Error, F::Id>,
316        >,
317    > {
318        self.content(work)
319            .await
320            .map_err(Error::Input)?
321            .with_signed_xml(factory, visitor, work)
322            .await
323    }
324}
325
326/// Every original reference, independently of its digest/coverage outcome.
327#[derive(Debug, Clone, Copy)]
328pub struct Reference<N, D, G> {
329    /// Original reference node, never its selected resource.
330    pub node: N,
331    /// Original signed instruction parent, retaining Manifest identity.
332    pub parent: Parent<N>,
333    /// Actual complete original resource, absent for missing/non-member input.
334    pub input: Option<MemberId<D, G>>,
335    /// Actual completed/failed/unchecked reference digest status.
336    pub status: Status,
337    /// Actual transform engine's original-element coverage.
338    pub coverage: Coverage,
339    /// Actual source kind observed by the original reference operation.
340    pub object_location: structured_xades::reference::ObjectLocation,
341}
342/// All original signature occurrences, including unverified/misplaced nodes.
343pub struct Signature<N, D, G> {
344    /// Original wrapper/nesting location, not an assertion of legal countersignature.
345    pub occurrence: crate::xml::Signature<N>,
346    /// Actual signature mathematics, independently of trust or `XAdES` level.
347    pub status: Status,
348    /// Original complete/unchecked/incomplete instruction catalogue.
349    pub completeness: Completeness<N>,
350    /// Every original reference returned by that catalogue, in original order.
351    pub references: OwnedVec<Reference<N, D, G>>,
352}
353/// Source-produced wrapper, signature and external-member facts.
354pub struct Facts<'v, 's, N, D, G, S: RangeSource> {
355    member: Member<'v, 's, S>,
356    reading: crate::xml::Reading<N, D, G>,
357    signatures: OwnedVec<Signature<N, S::Document, S::Generation>>,
358}
359
360/// One actual common `XAdES` stage composition, privately associated with this
361/// source-produced original signature. Trust and container facts stay separate.
362pub struct Assessment<'a, A, N, D, G, SD, SG> {
363    member: MemberId<SD, SG>,
364    snapshot: Snapshot<D, G>,
365    signature: N,
366    inner: structured_xades::baseline::Assessment<'a, A, N, D, G>,
367}
368impl<A, N: Copy, D: Copy, G: Copy, SD: Copy, SG: Copy> Assessment<'_, A, N, D, G, SD, SG> {
369    /// Exact actual signature-file occurrence.
370    #[must_use]
371    pub fn member(&self) -> MemberId<SD, SG> {
372        self.member
373    }
374    /// Exact original selected XML signature.
375    #[must_use]
376    pub fn signature(&self) -> N {
377        self.signature
378    }
379    /// Complete original common stage reports, including negative outcomes.
380    #[must_use]
381    pub fn xades(&self) -> &structured_xades::baseline::Assessment<'_, A, N, D, G> {
382        &self.inner
383    }
384}
385/// No new format or trust decision is invented by this source join.
386#[derive(Debug)]
387pub enum LevelError<E, N, SE> {
388    /// Original XML generation/current operation refused.
389    Xml(AccessError<E, N>),
390    /// Another actual source/signature supplied the stage evidence.
391    Foreign,
392    /// Original source/current operation refused.
393    Archive(ArchiveError<SE>),
394    /// Existing common stage composition refused substituted/mismatched reports.
395    Xades(structured_xades::baseline::LevelError),
396}
397/// Common stage composition for the actual XML and member identity domains.
398pub type AssessmentResult<'a, A, X, S> = Result<
399    Assessment<
400        'a,
401        A,
402        <X as Xml>::Id,
403        <X as Xml>::Document,
404        <X as Xml>::Generation,
405        <S as RangeSource>::Document,
406        <S as RangeSource>::Generation,
407    >,
408    LevelError<<X as Xml>::Error, <X as Xml>::Id, <S as RangeSource>::Error>,
409>;
410/// One original census slot, including an absent stage assessment.
411pub type LevelAnswer<'r, 'a, A, N, D, G, SD, SG> = Option<&'r Assessment<'a, A, N, D, G, SD, SG>>;
412/// Source-produced complete signature census or its original terminal cause.
413pub type InspectionResult<'v, 's, X, S> = Result<
414    Facts<'v, 's, <X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation, S>,
415    InspectError<<X as Xml>::Error, <X as Xml>::Id, <S as RangeSource>::Error>,
416>;
417/// A stage assessment in one actual member's identity domain.
418pub type MemberAssessment<'a, A, N, D, G, S> =
419    Assessment<'a, A, N, D, G, <S as RangeSource>::Document, <S as RangeSource>::Generation>;
420/// Full original census join, including absent and negative stage answers.
421pub type LevelsResult<'r, 'a, A, N, D, G, S> = Result<
422    Levels<'r, 'a, A, N, D, G, <S as RangeSource>::Document, <S as RangeSource>::Generation>,
423    JoinError<<S as RangeSource>::Error>,
424>;
425
426impl<'v, 's, X, S, W> Source<'_, 'v, 's, X, S, W>
427where
428    X: MemberReferences<'v, 's, S>,
429    S: RangeSource,
430    W: Work,
431{
432    /// Reuses the complete B-B/B-T/B-LT/B-LTA composition for this ACTUAL XML
433    /// source. Every nested counter/TSA/material obligation remains in those
434    /// existing stage reports, not replaced by a container-wide success flag.
435    pub fn assess<'a, A>(
436        &self,
437        evidence: structured_xades::baseline::Evidence<'a, A, X::Id, X::Document, X::Generation>,
438    ) -> AssessmentResult<'a, A, X, S> {
439        use structured_xades::baseline::Evidence;
440        let prepared = match &evidence {
441            Evidence::Basic(value) => value.inputs().fields.prepared(),
442            Evidence::Timestamped(value) => value.basic().inputs().fields.prepared(),
443            Evidence::LongTerm(value)
444            | Evidence::Archival {
445                long_term: value, ..
446            } => value.timed().basic().inputs().fields.prepared(),
447        };
448        let containers = prepared.bound().containers();
449        if containers.snapshot() != self.snapshot {
450            return Err(LevelError::Foreign);
451        }
452        let signature = containers.signature();
453        let access = Access::new(self.xml, self.snapshot, self.execution);
454        if !access
455            .has_name(
456                signature,
457                structured_xades::xml::Name {
458                    namespace: crate::manifest::DS,
459                    local: "Signature",
460                },
461            )
462            .map_err(LevelError::Xml)?
463        {
464            return Err(LevelError::Foreign);
465        }
466        self.member
467            .archive()
468            .admit(self.execution, self.member.central_span())
469            .map_err(LevelError::Archive)?;
470        let inner = structured_xades::baseline::assess(evidence).map_err(LevelError::Xades)?;
471        Ok(Assessment {
472            member: self.member.id(),
473            snapshot: self.snapshot,
474            signature,
475            inner,
476        })
477    }
478}
479
480/// Every original root's requested-level projection, including unchecked roots.
481pub struct Levels<'r, 'a, A, N, D, G, SD, SG> {
482    answers: OwnedVec<LevelAnswer<'r, 'a, A, N, D, G, SD, SG>>,
483    all_roots: bool,
484}
485impl<'r, 'a, A, N, D, G, SD, SG> Levels<'r, 'a, A, N, D, G, SD, SG> {
486    /// Same ordinal as the complete original signature census, including nested
487    /// and malformed occurrences. None is unexecuted, never a positive level.
488    #[must_use]
489    pub fn answers(&self) -> &[LevelAnswer<'r, 'a, A, N, D, G, SD, SG>] {
490        &self.answers
491    }
492    /// All original direct roots have a completed positive requested-level
493    /// report. This is not wrapper conformance, historical trust or acceptance.
494    #[must_use]
495    pub fn all_roots_requested_level_met(&self) -> bool {
496        self.all_roots
497    }
498}
499/// Invalid caller joins are processing errors rather than readable missing data.
500#[derive(Debug)]
501pub enum JoinError<E> {
502    /// Original source/current operation refused.
503    Archive(ArchiveError<E>),
504    /// A receipt belongs to another source, generation or original signature.
505    Foreign,
506    /// Several supplied receipts select the same original signature.
507    Duplicate,
508}
509impl<N: Copy + Eq + structured_asn1::memory::HashWork, D: Copy + Eq, G: Copy + Eq, S: RangeSource>
510    Facts<'_, '_, N, D, G, S>
511{
512    /// Joins all actual supplied stage receipts with the FULL original census.
513    /// A missing or failed root cannot disappear through success filtering.
514    pub fn levels<'r, 'a, A, W: Work>(
515        &self,
516        supplied: &[&'r MemberAssessment<'a, A, N, D, G, S>],
517        work: &W,
518    ) -> LevelsResult<'r, 'a, A, N, D, G, S> {
519        let archive = self.member.archive();
520        let execution = archive.session().query(work);
521        archive
522            .admit(&execution, self.member.central_span())
523            .map_err(JoinError::Archive)?;
524        let refusal = |cause| JoinError::Archive(resource(self.member.central_span(), cause));
525        let mut originals = execution.map();
526        for (index, signature) in self.signatures.iter().enumerate() {
527            originals
528                .try_insert(signature.occurrence.node, index)
529                .map_err(refusal)?;
530        }
531        let mut selected = execution.map();
532        for (index, value) in supplied.iter().enumerate() {
533            execution.charge_work(1).map_err(refusal)?;
534            if value.member != self.member.id()
535                || value.snapshot != self.reading.snapshot()
536                || originals
537                    .get(&value.signature, &execution)
538                    .map_err(refusal)?
539                    .is_none()
540            {
541                return Err(JoinError::Foreign);
542            }
543            if selected
544                .try_insert(value.signature, index)
545                .map_err(refusal)?
546                .is_some()
547            {
548                return Err(JoinError::Duplicate);
549            }
550        }
551        let mut answers = execution.vector();
552        answers
553            .try_reserve_exact(self.signatures.len())
554            .map_err(refusal)?;
555        let mut roots = 0usize;
556        let mut all_roots = true;
557        for signature in &self.signatures {
558            let answer = selected
559                .get(&signature.occurrence.node, &execution)
560                .map_err(refusal)?
561                .map(|index| supplied[*index]);
562            if signature.occurrence.direct {
563                roots += 1;
564                match answer {
565                    Some(value) if value.inner.all_requirements_met() => {}
566                    _ => all_roots = false,
567                }
568            }
569            answers.try_push(answer).map_err(refusal)?;
570        }
571        archive
572            .admit(&execution, self.member.central_span())
573            .map_err(JoinError::Archive)?;
574        Ok(Levels {
575            answers: answers.into_owned(),
576            all_roots: roots != 0 && all_roots,
577        })
578    }
579}
580impl<'v, 's, N: Copy, D: Copy, G: Copy, S: RangeSource> Facts<'v, 's, N, D, G, S> {
581    /// Actual signature member, established by the closed producing operation.
582    #[must_use]
583    pub fn member(&self) -> &Member<'v, 's, S> {
584        &self.member
585    }
586    /// Full wrapper and descendant census, preserving original faults.
587    #[must_use]
588    pub fn reading(&self) -> &crate::xml::Reading<N, D, G> {
589        &self.reading
590    }
591    /// All original mathematical/reference outcomes, without successful subsets.
592    #[must_use]
593    pub fn signatures(&self) -> &[Signature<N, S::Document, S::Generation>] {
594        &self.signatures
595    }
596}
597/// Original owner/processing/refusal causes do not become format negatives.
598#[derive(Debug)]
599pub enum InspectError<E, N, SE> {
600    /// Actual original wrapper inspection or source/current storage refused.
601    Wrapper(crate::xml::Error<E, N>),
602    /// Actual verified operation or generation refused.
603    Xml(AccessError<E, N>),
604    /// Actual reference catalogue refused, preserving the visitor cause.
605    References(VisitError<E, ReferenceError<SE>>),
606    /// Original source/current operation refused.
607    Archive(ArchiveError<SE>),
608}
609/// Reference association failures are terminal, never missing inputs.
610#[derive(Debug)]
611pub enum ReferenceError<E> {
612    /// Original source/query refused.
613    Archive(ArchiveError<E>),
614    /// Resource belongs to another actual producing archive/session.
615    Foreign,
616    /// Current/source descriptor storage refused before retention.
617    Resource(MemoryError),
618}
619impl<'v, 's, X, S, W> Source<'_, 'v, 's, X, S, W>
620where
621    X: AttributeXml + MemberReferences<'v, 's, S>,
622    S: RangeSource,
623    W: Work,
624{
625    /// Retains every original signature and its actual complete reference
626    /// catalogue while the producing verification state is still alive.
627    pub fn signatures(&self) -> InspectionResult<'v, 's, X, S> {
628        let access = Access::new(self.xml, self.snapshot, self.execution);
629        let reading = crate::xml::inspect(self.xml, self.root, self.execution)
630            .map_err(InspectError::Wrapper)?;
631        let mut signatures = self.execution.vector();
632        for occurrence in reading.signatures() {
633            access
634                .inspect(occurrence.node, |_| ())
635                .map_err(InspectError::Xml)?;
636            let status = self
637                .xml
638                .signature_status(self.snapshot, occurrence.node, self.execution)
639                .map_err(|cause| InspectError::Xml(AccessError::Xml(cause)))?;
640            let mut references = self.execution.vector();
641            let completeness = self
642                .xml
643                .visit_member_references(self.snapshot, occurrence.node, self.execution, |item| {
644                    let input = if let Some(resource) = item.resource {
645                        self.execution
646                            .charge_work(1)
647                            .map_err(ReferenceError::Resource)?;
648                        if !core::ptr::eq(resource.member.archive(), self.member.archive()) {
649                            return Err(ReferenceError::Foreign);
650                        }
651                        self.member
652                            .archive()
653                            .original(resource.member(), self.execution)
654                            .map_err(ReferenceError::Archive)?;
655                        Some(resource.member())
656                    } else {
657                        None
658                    };
659                    references
660                        .try_push(Reference {
661                            node: item.descriptor.reference.node,
662                            parent: item.descriptor.parent,
663                            input,
664                            status: item.descriptor.reference.status,
665                            coverage: item.descriptor.reference.coverage,
666                            object_location: item.descriptor.object_location,
667                        })
668                        .map_err(ReferenceError::Resource)
669                })
670                .map_err(InspectError::References)?;
671            access
672                .inspect(occurrence.node, |_| ())
673                .map_err(InspectError::Xml)?;
674            signatures
675                .try_push(Signature {
676                    occurrence: *occurrence,
677                    status,
678                    completeness,
679                    references: references.into_owned(),
680                })
681                .map_err(|cause| {
682                    InspectError::Wrapper(crate::xml::Error::Resource {
683                        node: occurrence.node,
684                        cause,
685                    })
686                })?;
687        }
688        let member = self
689            .member
690            .archive()
691            .original(self.member.id(), self.execution)
692            .map_err(InspectError::Archive)?;
693        access
694            .inspect(self.root, |_| ())
695            .map_err(InspectError::Xml)?;
696        Ok(Facts {
697            member,
698            reading,
699            signatures: signatures.into_owned(),
700        })
701    }
702}