1use crate::source::{Query, ScopeError, Snapshot, equal_id};
4use crate::timestamp::{Purpose, Verified};
5use core::marker::PhantomData;
6use structured_asn1::memory::{HashWork, MemoryError, OwnedMap, Work};
7
8pub struct Coverage<N: HashWork, D, G, W: Work, I> {
16 snapshot: Snapshot<D, G>,
17 signature: N,
18 timestamp: N,
19 purpose: Purpose,
20 items: OwnedMap<N, bool, W>,
21 issuer: PhantomData<I>,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum CoverageError<N> {
27 Scope(ScopeError<N>),
29 Resource {
31 node: N,
33 cause: MemoryError,
35 },
36 Foreign {
38 node: N,
40 },
41}
42
43impl<N: Copy + Eq + HashWork, D: Copy + Eq, G: Copy + Eq, W: Work, I> Coverage<N, D, G, W, I> {
44 #[must_use]
51 pub fn new(
52 _issuer: I,
53 snapshot: Snapshot<D, G>,
54 signature: N,
55 timestamp: N,
56 purpose: Purpose,
57 items: OwnedMap<N, bool, W>,
58 ) -> Self {
59 Self {
60 snapshot,
61 signature,
62 timestamp,
63 purpose,
64 items,
65 issuer: PhantomData,
66 }
67 }
68
69 pub fn selects<Q: Query<Id = N, Document = D, Generation = G>>(
72 &self,
73 node: N,
74 query: &Q,
75 ) -> Result<bool, CoverageError<N>> {
76 if self.snapshot != query.snapshot() {
77 return Err(CoverageError::Foreign { node });
78 }
79 query.admit(node, 1).map_err(CoverageError::Scope)?;
80 self.items
81 .get(&node, query.execution())
82 .map(|value| value == Some(&true))
83 .map_err(|cause| CoverageError::Resource { node, cause })
84 }
85
86 pub fn covers<Q: Query<Id = N, Document = D, Generation = G>>(
90 &self,
91 evidence: &Verified<N, D, G, I>,
92 node: N,
93 query: &Q,
94 ) -> Result<bool, CoverageError<N>> {
95 self.require_evidence(evidence, node, query)?;
96 self.selects(node, query)
97 }
98
99 pub fn require_evidence<Q: Query<Id = N, Document = D, Generation = G>>(
101 &self,
102 evidence: &Verified<N, D, G, I>,
103 node: N,
104 query: &Q,
105 ) -> Result<(), CoverageError<N>> {
106 if self.snapshot != query.snapshot() {
107 return Err(CoverageError::Foreign { node });
108 }
109 query.admit(node, 1).map_err(CoverageError::Scope)?;
110 self.require_identity(
111 evidence.token().snapshot,
112 evidence.signature(),
113 evidence.property(),
114 evidence.purpose(),
115 node,
116 query.execution(),
117 )
118 }
119
120 fn require_identity<Q: Work>(
121 &self,
122 snapshot: Snapshot<D, G>,
123 signature: N,
124 timestamp: N,
125 purpose: Purpose,
126 node: N,
127 execution: &Q,
128 ) -> Result<(), CoverageError<N>> {
129 let resource = |cause| CoverageError::Resource { node, cause };
130 if snapshot != self.snapshot
131 || !equal_id(signature, self.signature, execution).map_err(resource)?
132 || !equal_id(timestamp, self.timestamp, execution).map_err(resource)?
133 || purpose != self.purpose
134 {
135 return Err(CoverageError::Foreign { node });
136 }
137 Ok(())
138 }
139}
140
141#[cfg(test)]
142mod tests;