turing_machine_rs/machines/
classic.rs

1use std::fmt;
2
3use crate::instruction::Head;
4use crate::program::Program;
5use crate::state::Configuration;
6use crate::{Symbol, TuringMachine, With};
7
8/// [`Classic`] is a common [`TuringMachine`] realization that can be used
9/// freely for program execution.
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct Classic<S: Symbol> {
12    default: S,
13    program: Program<S>,
14}
15
16impl<S: Symbol> Classic<S> {
17    /// Constructs a new [`Classic`] Turing machine from the program
18    /// [`Program`] and the default symbol [`Symbol`].
19    ///
20    /// Returns [`Ok(Classic)`] when the default symbol is in the program
21    /// alphabet otherwise [`Err(String)`] with diagnostic information.
22    ///
23    /// # Examples
24    /// Trying to return the new machine with a mismatched default symbol:
25    /// ```rust
26    /// use turing_machine_rs::instruction::State;
27    /// use turing_machine_rs::machines::Classic;
28    /// use turing_machine_rs::program::Program;
29    ///
30    /// let program = Program::new(vec!['0', '1'], State(1));
31    /// let machine = Classic::new(program, '!');
32    ///
33    /// assert!(machine.is_err());
34    /// ```
35    ///
36    /// Successful creation:
37    /// ```rust
38    /// use turing_machine_rs::instruction::State;
39    /// use turing_machine_rs::machines::Classic;
40    /// use turing_machine_rs::program::Program;
41    ///
42    /// let program = Program::new(vec!['0', '1'], State(1));
43    /// let machine = Classic::new(program, '0');
44    ///
45    /// assert!(machine.is_ok());
46    /// ```
47    pub fn new(program: Program<S>, default: S) -> Result<Self, String> {
48        match program.alphabet().contains(&default) {
49            true => Ok(Classic { program, default }),
50            false => Err(format!(
51                "new error: default symbol {} is not in alphabet {:?}",
52                default,
53                program.alphabet()
54            )),
55        }
56    }
57}
58
59impl<S: Symbol> TuringMachine<S> for Classic<S> {
60    /// Executes [`Configuration`] once by mutation.
61    ///
62    /// Returns [`Ok(Configuration)`] when an [`crate::instruction::Instruction`]
63    /// exists for the current [`Configuration`] symbol and state.
64    /// And otherwise returns [`Err(String)`] with diagnostic information.
65    fn execute_once(&self, mut conf: Configuration<S>) -> Result<Configuration<S>, String> {
66        let head = Head::new(conf.state, conf.get_symbol().clone());
67        let inst = match self.program.get(&head)? {
68            Some(inst) => inst,
69            None => {
70                return Err(format!(
71                    "uncovered case: have no tail for head ({}) in program",
72                    head
73                ))
74            }
75        };
76        conf.state = inst.tail.state;
77        conf.set_symbol(inst.tail.symbol.clone());
78        conf.shift(inst.tail.movement, self.default.clone());
79        Ok(conf)
80    }
81
82    /// Executes [`Configuration`] until predicate is `false` by mutation.
83    ///
84    /// Returns [`Ok(Configuration)`] when an [`crate::instruction::Instruction`]
85    /// exists for the current [`Configuration`] symbol and state.
86    /// And otherwise returns [`Err(String)`] with diagnostic information.
87    fn execute_until(
88        &self,
89        mut conf: Configuration<S>,
90        until: impl Fn(&Configuration<S>) -> bool,
91    ) -> Result<Configuration<S>, String> {
92        while !until(&conf) {
93            let head = Head::new(conf.state, conf.get_symbol().clone());
94            let inst = match self.program.get(&head)? {
95                Some(inst) => inst,
96                None => {
97                    return Err(format!(
98                        "uncovered case: have no tail for head ({}) in program",
99                        head
100                    ))
101                }
102            };
103            conf.state = inst.tail.state;
104            conf.set_symbol(inst.tail.symbol.clone());
105            conf.shift(inst.tail.movement, self.default.clone());
106        }
107        Ok(conf)
108    }
109}
110
111impl<S: Symbol> With<Classic<S>> for Classic<S> {
112    type Output = Result<Classic<S>, String>;
113
114    /// Makes superposition with two or more [`Classic`] machines by chain.
115    /// This method accept only [`Classic`] struct and can be used only for
116    /// another [`Classic`] machine.
117    ///
118    /// Returns a new [`Ok(Classic)`] when machines can be concatenated
119    /// and [`Err(String)`] with diagnostic information when machines
120    /// have different alphabets or default symbols.
121    fn with(&self, other: &Classic<S>) -> Self::Output {
122        if self.default != other.default {
123            return Err(format!(
124                "with error: classic machines have different default symbols: {} and {}",
125                self.default, other.default,
126            ));
127        }
128        // `Program::with` implementation guarantees that program can
129        // be concatenated only with the same alphabet
130        let program = self.program.with(&other.program)?;
131        Classic::new(program, self.default.clone())
132    }
133}
134
135impl<S: Symbol> With<Classic<S>> for Result<Classic<S>, String> {
136    type Output = Result<Classic<S>, String>;
137
138    /// Makes superposition with two or more [`Classic`] machines by chain.
139    /// This method accept only [`Classic`] struct and can be used only for
140    /// [`Result<Classic, String>`].
141    ///
142    /// Returns a new [`Ok(Classic)`] when `self` is [`Result::Ok`] and machines
143    /// can be concatenated and [`Err(String)`] when `self` is [`Result::Ok`]
144    /// but machines have different alphabets or default symbols.
145    ///
146    /// And Returns a copy of [`Err(String)`] when `self` is [`Result::Err`].
147    fn with(&self, other: &Classic<S>) -> Self::Output {
148        match self {
149            Ok(machine) => machine.with(other),
150            Err(msg) => Err(msg.clone()),
151        }
152    }
153}
154
155impl<S: Symbol> fmt::Display for Classic<S> {
156    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
157        use std::any::type_name;
158
159        write!(
160            f,
161            "Classic<{}> {{ program: {} }}",
162            type_name::<S>(),
163            self.program
164        )
165    }
166}