1use super::closure::{Key, follow};
4use super::{
5 AuthorityClosureError, AuthorityNode, AuthorityOrigin, Participant, ParticipantAuthority,
6 ParticipantClosure,
7};
8use crate::source::{Query, ScopeError};
9use structured_asn1::memory::{OwnedMap, OwnedVec, Work};
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16pub struct Uses(u8);
17
18impl Uses {
19 #[must_use]
21 pub fn participant<N: Copy>(participant: Participant<N>) -> Self {
22 match participant {
23 Participant::Signer(_) | Participant::Counter { .. } => Self(1),
24 Participant::Credential { .. } => Self(2),
25 Participant::Timestamp { .. } => Self(4),
26 }
27 }
28
29 pub fn merge(&mut self, other: Self) {
31 self.0 |= other.0;
32 }
33
34 #[must_use]
36 pub fn signature(self) -> bool {
37 self.0 & 1 != 0
38 }
39 #[must_use]
41 pub fn credential(self) -> bool {
42 self.0 & 2 != 0
43 }
44 #[must_use]
46 pub fn timestamp(self) -> bool {
47 self.0 & 4 != 0
48 }
49}
50
51pub struct AuthorityUse<'view, 'certificate, 'document> {
53 node: &'view AuthorityNode<'view, 'certificate, 'document>,
54 uses: Uses,
55 pending: u8,
56}
57
58impl<'view, 'certificate, 'document> AuthorityUse<'view, 'certificate, 'document> {
59 #[must_use]
61 pub fn node(&self) -> &'view AuthorityNode<'view, 'certificate, 'document> {
62 self.node
63 }
64 #[must_use]
66 pub fn uses(&self) -> Uses {
67 self.uses
68 }
69}
70
71pub struct AuthorityUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I> {
74 inputs: &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>,
75 entries: OwnedVec<AuthorityUse<'view, 'certificate, 'document>>,
76}
77
78impl<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>
79 AuthorityUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>
80{
81 #[must_use]
83 pub fn inputs(
84 &self,
85 ) -> &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>
86 {
87 self.inputs
88 }
89 #[must_use]
91 pub fn entries(&self) -> &[AuthorityUse<'view, 'certificate, 'document>] {
92 &self.entries
93 }
94}
95
96#[derive(Debug)]
98pub enum UsesError<N> {
99 Scope(ScopeError<N>),
101 Foreign,
103 Closure(AuthorityClosureError),
105}
106
107pub type UsesResult<'closure, 'requirements, 'view, 'certificate, 'document, Q, I> = Result<
109 AuthorityUses<
110 'closure,
111 'requirements,
112 'view,
113 'certificate,
114 'document,
115 <Q as Query>::Id,
116 <Q as Query>::Document,
117 <Q as Query>::Generation,
118 I,
119 >,
120 UsesError<<Q as Query>::Id>,
121>;
122
123struct Flow<'view, 'certificate, 'document, W: Work> {
124 index: OwnedMap<Key<'view, 'document>, usize, W>,
125 entries: OwnedVec<AuthorityUse<'view, 'certificate, 'document>, W>,
126 queue: OwnedVec<usize, W>,
127}
128
129impl<'view, 'document, W: Work> Flow<'view, '_, 'document, W> {
130 fn need(
131 &mut self,
132 key: Key<'view, 'document>,
133 uses: u8,
134 origin: AuthorityOrigin,
135 work: &W,
136 ) -> Result<(), AuthorityClosureError> {
137 let index = *self
138 .index
139 .get(&key, work)?
140 .ok_or(AuthorityClosureError::MissingPath { origin })?;
141 work.charge_work(1)?;
142 let entry = &mut self.entries[index];
143 let added = uses & !entry.uses.0;
144 if added == 0 {
145 return Ok(());
146 }
147 if entry.pending == 0 {
148 self.queue.try_push(index)?;
149 }
150 entry.uses.0 |= added;
151 entry.pending |= added;
152 Ok(())
153 }
154}
155
156pub fn authority_uses<'closure, 'requirements, 'view, 'certificate, 'document, Q: Query, I>(
171 inputs: &'closure ParticipantClosure<
172 'requirements,
173 'view,
174 'certificate,
175 'document,
176 Q::Id,
177 Q::Document,
178 Q::Generation,
179 I,
180 >,
181 query: &Q,
182) -> UsesResult<'closure, 'requirements, 'view, 'certificate, 'document, Q, I> {
183 let requirements = inputs.requirements();
184 if requirements.scope().location().snapshot != query.snapshot() {
185 return Err(UsesError::Foreign);
186 }
187 query
188 .admit(requirements.signature(), 1)
189 .map_err(UsesError::Scope)?;
190 derive(inputs, query.execution()).map_err(UsesError::Closure)
191}
192
193fn derive<
194 'closure,
195 'requirements,
196 'view,
197 'certificate,
198 'document,
199 N: Copy,
200 D: Copy,
201 G: Copy,
202 W: Work,
203 I,
204>(
205 inputs: &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>,
206 work: &W,
207) -> Result<
208 AuthorityUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>,
209 AuthorityClosureError,
210> {
211 let mut flow = Flow {
212 index: work.map(),
213 entries: work.vector(),
214 queue: work.vector(),
215 };
216 let mut responders = work.map();
217 flow.entries
218 .try_reserve_exact(inputs.authorities().nodes().len())?;
219 flow.queue
220 .try_reserve_exact(inputs.authorities().nodes().len())?;
221 for (index, node) in inputs.authorities().nodes().iter().enumerate() {
222 work.charge_work(1)?;
223 let key = Key {
224 path: node.statuses.path(),
225 at: node.statuses.evaluated_at(),
226 };
227 if flow.index.try_insert(key, index)?.is_some() {
228 return Err(AuthorityClosureError::DuplicateNode { index });
229 }
230 flow.entries.try_push(AuthorityUse {
231 node,
232 uses: Uses(0),
233 pending: 0,
234 })?;
235 for responder in node.responders {
236 work.charge_work(1)?;
237 let key = core::ptr::from_ref(responder.target()).addr();
238 if responders.try_insert(key, *responder)?.is_some() {
239 return Err(AuthorityClosureError::DuplicateResponder { node: index });
240 }
241 }
242 }
243 let mut root = 0;
244 for entry in inputs.requirements().entries() {
245 work.charge_work(1)?;
246 let ParticipantAuthority::Path(_) = entry.authority() else {
247 continue;
248 };
249 let statuses = inputs.authorities().roots()[root];
250 let uses = Uses::participant(entry.participant()).0;
251 flow.need(
252 Key {
253 path: statuses.path(),
254 at: statuses.evaluated_at(),
255 },
256 uses,
257 AuthorityOrigin::Root { index: root },
258 work,
259 )?;
260 root += 1;
261 }
262 debug_assert_eq!(root, inputs.authorities().roots().len());
263 while !flow.queue.is_empty() {
264 work.charge_work(1)?;
265 let index = flow.queue.pop().expect("nonempty queue");
266 let node = flow.entries[index].node;
267 let added = flow.entries[index].pending;
268 flow.entries[index].pending = 0;
269 follow(
270 node.statuses,
271 index,
272 &responders,
273 &mut |path, at, origin, work| flow.need(Key { path, at }, added, origin, work),
274 work,
275 )?;
276 }
277 Ok(AuthorityUses {
278 inputs,
279 entries: flow.entries.into_owned(),
280 })
281}