use std::collections::HashSet;
use crate::jet::Jet;
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<J: Jet> {
fn visit_node(&mut self, _node: &RedeemNode<J>, _input: super::FrameIter, _output: NodeOutput) {
}
}
pub trait PruneTracker<J: Jet>: ExecTracker<J> {
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<J: Jet> ExecTracker<J> for SetTracker {
fn visit_node<'d>(
&mut self,
node: &RedeemNode<J>,
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<J: Jet> PruneTracker<J> 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<J: Jet> ExecTracker<J> for NoTracker {
fn visit_node<'d>(
&mut self,
node: &RedeemNode<J>,
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<J: Jet> ExecTracker<J> for StderrTracker {
fn visit_node(&mut self, node: &RedeemNode<J>, 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::<J>::visit_node(&mut self.inner, node, input, output);
self.exec_count += 1;
eprintln!();
}
}
impl<J: Jet> PruneTracker<J> for StderrTracker {
fn contains_left(&self, ihr: Ihr) -> bool {
if PruneTracker::<J>::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::<J>::contains_right(&self.inner, ihr) {
true
} else {
eprintln!("Pruning unexecuted right child of IHR {ihr}");
false
}
}
}