use std::io::Write;
use crate::tracer::{StepState, Tracer};
use crate::value::RegVal;
const W_STEP: usize = 6;
const W_OFFSET: usize = 8;
const W_INSTR: usize = 21;
const W_STACK: usize = 25;
const W_READ: usize = 15;
const W_WRITTEN: usize = 15;
const MAX_STACK_DISPLAY: usize = 8;
#[derive(Debug)]
pub struct TextTracer<W: Write> {
out: W,
header_written: bool,
}
impl<W: Write> TextTracer<W> {
pub fn new(out: W) -> Self {
Self {
out,
header_written: false,
}
}
}
fn fmt_regval(val: &RegVal) -> String {
match val {
RegVal::Unset => "unset".to_string(),
RegVal::Int(v) => format!("{v}"),
RegVal::VecInt(v) => format!("vec<int>(len={})", v.len()),
RegVal::VecXqmx(v) => format!("vec<model>(len={})", v.len()),
RegVal::Model(m) => format!("model({}x{})", m.rows, m.cols),
RegVal::Sample(s) => format!("sample(len={})", s.values.len()),
}
}
fn fmt_regs(regs: &[(u8, RegVal)]) -> String {
regs.iter()
.map(|(idx, val)| format!("r{idx}={}", fmt_regval(val)))
.collect::<Vec<_>>()
.join(", ")
}
fn fmt_stack(stack: &[i64]) -> String {
if stack.len() <= MAX_STACK_DISPLAY {
format!("{stack:?}")
} else {
let skip = stack.len() - MAX_STACK_DISPLAY;
let top = stack.get(skip..).unwrap_or_default();
format!("[...{skip} more, {}]", fmt_stack_elems(top))
}
}
fn fmt_stack_elems(elems: &[i64]) -> String {
elems
.iter()
.map(|v| format!("{v}"))
.collect::<Vec<_>>()
.join(", ")
}
impl<W: Write> Tracer for TextTracer<W> {
type Error = std::io::Error;
fn on_step(&mut self, state: &StepState<'_>) -> Result<(), Self::Error> {
if !self.header_written {
writeln!(
self.out,
"{:<W_STEP$} {:<W_OFFSET$} {:<W_INSTR$} {:<W_STACK$} {:<W_READ$} {:<W_WRITTEN$}",
"step", "offset", "instruction", "stack", "read-regs", "written-regs",
)?;
self.header_written = true;
}
let offset = format!("{:#06X}", state.pos);
let instr = format!("{}", state.instruction);
let stack = fmt_stack(state.stack);
let read = fmt_regs(state.read_regs);
let written = fmt_regs(state.written_regs);
writeln!(
self.out,
"{:>W_STEP$} {:<W_OFFSET$} {:<W_INSTR$} {:<W_STACK$} {:<W_READ$} {:<W_WRITTEN$}",
state.step, offset, instr, stack, read, written,
)?;
Ok(())
}
}