use crate::binding::{self, Bound, SignatureXml};
use crate::container::DS;
use crate::timestamp::{self, InputError};
use crate::xml::{Access, AccessError, Name, Snapshot, Xml};
use structured_asn1::memory::Work;
mod walk;
pub use walk::{WalkError, WalkResult, walk};
#[derive(Debug)]
pub enum Error<E, N> {
Input(InputError<E, N>),
Binding(binding::BindingError<E, N>),
}
#[derive(Debug, Clone, Copy)]
pub struct Counter<N, D, G> {
snapshot: Snapshot<D, G>,
parent: N,
value: N,
node: N,
child: N,
}
impl<N: Copy, D: Copy, G: Copy> Counter<N, D, G> {
#[must_use]
pub fn snapshot(&self) -> Snapshot<D, G> {
self.snapshot
}
#[must_use]
pub fn parent(&self) -> N {
self.parent
}
#[must_use]
pub fn value(&self) -> N {
self.value
}
#[must_use]
pub fn node(&self) -> N {
self.node
}
#[must_use]
pub fn child(&self) -> N {
self.child
}
}
#[derive(Debug, Clone, Copy)]
pub struct Checked<N, D, G> {
original: Counter<N, D, G>,
reference: N,
ordinal: usize,
}
impl<N: Copy, D: Copy, G: Copy> Checked<N, D, G> {
#[must_use]
pub fn original(&self) -> &Counter<N, D, G> {
&self.original
}
#[must_use]
pub fn reference(&self) -> N {
self.reference
}
#[must_use]
pub fn ordinal(&self) -> usize {
self.ordinal
}
}
pub type Original<X> = Counter<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
pub type CounterResult<T, X> = Result<T, Error<<X as Xml>::Error, <X as Xml>::Id>>;
pub type Binding<X> = Checked<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
pub fn read<X: Xml, W: Work>(
access: &Access<'_, X, W>,
bound: &Bound<X::Id, X::Document, X::Generation>,
node: X::Id,
) -> CounterResult<Original<X>, X> {
let parent = timestamp::unsigned_parent(access, bound, node).map_err(Error::Input)?;
let mut found = false;
for child in access.children(parent) {
let child = child.map_err(|cause| Error::Input(InputError::Child(cause)))?;
if access
.equal_id(child, node)
.map_err(|cause| Error::Input(InputError::Resource { node: child, cause }))?
{
found = true;
break;
}
}
if !found {
return Err(Error::Input(InputError::Foreign { node }));
}
let parent = bound.containers().signature();
let value = timestamp::singleton(access, parent, DS, "SignatureValue").map_err(Error::Input)?;
walk::member(access, parent, value, node)
}
pub fn bind<X: SignatureXml, W: Work>(
child_access: &Access<'_, X, W>,
original: Original<X>,
) -> CounterResult<Binding<X>, X> {
if child_access.snapshot() != original.snapshot {
return Err(Error::Input(InputError::Access(AccessError::Changed {
node: original.child,
})));
}
let (reference, ordinal) = binding::covering_reference(
child_access,
original.child,
binding::Purpose::Counter(original.value),
)
.map_err(Error::Binding)?;
Ok(Checked {
original,
reference,
ordinal,
})
}
fn named<X: Xml, W: Work>(
access: &Access<'_, X, W>,
node: X::Id,
namespace: &str,
local: &str,
) -> CounterResult<bool, X> {
access
.has_name(node, Name { namespace, local })
.map_err(|cause| Error::Input(InputError::Access(cause)))
}