use super::Prepared;
use crate::reference::LexicalSource;
use crate::scalar::{Datatype, ScalarXml, UriXml};
use crate::xml::{Access, AccessError, Xml};
use crate::{commitment, format, identifier, policy, scalar};
use structured_asn1::memory::{MemoryError, Work};
#[derive(Debug)]
pub enum UriError<E, N> {
Access(AccessError<E, N>),
Structure(crate::properties::Error<E, N>),
Identifier(identifier::CheckError<E, N>),
Scalar(scalar::Error<E, N>),
Policy(policy::SyntaxError<E, N>),
}
pub type UriResult<X> = Result<(), UriError<<X as Xml>::Error, <X as Xml>::Id>>;
pub fn check_uris<X: ScalarXml + UriXml, W: Work>(
prepared: &Prepared<X>,
access: &Access<'_, X, W>,
) -> UriResult<X> {
let layout = prepared.bound().containers();
let root = layout.signature();
if layout.snapshot() != access.snapshot() {
return Err(UriError::Access(AccessError::Changed { node: root }));
}
access
.query(root, |_, _, _| Ok(()))
.map_err(UriError::Access)?;
let mut at = 0;
while at < prepared.formats().len() {
admit(access, root)?;
let original = prepared.formats()[at].original();
format::check_encoding(access, original).map_err(UriError::Scalar)?;
scalar::check(
access,
original.node(),
LexicalSource::Attribute(crate::xml::Name {
namespace: "",
local: "ObjectReference",
}),
Datatype::AnyUri,
)
.map_err(UriError::Scalar)?;
if let Some(node) = original.identifier() {
let identifier = identifier::read(access, node).map_err(UriError::Structure)?;
identifier::check(access, &identifier).map_err(UriError::Identifier)?;
}
at += 1;
}
let mut at = 0;
while at < prepared.commitments().len() {
admit(access, root)?;
let original = prepared.commitments()[at].original();
identifier::check(access, original.kind()).map_err(UriError::Identifier)?;
if let commitment::Objects::References(nodes) = original.objects() {
let mut index = 0;
while index < nodes.len() {
admit(access, original.node())?;
scalar::check(
access,
nodes[index],
LexicalSource::SimpleContent,
Datatype::AnyUri,
)
.map_err(UriError::Scalar)?;
index += 1;
}
}
at += 1;
}
if let Some(original) = prepared.policy() {
admit(access, root)?;
if let policy::Declaration::Explicit(explicit) = original.declaration() {
identifier::check(access, &explicit.identifier).map_err(UriError::Identifier)?;
}
policy::check_qualifier_syntax(access, original).map_err(UriError::Policy)?;
}
if let Some(original) = prepared.policy_store() {
admit(access, root)?;
identifier::check(access, original.specification()).map_err(UriError::Identifier)?;
if let policy::StoredDocument::Local(node) = original.document() {
scalar::check(access, node, LexicalSource::SimpleContent, Datatype::AnyUri)
.map_err(UriError::Scalar)?;
}
}
access
.query(root, |_, _, _| Ok(()))
.map_err(UriError::Access)
}
fn admit<X: Xml, W: Work>(access: &Access<'_, X, W>, node: X::Id) -> UriResult<X> {
access
.execution()
.charge_work(1)
.map_err(|cause: MemoryError| UriError::Access(AccessError::Resource { node, cause }))
}