use std::collections::HashSet;
use crate::node::Inner;
use crate::{Ihr, RedeemNode, Value};
#[derive(Debug, Clone)]
pub enum NodeOutput<'m> {
NonTerminal,
JetFailed,
Success(super::FrameIter<'m>),
}
pub trait ExecTracker {
fn visit_node(&mut self, _node: &RedeemNode, _input: super::FrameIter, _output: NodeOutput) {}
}
pub trait PruneTracker: ExecTracker {
fn contains_left(&self, ihr: Ihr) -> bool;
fn contains_right(&self, ihr: Ihr) -> bool;
}
#[derive(Clone, Debug, Default)]
pub struct SetTracker {
left: HashSet<Ihr>,
right: HashSet<Ihr>,
}
impl ExecTracker for SetTracker {
fn visit_node<'d>(
&mut self,
node: &RedeemNode,
mut input: super::FrameIter,
_output: NodeOutput,
) {
match (node.inner(), input.next()) {
(Inner::AssertL(..) | Inner::Case(..), Some(false)) => {
self.left.insert(node.ihr());
}
(Inner::AssertR(..) | Inner::Case(..), Some(true)) => {
self.right.insert(node.ihr());
}
_ => {}
}
}
}
impl PruneTracker for SetTracker {
fn contains_left(&self, ihr: Ihr) -> bool {
self.left.contains(&ihr)
}
fn contains_right(&self, ihr: Ihr) -> bool {
self.right.contains(&ihr)
}
}
#[derive(Copy, Clone, Debug)]
pub struct NoTracker;
impl ExecTracker for NoTracker {
fn visit_node<'d>(
&mut self,
node: &RedeemNode,
mut input: super::FrameIter,
output: NodeOutput,
) {
if cfg!(test) {
Value::from_padded_bits(&mut input, &node.arrow().source)
.expect("decoding input should work");
if let NodeOutput::Success(mut output) = output {
Value::from_padded_bits(&mut output, &node.arrow().target)
.expect("decoding output should work");
}
}
}
}
#[derive(Clone, Debug, Default)]
pub struct StderrTracker {
exec_count: usize,
inner: SetTracker,
}
impl StderrTracker {
pub fn new() -> Self {
Self::default()
}
}
impl ExecTracker for StderrTracker {
fn visit_node(&mut self, node: &RedeemNode, input: super::FrameIter, output: NodeOutput) {
let input_val = Value::from_padded_bits(&mut input.clone(), &node.arrow().source)
.expect("input from bit machine will always be well-formed");
eprintln!(
"[{:4}] exec {:10} {}",
self.exec_count,
node.inner(),
node.arrow()
);
eprintln!(" input {input_val}");
match output.clone() {
NodeOutput::NonTerminal => { }
NodeOutput::JetFailed => eprintln!(" JET FAILED"),
NodeOutput::Success(mut output) => {
let output_val = Value::from_padded_bits(&mut output, &node.arrow().target)
.expect("output from bit machine will always be well-formed");
eprintln!(" output {output_val}");
}
}
if let crate::node::Inner::AssertL(_, cmr) = node.inner() {
eprintln!(" [debug] assertL CMR {cmr}");
}
ExecTracker::visit_node(&mut self.inner, node, input, output);
self.exec_count += 1;
eprintln!();
}
}
impl PruneTracker for StderrTracker {
fn contains_left(&self, ihr: Ihr) -> bool {
if PruneTracker::contains_left(&self.inner, ihr) {
true
} else {
eprintln!("Pruning unexecuted left child of IHR {ihr}");
false
}
}
fn contains_right(&self, ihr: Ihr) -> bool {
if PruneTracker::contains_right(&self.inner, ihr) {
true
} else {
eprintln!("Pruning unexecuted right child of IHR {ihr}");
false
}
}
}