use crate::operation::{
OperationExecutionContext, OperationNodeId, OperationNodeKind, OperationPlanError,
OperationStage,
};
pub struct Projection<'a>(crate::xml::dom::benchmark::Projection<'a>);
impl<'a> Projection<'a> {
pub fn new(
input: &'a str,
backend: crate::XmlBackend,
) -> Result<Self, crate::xml::dom::ParseError> {
Ok(Self(crate::xml::dom::benchmark::Projection::new(
input, backend,
)?))
}
pub fn project(&self) -> Result<crate::xml::dom::Document<'a>, crate::xml::dom::ParseError> {
self.0.project()
}
}
pub struct NodeSets<'a> {
document: crate::xml::dom::Document<'a>,
}
impl<'a> NodeSets<'a> {
pub fn new(input: &'a str) -> Result<Self, crate::xml::dom::ParseError> {
Ok(Self {
document: crate::xml::dom::Document::parse(input)?,
})
}
pub fn enveloped(&self) -> usize {
let mut nodes = crate::xmldsig::NodeSet::entire_document_without_comments(&self.document)
.expect("benchmark document fits node-set limits");
let signature = self
.document
.root_element()
.last_element_child()
.expect("benchmark document has an enveloped child");
nodes.exclude_subtree(signature);
self.canonicalize(&nodes)
}
pub fn selection(&self, stride: usize, dense: bool) -> usize {
use crate::xmldsig::types::projection::{NativeKeys, Projection};
let budget = crate::xmldsig::types::NodeSetMaterializationBudget::default();
let mut nodes = Projection::empty(&self.document, NativeKeys);
nodes
.pin_representation(dense)
.expect("native storage is infallible");
for element in self
.document
.descendants()
.filter(|node| node.is_element())
.step_by(stride)
{
nodes
.insert_tree(element, Some(&budget))
.expect("selection fits");
for ordinal in 0..element.attributes().len() {
nodes
.insert_attribute_at(element, ordinal, &budget)
.expect("selection fits");
}
for ordinal in 0..element.namespaces().len() {
nodes
.insert_namespace_at(element, ordinal, &budget)
.expect("selection fits");
}
}
self.canonicalize(&nodes)
}
fn canonicalize(&self, nodes: &dyn crate::c14n::NodeVisibility) -> usize {
let algorithm = crate::c14n::C14nAlgorithm::new(crate::c14n::C14nMode::Inclusive1_0, false);
let mut output = Vec::new();
crate::c14n::canonicalize_with_visibility(
&self.document,
Some(nodes),
&algorithm,
&mut output,
)
.expect("benchmark canonicalization");
output.len()
}
}
pub struct Plan {
context: OperationExecutionContext<(), ()>,
order: Vec<OperationNodeId>,
}
impl Plan {
pub fn new(references: usize) -> Self {
assert!((1..=64).contains(&references), "bounded benchmark graph");
let mut context = OperationExecutionContext::new((), (), None);
let root = context.add_node(OperationNodeKind::Document, OperationStage::Parse, None);
let mut order = vec![root];
for index in 0..references {
let node = context.add_node(
OperationNodeKind::Digest { index },
OperationStage::Digest,
None,
);
context
.add_dependency(node, root)
.expect("forward dependency");
order.push(node);
}
let crypto = context.add_node(OperationNodeKind::Crypto, OperationStage::Crypto, None);
for &node in &order[1..] {
context
.add_dependency(crypto, node)
.expect("forward dependency");
}
order.push(crypto);
let evidence =
context.add_node(OperationNodeKind::Evidence, OperationStage::Evidence, None);
context
.add_dependency(evidence, crypto)
.expect("forward dependency");
order.push(evidence);
Self { context, order }
}
pub fn compile(&mut self) {
self.context.compile().expect("valid benchmark plan");
}
pub fn execute(&self) {
for &node in &self.order {
self.context
.run(node, || Ok::<_, OperationPlanError>(()))
.expect("dependency order");
}
}
}