Skip to main content

rstm_core/motion/
head_step.rs

1/*
2    Appellation: moving_head <module>
3    Created At: 2025.12.19:14:43:21
4    Contrib: @FL03
5*/
6use crate::{Head, Tail};
7use rstm_state::RawState;
8
9/// [`HeadStep`] defines a *lazy* stepper for a Turing machine configured with a so-called 
10/// *moving head*.
11pub struct HeadStep<'a, Q1, A1, Q2 = Q1, A2 = A1>
12where
13    Q1: RawState,
14    Q2: RawState,
15{
16    pub(crate) head: &'a mut Head<Q1, A1>,
17    pub(crate) tail: Tail<Q2, A2>,
18}
19/// the standard implementation of [`HeadStep`] focuses on instances where the head and tail
20/// share the same type-space; meaning `Head<Q, A>` and `Tail<Q, A>` types are being utilized.
21impl<'a, Q, A> HeadStep<'a, Q, A>
22where
23    Q: RawState,
24{
25    #[inline]
26    /// apply the step, mutating the head according to the tail's instructions before
27    /// returning the previous head value.
28    pub fn apply(self) -> Head<Q, A> {
29        let Tail {
30            next_state,
31            write_symbol,
32            ..
33        } = self.tail;
34        // replace the head with the next state and symbol, returning the previous head
35        self.head.replace(next_state, write_symbol)
36    }
37    #[inline]
38    /// this method performs the step operation onto the tape, assuming the head's symbol to be  
39    pub fn move_along(self, tape: &mut [A], pos: &mut usize) -> Head<Q, A>
40    where
41        A: Clone,
42    {
43        tape[*pos] = self.tail.write_symbol.clone();
44        *pos += self.tail.direction;
45        self.apply()
46    }
47}
48
49/// this implementation of the [`HeadStep`] is specifically designed for scenarios where the
50/// head's symbol is used to define the position
51impl<'a, Q, A> HeadStep<'a, Q, usize, Q, A>
52where
53    Q: RawState,
54{
55    #[inline]
56    /// this method shifts the head along the tape, returning a head containing the previous
57    /// state and symbol.
58    ///
59    /// **note**: this method **does not** check if the current nor the next state is halted,
60    /// it is up to the caller to establishing halting.
61    pub fn shift(self, tape: &mut [A]) -> crate::Result<Head<Q, A>>
62    where
63        A: Clone,
64    {
65        let pos = self.head.symbol;
66        if pos >= tape.len() {
67            #[cfg(feature = "tracing")]
68            tracing::error!(
69                "The position of the head ({}) is out of tape bounds for a tape of length {}",
70                pos,
71                tape.len()
72            );
73            return Err(crate::Error::index_out_of_bounds(pos, tape.len()));
74        }
75        let Tail {
76            next_state,
77            direction,
78            write_symbol,
79        } = self.tail;
80        // replace the head state
81        let prev = Head {
82            state: self.head.replace_state(next_state),
83            symbol: tape[pos].clone(),
84        };
85        // write the new symbol to the tape
86        tape[pos] = write_symbol;
87        // update the head position based on the tail's direction
88        self.head.symbol += direction;
89        Ok(prev)
90    }
91}