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}