Skip to main content

structured_pades/timestamp/
coverage.rs

1//! Exact checked PDF input coverage of the complete original material index.
2
3use super::{ISSUER, Node, Pades, Requirements};
4use crate::{
5    material::{Placement, Unified},
6    query::Query,
7    range::RangeSource,
8};
9use structured_asn1::memory::{Execution, Work};
10use structured_ltv::{
11    material::{Coverage, CoverageError, IndexError},
12    source::Query as _,
13    timestamp::CheckedActor,
14};
15
16/// Original source/current admission versus an inconsistent material scope.
17#[derive(Debug)]
18pub enum Error {
19    /// Wrong source, root, token or input selection.
20    Pdf(crate::Error),
21    /// Original exact material-index refusal.
22    Index(IndexError<Node>),
23    /// Original coverage/current source refusal.
24    Coverage(CoverageError<Node>),
25}
26
27impl<D: Copy + Eq, G: Copy + Eq> Requirements<'_, '_, D, G> {
28    /// Builds coverage from the actual checked whole-revision input. Every
29    /// historical occurrence is visited, including late copies and the DTS's
30    /// excluded own token. No successful subset or caller mask is accepted.
31    pub fn material_coverage<'q, S: RangeSource<Document = D, Generation = G>>(
32        &self,
33        ordinal: usize,
34        actor: &CheckedActor<'_, '_, Node, D, G, Pades>,
35        material: &Unified<'_, '_, D, G>,
36        query: &Query<'q, '_, S>,
37    ) -> Result<Coverage<Node, D, G, Execution<'q>, Pades>, Error> {
38        let root = self.all().signature();
39        if !query.belongs(self.root.owner().value.session)
40            || !query.belongs(material.session)
41            || query.snapshot() != self.root.owner().value.stamp.snapshot
42            || !core::ptr::eq(material.required, self.all())
43        {
44            return Err(Error::Coverage(CoverageError::Foreign { node: root }));
45        }
46        let signature = self
47            .archive(ordinal, actor, query.execution())
48            .map_err(Error::Pdf)?;
49        let index = &material.index;
50        index.require_signature(root, query).map_err(Error::Index)?;
51        let mut items = query.execution().map();
52        for original in index.all_occurrences(query).map_err(Error::Index)? {
53            let original = original.map_err(Error::Index)?;
54            let node = original.location().node;
55            let covered = super::requirements::covers_node(signature, node, query.execution())
56                .map_err(Error::Pdf)?;
57            // Placement is source metadata; it must agree with its sealed
58            // historical node even if two windows reference the same body.
59            match original.placement() {
60                Placement::Dss { revision, .. } | Placement::VriTimestamp { revision, .. }
61                    if node.material_revision() != Some(revision) =>
62                {
63                    return Err(Error::Coverage(CoverageError::Foreign { node }));
64                }
65                _ => {}
66            }
67            items
68                .try_insert(node, covered)
69                .map_err(|cause| Error::Coverage(CoverageError::Resource { node, cause }))?;
70        }
71        let proof = actor.verified();
72        Ok(Coverage::for_token(
73            ISSUER,
74            query.snapshot(),
75            root,
76            proof.property(),
77            proof.token().node,
78            proof.purpose(),
79            items,
80        ))
81    }
82}