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 token: Option<N>,
20 purpose: Purpose,
21 items: OwnedMap<N, bool, W>,
22 issuer: PhantomData<I>,
23}
24
25#[derive(Clone, Copy)]
26struct Identity<N, D, G> {
27 snapshot: Snapshot<D, G>,
28 signature: N,
29 property: N,
30 token: N,
31 purpose: Purpose,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum CoverageError<N> {
37 Scope(ScopeError<N>),
39 Resource {
41 node: N,
43 cause: MemoryError,
45 },
46 Foreign {
48 node: N,
50 },
51}
52
53impl<N: Copy + Eq + HashWork, D: Copy + Eq, G: Copy + Eq, W: Work, I> Coverage<N, D, G, W, I> {
54 #[must_use]
65 pub fn new(
66 _issuer: I,
67 snapshot: Snapshot<D, G>,
68 signature: N,
69 timestamp: N,
70 purpose: Purpose,
71 items: OwnedMap<N, bool, W>,
72 ) -> Self {
73 Self {
74 snapshot,
75 signature,
76 timestamp,
77 token: None,
78 purpose,
79 items,
80 issuer: PhantomData,
81 }
82 }
83
84 #[must_use]
88 pub fn for_token(
89 issuer: I,
90 snapshot: Snapshot<D, G>,
91 signature: N,
92 property: N,
93 token: N,
94 purpose: Purpose,
95 items: OwnedMap<N, bool, W>,
96 ) -> Self {
97 let mut result = Self::new(issuer, snapshot, signature, property, purpose, items);
98 result.token = Some(token);
99 result
100 }
101
102 #[must_use]
107 pub fn subject(&self) -> N {
108 match self.token {
109 Some(token) => token,
110 None => self.timestamp,
111 }
112 }
113
114 pub fn selects<Q: Query<Id = N, Document = D, Generation = G>>(
117 &self,
118 node: N,
119 query: &Q,
120 ) -> Result<bool, CoverageError<N>> {
121 if self.snapshot != query.snapshot() {
122 return Err(CoverageError::Foreign { node });
123 }
124 query.admit(node, 1).map_err(CoverageError::Scope)?;
125 self.items
126 .get(&node, query.execution())
127 .map(|value| value == Some(&true))
128 .map_err(|cause| CoverageError::Resource { node, cause })
129 }
130
131 pub fn covers<Q: Query<Id = N, Document = D, Generation = G>>(
135 &self,
136 evidence: &Verified<N, D, G, I>,
137 node: N,
138 query: &Q,
139 ) -> Result<bool, CoverageError<N>> {
140 self.require_evidence(evidence, node, query)?;
141 self.selects(node, query)
142 }
143
144 pub fn require_evidence<Q: Query<Id = N, Document = D, Generation = G>>(
146 &self,
147 evidence: &Verified<N, D, G, I>,
148 node: N,
149 query: &Q,
150 ) -> Result<(), CoverageError<N>> {
151 if self.snapshot != query.snapshot() {
152 return Err(CoverageError::Foreign { node });
153 }
154 query.admit(node, 1).map_err(CoverageError::Scope)?;
155 self.require_identity(
156 Identity {
157 snapshot: evidence.token().snapshot,
158 signature: evidence.signature(),
159 property: evidence.property(),
160 token: evidence.token().node,
161 purpose: evidence.purpose(),
162 },
163 node,
164 query.execution(),
165 )
166 }
167
168 fn require_identity<Q: Work>(
169 &self,
170 identity: Identity<N, D, G>,
171 node: N,
172 execution: &Q,
173 ) -> Result<(), CoverageError<N>> {
174 let resource = |cause| CoverageError::Resource { node, cause };
175 if identity.snapshot != self.snapshot
176 || !equal_id(identity.signature, self.signature, execution).map_err(resource)?
177 || !equal_id(identity.property, self.timestamp, execution).map_err(resource)?
178 || identity.purpose != self.purpose
179 {
180 return Err(CoverageError::Foreign { node });
181 }
182 if let Some(token) = self.token
183 && !equal_id(identity.token, token, execution).map_err(resource)?
184 {
185 return Err(CoverageError::Foreign { node });
186 }
187 Ok(())
188 }
189}
190
191#[cfg(test)]
192mod tests;