use crate::{DispatchError, DispatchResult, OpFrame};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DenseOpArg {
pub n: i64,
pub text: &'static str,
}
impl DenseOpArg {
pub const ZERO: Self = Self { n: 0, text: "" };
pub const fn n(n: i64) -> Self { Self { n, text: "" } }
pub const fn text(text: &'static str) -> Self { Self { n: 0, text } }
}
pub type DenseOpFn = fn(OpFrame, DenseOpArg) -> DispatchResult<OpFrame>;
#[derive(Clone, Copy)]
pub struct DenseOpEntry {
pub func: DenseOpFn,
pub arg: DenseOpArg,
pub name: &'static str,
}
impl core::fmt::Debug for DenseOpEntry {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("DenseOpEntry")
.field("name", &self.name)
.field("arg", &self.arg)
.finish()
}
}
pub fn dense_nop(frame: OpFrame, _arg: DenseOpArg) -> DispatchResult<OpFrame> { Ok(frame) }
pub fn dense_add_prefix(mut frame: OpFrame, arg: DenseOpArg) -> DispatchResult<OpFrame> {
frame.text = format!("{}{}", arg.text, frame.text);
Ok(frame)
}
pub fn dense_add_suffix(mut frame: OpFrame, arg: DenseOpArg) -> DispatchResult<OpFrame> {
frame.text = format!("{}{}", frame.text, arg.text);
Ok(frame)
}
pub fn dense_acc_add(mut frame: OpFrame, arg: DenseOpArg) -> DispatchResult<OpFrame> {
frame.acc += arg.n;
Ok(frame)
}
pub fn dense_acc_mul(mut frame: OpFrame, arg: DenseOpArg) -> DispatchResult<OpFrame> {
frame.acc *= arg.n;
Ok(frame)
}
pub fn dense_octet_encode(mut frame: OpFrame, _arg: DenseOpArg) -> DispatchResult<OpFrame> {
if !frame.text.chars().all(|c| c.is_ascii_hexdigit()) {
return Err(DispatchError::InvalidInput(frame.text));
}
let value = u32::from_str_radix(&frame.text, 16)
.map_err(|_| DispatchError::InvalidInput(frame.text.clone()))?;
frame.text = format!("{:X}", value);
Ok(frame)
}
const NOP_ENTRY: DenseOpEntry = DenseOpEntry {
func: dense_nop,
arg: DenseOpArg::ZERO,
name: "nop",
};
#[derive(Debug, Clone)]
pub struct DenseOperationTable {
entries: [DenseOpEntry; 256],
}
impl Default for DenseOperationTable {
fn default() -> Self { Self::new() }
}
impl DenseOperationTable {
pub fn new() -> Self { Self { entries: [NOP_ENTRY; 256] } }
pub fn register(&mut self, selector: u8, name: &'static str, func: DenseOpFn, arg: DenseOpArg) {
self.entries[selector as usize] = DenseOpEntry { func, arg, name };
}
pub fn execute(&self, selector: u8, frame: OpFrame) -> DispatchResult<OpFrame> {
let entry = self.entries[selector as usize];
(entry.func)(frame, entry.arg)
}
pub fn name(&self, selector: u8) -> &'static str { self.entries[selector as usize].name }
}
pub fn default_dense_table() -> DenseOperationTable {
let mut table = DenseOperationTable::new();
table.register(0x01, "add_prefix", dense_add_prefix, DenseOpArg::text("Prefix_"));
table.register(0x02, "add_suffix", dense_add_suffix, DenseOpArg::text("_Suffix"));
table.register(0x20, "octet_encode", dense_octet_encode, DenseOpArg::ZERO);
table.register(0x30, "acc_add", dense_acc_add, DenseOpArg::n(1));
table.register(0x31, "acc_mul", dense_acc_mul, DenseOpArg::n(2));
table
}