use crate::instruction::{Head, Move, Tail};
use crate::state::Configuration;
use crate::{Symbol, TuringMachine};
type CHandler<S> = Box<dyn Fn(&Configuration<S>)>;
type IHandler<S> = Box<dyn Fn(&Head<S>, &Tail<S>)>;
pub struct Debugger<Machine, S: Symbol>
where
Machine: TuringMachine<S>,
{
machine: Machine,
c_handler: Option<CHandler<S>>,
i_handler: Option<IHandler<S>>,
}
impl<Machine, S: Symbol> Debugger<Machine, S>
where
Machine: TuringMachine<S>,
{
pub fn new(machine: Machine) -> Self {
Debugger {
machine,
c_handler: None,
i_handler: None,
}
}
pub fn set_c_handler(&mut self, c_handler: impl Fn(&Configuration<S>) + 'static) {
self.c_handler = Some(Box::new(c_handler));
}
pub fn set_i_handler(&mut self, i_handler: impl Fn(&Head<S>, &Tail<S>) + 'static) {
self.i_handler = Some(Box::new(i_handler));
}
}
impl<Machine, S: Symbol> TuringMachine<S> for Debugger<Machine, S>
where
Machine: TuringMachine<S>,
{
fn execute_once(&self, conf: Configuration<S>) -> Result<Configuration<S>, String> {
let next = self.machine.execute_once(conf.clone())?;
if let Some(ref c_handler) = self.c_handler {
c_handler(&conf);
}
if let Some(ref i_handler) = self.i_handler {
let head = Head::new(conf.state, conf.get_symbol().clone());
let movement = match (conf.index(), next.index()) {
(old, new) if old < new => Move::Right,
(old, new) if old == new => Move::None,
(old, new) if old > new => Move::Right,
(old, new) => panic!(
"execute_once error: not all compare cases are covered for old {} and new {} indexes",
old,
new
)
};
let tail = Tail::new(next.state, next.get_symbol().clone(), movement);
i_handler(&head, &tail);
}
Ok(next)
}
fn execute_until(
&self,
mut conf: Configuration<S>,
until: impl Fn(&Configuration<S>) -> bool,
) -> Result<Configuration<S>, String> {
if self.c_handler.is_none() && self.i_handler.is_none() {
return self.machine.execute_until(conf, until);
}
while !until(&conf) {
conf = self.execute_once(conf)?;
}
Ok(conf)
}
}