use super::closure::{Key, follow};
use super::{
AuthorityClosureError, AuthorityNode, AuthorityOrigin, Participant, ParticipantAuthority,
ParticipantClosure,
};
use crate::source::{Query, ScopeError};
use structured_asn1::memory::{OwnedMap, OwnedVec, Work};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Uses(u8);
impl Uses {
#[must_use]
pub fn participant<N: Copy>(participant: Participant<N>) -> Self {
match participant {
Participant::Signer(_) | Participant::Counter { .. } => Self(1),
Participant::Credential { .. } => Self(2),
Participant::Timestamp { .. } => Self(4),
}
}
pub fn merge(&mut self, other: Self) {
self.0 |= other.0;
}
#[must_use]
pub fn signature(self) -> bool {
self.0 & 1 != 0
}
#[must_use]
pub fn credential(self) -> bool {
self.0 & 2 != 0
}
#[must_use]
pub fn timestamp(self) -> bool {
self.0 & 4 != 0
}
}
pub struct AuthorityUse<'view, 'certificate, 'document> {
node: &'view AuthorityNode<'view, 'certificate, 'document>,
uses: Uses,
pending: u8,
}
impl<'view, 'certificate, 'document> AuthorityUse<'view, 'certificate, 'document> {
#[must_use]
pub fn node(&self) -> &'view AuthorityNode<'view, 'certificate, 'document> {
self.node
}
#[must_use]
pub fn uses(&self) -> Uses {
self.uses
}
}
pub struct AuthorityUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I> {
inputs: &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>,
entries: OwnedVec<AuthorityUse<'view, 'certificate, 'document>>,
}
impl<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>
AuthorityUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>
{
#[must_use]
pub fn inputs(
&self,
) -> &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>
{
self.inputs
}
#[must_use]
pub fn entries(&self) -> &[AuthorityUse<'view, 'certificate, 'document>] {
&self.entries
}
}
#[derive(Debug)]
pub enum UsesError<N> {
Scope(ScopeError<N>),
Foreign,
Closure(AuthorityClosureError),
}
pub type UsesResult<'closure, 'requirements, 'view, 'certificate, 'document, Q, I> = Result<
AuthorityUses<
'closure,
'requirements,
'view,
'certificate,
'document,
<Q as Query>::Id,
<Q as Query>::Document,
<Q as Query>::Generation,
I,
>,
UsesError<<Q as Query>::Id>,
>;
struct Flow<'view, 'certificate, 'document, W: Work> {
index: OwnedMap<Key<'view, 'document>, usize, W>,
entries: OwnedVec<AuthorityUse<'view, 'certificate, 'document>, W>,
queue: OwnedVec<usize, W>,
}
impl<'view, 'document, W: Work> Flow<'view, '_, 'document, W> {
fn need(
&mut self,
key: Key<'view, 'document>,
uses: u8,
origin: AuthorityOrigin,
work: &W,
) -> Result<(), AuthorityClosureError> {
let index = *self
.index
.get(&key, work)?
.ok_or(AuthorityClosureError::MissingPath { origin })?;
work.charge_work(1)?;
let entry = &mut self.entries[index];
let added = uses & !entry.uses.0;
if added == 0 {
return Ok(());
}
if entry.pending == 0 {
self.queue.try_push(index)?;
}
entry.uses.0 |= added;
entry.pending |= added;
Ok(())
}
}
pub fn authority_uses<'closure, 'requirements, 'view, 'certificate, 'document, Q: Query, I>(
inputs: &'closure ParticipantClosure<
'requirements,
'view,
'certificate,
'document,
Q::Id,
Q::Document,
Q::Generation,
I,
>,
query: &Q,
) -> UsesResult<'closure, 'requirements, 'view, 'certificate, 'document, Q, I> {
let requirements = inputs.requirements();
if requirements.scope().location().snapshot != query.snapshot() {
return Err(UsesError::Foreign);
}
query
.admit(requirements.signature(), 1)
.map_err(UsesError::Scope)?;
derive(inputs, query.execution()).map_err(UsesError::Closure)
}
fn derive<
'closure,
'requirements,
'view,
'certificate,
'document,
N: Copy,
D: Copy,
G: Copy,
W: Work,
I,
>(
inputs: &'closure ParticipantClosure<'requirements, 'view, 'certificate, 'document, N, D, G, I>,
work: &W,
) -> Result<
AuthorityUses<'closure, 'requirements, 'view, 'certificate, 'document, N, D, G, I>,
AuthorityClosureError,
> {
let mut flow = Flow {
index: work.map(),
entries: work.vector(),
queue: work.vector(),
};
let mut responders = work.map();
flow.entries
.try_reserve_exact(inputs.authorities().nodes().len())?;
flow.queue
.try_reserve_exact(inputs.authorities().nodes().len())?;
for (index, node) in inputs.authorities().nodes().iter().enumerate() {
work.charge_work(1)?;
let key = Key {
path: node.statuses.path(),
at: node.statuses.evaluated_at(),
};
if flow.index.try_insert(key, index)?.is_some() {
return Err(AuthorityClosureError::DuplicateNode { index });
}
flow.entries.try_push(AuthorityUse {
node,
uses: Uses(0),
pending: 0,
})?;
for responder in node.responders {
work.charge_work(1)?;
let key = core::ptr::from_ref(responder.target()).addr();
if responders.try_insert(key, *responder)?.is_some() {
return Err(AuthorityClosureError::DuplicateResponder { node: index });
}
}
}
let mut root = 0;
for entry in inputs.requirements().entries() {
work.charge_work(1)?;
let ParticipantAuthority::Path(_) = entry.authority() else {
continue;
};
let statuses = inputs.authorities().roots()[root];
let uses = Uses::participant(entry.participant()).0;
flow.need(
Key {
path: statuses.path(),
at: statuses.evaluated_at(),
},
uses,
AuthorityOrigin::Root { index: root },
work,
)?;
root += 1;
}
debug_assert_eq!(root, inputs.authorities().roots().len());
while !flow.queue.is_empty() {
work.charge_work(1)?;
let index = flow.queue.pop().expect("nonempty queue");
let node = flow.entries[index].node;
let added = flow.entries[index].pending;
flow.entries[index].pending = 0;
follow(
node.statuses,
index,
&responders,
&mut |path, at, origin, work| flow.need(Key { path, at }, added, origin, work),
work,
)?;
}
Ok(AuthorityUses {
inputs,
entries: flow.entries.into_owned(),
})
}