mod error;
mod program;
mod state;
use super::super::codecs::structure::DispatchInstructions;
use super::super::error::ExecError;
use super::super::exec::{Edge, GraphCx};
use super::super::registry::{GraphFn, NodeId};
use super::run_dispatch_node;
use program::AtomType;
pub(crate) const DESCRIPTION_PID: i32 = crate::graph::params::sddl::DESCRIPTION;
#[derive(Debug)]
pub(crate) struct Sddl;
pub(crate) static SDDL: Sddl = Sddl;
pub(crate) fn validate(description: &[u8]) -> bool {
program::load(description).is_ok()
}
fn conversion_node(width: usize, big_endian: bool) -> Option<NodeId> {
let index = match (width, big_endian) {
(1, _) => 19,
(2, false) => 20,
(4, false) => 21,
(8, false) => 22,
(2, true) => 23,
(4, true) => 24,
(8, true) => 25,
_ => return None,
};
Some(NodeId::std(index))
}
impl GraphFn for Sddl {
fn run(&self, cx: &mut GraphCx<'_, '_, '_>, inputs: &[Edge]) -> Result<(), ExecError> {
let [input] = inputs else {
return Err(ExecError::Parameter("sddl takes exactly one input"));
};
if !cx.eff.custom_nodes.is_empty() {
return Err(ExecError::Parameter("sddl takes no custom node"));
}
let [successor] = cx.eff.custom_graphs else {
return Err(ExecError::Parameter("sddl needs exactly one custom graph"));
};
let successor = *successor;
let description = cx
.eff
.params
.copy(DESCRIPTION_PID)
.filter(|description| !description.is_empty())
.ok_or(ExecError::Parameter("sddl needs a description"))?;
let program = program::load(description)?;
let instructions = state::run(&program, cx.data(*input)?.bytes())?;
let dispatch = DispatchInstructions {
segment_sizes: instructions.segment_sizes,
tags: instructions.tags,
nb_tags: instructions.outputs.len(),
};
let edges = run_dispatch_node(cx, *input, &dispatch)?;
if edges.len() != instructions.outputs.len() + 2 {
return Err(ExecError::Parameter(
"dispatch produced an unexpected number of outputs",
));
}
let mut converted = edges.clone();
for (index, info) in instructions.outputs.iter().enumerate() {
if info.width == 0 {
continue;
}
if info.ty == AtomType::Numeric {
let node = conversion_node(info.width, info.big_endian).ok_or(
ExecError::Parameter("unhandled output stream width from dispatch"),
)?;
let out = cx.run_node(node, &[edges[index + 2]], None)?;
let [edge] = out[..] else {
return Err(ExecError::SuccessorInputs);
};
converted[index + 2] = edge;
}
}
for (index, &edge) in converted.iter().enumerate() {
cx.set_metadata(edge, 0, index as i32)?;
}
cx.set_destination(&converted, successor, None)
}
}
#[cfg(test)]
mod tests;