turing_machine_rs/machines/debugger.rs
1use crate::instruction::{Head, Move, Tail};
2use crate::state::Configuration;
3use crate::{Symbol, TuringMachine};
4
5type CHandler<S> = Box<dyn Fn(&Configuration<S>)>;
6type IHandler<S> = Box<dyn Fn(&Head<S>, &Tail<S>)>;
7
8/// [`Debugger`] is an super useful [`TuringMachine`] for debugging another
9/// Turing machine! This machine debugged all Turing machines in tests.
10///
11/// Note: this machine is not implementing [`crate::With`].
12///
13/// # Examples
14/// ```rust
15/// use std::cell::RefCell;
16/// use std::ops::Deref;
17/// use std::rc::Rc;
18///
19/// use turing_machine_rs::TuringMachine;
20/// use turing_machine_rs::instruction::{Move, State};
21/// use turing_machine_rs::machines::{Debugger, Classic};
22/// use turing_machine_rs::program::{Extend, Program};
23/// use turing_machine_rs::state::{Configuration, Tape};
24///
25/// fn main() -> Result<(), String> {
26/// let mut program = Program::new(vec![' '], State(1));
27/// program.extend([(1, ' ', 1, ' ', Move::Right)])?;
28///
29/// let machine = Classic::new(program, ' ')?;
30/// let mut debugger = Debugger::new(machine);
31///
32/// let conf = Configuration::new_nrm(Tape::from(" "))?;
33///
34/// let buffer = Rc::new(RefCell::new(String::new()));
35///
36/// let c_buffer = buffer.clone();
37/// debugger.set_c_handler(move |_| {
38/// let mut buffer = c_buffer.borrow_mut();
39/// buffer.push('c');
40/// });
41///
42/// let conf = debugger.execute_once(conf)?;
43/// debugger.execute_once(conf)?;
44///
45/// assert_eq!(String::from("cc"), buffer.deref().borrow().as_ref());
46/// Ok(())
47/// }
48/// ```
49pub struct Debugger<Machine, S: Symbol>
50where
51 Machine: TuringMachine<S>,
52{
53 machine: Machine,
54 c_handler: Option<CHandler<S>>,
55 i_handler: Option<IHandler<S>>,
56}
57
58impl<Machine, S: Symbol> Debugger<Machine, S>
59where
60 Machine: TuringMachine<S>,
61{
62 /// Constructs a new [`Debugger`] with a [`TuringMachine`] and no handlers.
63 ///
64 /// For setup handlers, use the [`Debugger::set_c_handler`]
65 /// and the [`Debugger::set_i_handler`] methods.
66 pub fn new(machine: Machine) -> Self {
67 Debugger {
68 machine,
69 c_handler: None,
70 i_handler: None,
71 }
72 }
73
74 /// Sets a handler for configurations. Handler must implement
75 /// [`Fn(&Configuration<Symbol>)`] trait.
76 ///
77 /// This function is not permanent so handler can be changed.
78 pub fn set_c_handler(&mut self, c_handler: impl Fn(&Configuration<S>) + 'static) {
79 self.c_handler = Some(Box::new(c_handler));
80 }
81
82 /// Sets a handler for instructions. Handler must implement
83 /// [`Fn(&Head<Symbol>, &Tail<Symbol>)`] trait.
84 ///
85 /// This function is not permanent so handler can be changed.
86 pub fn set_i_handler(&mut self, i_handler: impl Fn(&Head<S>, &Tail<S>) + 'static) {
87 self.i_handler = Some(Box::new(i_handler));
88 }
89}
90
91impl<Machine, S: Symbol> TuringMachine<S> for Debugger<Machine, S>
92where
93 Machine: TuringMachine<S>,
94{
95 /// Executes [`Configuration`] once by mutation.
96 ///
97 /// Works quickly when no handler is set (but you probably don't want to
98 /// use the debugger without the debugging).
99 ///
100 /// # Panics
101 /// [`Debugger`] could panic only if source code is broken - this would be a bug.
102 /// All match cases must and are covered.
103 ///
104 /// So you could open an issue on [GitHub](https://github.com/Helltraitor/turing-machine-rs).
105 fn execute_once(&self, conf: Configuration<S>) -> Result<Configuration<S>, String> {
106 let next = self.machine.execute_once(conf.clone())?;
107 if let Some(ref c_handler) = self.c_handler {
108 c_handler(&conf);
109 }
110 if let Some(ref i_handler) = self.i_handler {
111 let head = Head::new(conf.state, conf.get_symbol().clone());
112 let movement = match (conf.index(), next.index()) {
113 (old, new) if old < new => Move::Right,
114 (old, new) if old == new => Move::None,
115 (old, new) if old > new => Move::Right,
116 (old, new) => panic!(
117 "execute_once error: not all compare cases are covered for old {} and new {} indexes",
118 old,
119 new
120 )
121 };
122 let tail = Tail::new(next.state, next.get_symbol().clone(), movement);
123 i_handler(&head, &tail);
124 }
125 Ok(next)
126 }
127
128 /// Executes [`Configuration`] until predicate is `false` by mutation.
129 ///
130 /// Uses the [`Debugger::execute_once`] method in the loop. Works quickly
131 /// when no handler set (but probably you don't wnat to use the debugger without tools).
132 fn execute_until(
133 &self,
134 mut conf: Configuration<S>,
135 until: impl Fn(&Configuration<S>) -> bool,
136 ) -> Result<Configuration<S>, String> {
137 if self.c_handler.is_none() && self.i_handler.is_none() {
138 return self.machine.execute_until(conf, until);
139 }
140 while !until(&conf) {
141 conf = self.execute_once(conf)?;
142 }
143 Ok(conf)
144 }
145}