Skip to main content

rstm_core/programs/
instruction_set.rs

1/*
2    Appellation: program <module>
3    Created At: 2025.09.05:04:59:21
4    Contrib: @FL03
5*/
6#![allow(deprecated)]
7#![cfg(feature = "alloc")]
8use crate::{Head, Rule, RuleVec, Tail};
9use alloc::vec::{self, Vec};
10use rstm_state::{RawState, State};
11
12#[deprecated(since = "0.1.4", note = "Use the `Program` implementation instead")]
13/// The implementation is designed to provide a structured representation of a set
14/// of rules and an optional initial state for a Turing machine or similar computational model.
15/// It encapsulates the rules that dictate the machine's behavior and the starting point for
16/// its execution.
17#[derive(Clone, Debug, Default)]
18#[cfg_attr(
19    feature = "serde",
20    derive(serde::Deserialize, serde::Serialize),
21    serde(deny_unknown_fields, rename_all = "snake_case")
22)]
23#[repr(C)]
24pub struct InstructionSet<Q = String, A = char>
25where
26    Q: RawState,
27{
28    pub(crate) initial_state: State<Q>,
29    pub(crate) rules: Vec<Rule<Q, A>>,
30}
31
32impl<Q, A> InstructionSet<Q, A>
33where
34    Q: RawState,
35{
36    /// initializes a new, empty instance of the program
37    pub const fn new(initial_state: Q) -> Self {
38        Self {
39            initial_state: State(initial_state),
40            rules: Vec::new(),
41        }
42    }
43    /// returns a new instance of the program using the given rules
44    pub fn from_rules<I>(iter: I) -> Self
45    where
46        Q: Default,
47        I: IntoIterator<Item = Rule<Q, A>>,
48    {
49        Self {
50            initial_state: State::default(),
51            rules: Vec::from_iter(iter),
52        }
53    }
54    /// Create a new instance of the program using the given initial state.
55    pub fn from_state(initial_state: Q) -> Self {
56        Self {
57            initial_state: State(initial_state),
58            rules: Vec::new(),
59        }
60    }
61    #[cfg(all(feature = "json", feature = "std"))]
62    /// load a program from a `.json` file at the given path
63    pub fn load_from_json<P: AsRef<std::path::Path>>(path: P) -> crate::Result<Self>
64    where
65        InstructionSet<Q, A>: serde::de::DeserializeOwned,
66    {
67        // open the file
68        let file = std::fs::File::open(path)?;
69        // create a buffered reader
70        let reader = std::io::BufReader::new(file);
71        // deserialize the program
72        let p = serde_json::from_reader(reader)?;
73        Ok(p)
74    }
75    /// Returns an owned reference to the initial state of the program.
76    pub fn initial_state(&self) -> State<&Q> {
77        self.initial_state.view()
78    }
79    /// Returns a reference to the instructions.
80    pub const fn rules(&self) -> &RuleVec<Q, A> {
81        &self.rules
82    }
83    /// Returns a mutable reference to the instructions.
84    pub const fn rules_mut(&mut self) -> &mut RuleVec<Q, A> {
85        &mut self.rules
86    }
87    /// consumes the current instance to create another with the given default state
88    pub fn with_default_state(self, state: Q) -> Self {
89        Self {
90            initial_state: State(state),
91            ..self
92        }
93    }
94    /// consumes the current instance to create another with the given rules
95    pub fn with_rules<I>(self, rules: I) -> Self
96    where
97        I: IntoIterator<Item = Rule<Q, A>>,
98    {
99        Self {
100            rules: Vec::from_iter(rules),
101            ..self
102        }
103    }
104    /// Returns an iterator over the elements.
105    pub fn iter(&self) -> core::slice::Iter<'_, Rule<Q, A>> {
106        self.rules().iter()
107    }
108    /// Returns a mutable iterator over the elements.
109    pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, Rule<Q, A>> {
110        self.rules_mut().iter_mut()
111    }
112    /// returns an immutable reference to the tail for a given head; returns [`None`](Option::None)
113    /// if no match is found.
114    pub fn get<K>(&self, head: &K) -> Option<&Tail<Q, A>>
115    where
116        Q: PartialEq,
117        A: PartialEq,
118        K: core::borrow::Borrow<Head<Q, A>>,
119    {
120        self.iter().find_map(|i| {
121            if i.head() == head.borrow() {
122                Some(i.tail())
123            } else {
124                None
125            }
126        })
127    }
128    /// returns a mutable reference to the tail for a given head; returns [`None`](Option::None)
129    /// if no match is found.
130    pub fn get_mut<K>(&mut self, head: &K) -> Option<&mut Tail<Q, A>>
131    where
132        Q: PartialEq,
133        A: PartialEq,
134        K: core::borrow::Borrow<Head<Q, A>>,
135    {
136        self.iter_mut().find_map(|i| {
137            if i.head() == head.borrow() {
138                Some(i.tail_mut())
139            } else {
140                None
141            }
142        })
143    }
144    /// returns a reference to the tail of a rule for a given state and symbol; returns
145    /// [`None`](Option::None) if no match is found.
146    pub fn find_tail(&self, state: State<&Q>, symbol: &A) -> Option<&Tail<Q, A>>
147    where
148        Q: PartialEq,
149        A: PartialEq,
150    {
151        self.iter().find_map(|i| {
152            if i.head().view() == (Head { state, symbol }) {
153                Some(i.tail())
154            } else {
155                None
156            }
157        })
158    }
159    /// returns a mutable reference to the tail for a given head; returns [`None`](Option::None)
160    /// if no match is found.
161    pub fn find_mut_tail(&mut self, state: State<&Q>, symbol: &A) -> Option<&mut Tail<Q, A>>
162    where
163        Q: PartialEq,
164        A: PartialEq,
165    {
166        self.iter_mut().find_map(|i| {
167            if i.head().view() == (Head { state, symbol }) {
168                Some(i.tail_mut())
169            } else {
170                None
171            }
172        })
173    }
174    /// Returns a collection of rules whose head contains a match for the given state.
175    pub fn filter_by_state(&self, state: State<&Q>) -> Vec<&Rule<Q, A>>
176    where
177        Q: PartialEq,
178    {
179        self.iter().filter(|i| *i.head() == state).collect()
180    }
181    #[cfg(all(feature = "json", feature = "std"))]
182    /// export the program to a `.json` file at the given path
183    ///
184    /// **note**: there are no checks to see if the file already exists; it will automatically
185    /// be overwritten.
186    pub fn export_json<P>(&self, path: P) -> std::io::Result<()>
187    where
188        P: AsRef<std::path::Path>,
189        Q: serde::Serialize,
190        A: serde::Serialize,
191    {
192        let path = path.as_ref();
193        // ensure the filename ends with `.json`
194        if path.extension().map(|os| os.to_str()).flatten() != Some("json") {
195            #[cfg(feature = "tracing")]
196            tracing::error!(
197                "the provided path does not end with `.json`; consider changing the file extension"
198            );
199            return Err(std::io::Error::new(
200                std::io::ErrorKind::InvalidInput,
201                "the provided path does not end with `.json`",
202            ));
203        }
204        let serialized = serde_json::to_string_pretty(self).unwrap();
205        std::fs::write(path, serialized)?;
206        #[cfg(feature = "tracing")]
207        tracing::info!("Program exported as JSON");
208        Ok(())
209    }
210}
211
212impl<Q, A> InstructionSet<Q, A>
213where
214    Q: RawState,
215{
216    #[cfg(feature = "serde_json")]
217    /// serializes the current instance into a JSON string
218    pub fn to_json(&self) -> serde_json::Value
219    where
220        A: serde::Serialize,
221        Q: serde::Serialize,
222    {
223        serde_json::to_value(self).expect("Failed to serialize the Program instance")
224    }
225}
226
227impl<Q, A> AsRef<[Rule<Q, A>]> for InstructionSet<Q, A>
228where
229    Q: RawState,
230{
231    fn as_ref(&self) -> &[Rule<Q, A>] {
232        &self.rules
233    }
234}
235
236impl<Q, A> AsMut<[Rule<Q, A>]> for InstructionSet<Q, A>
237where
238    Q: RawState,
239{
240    fn as_mut(&mut self) -> &mut [Rule<Q, A>] {
241        &mut self.rules
242    }
243}
244
245impl<Q, A> core::ops::Deref for InstructionSet<Q, A>
246where
247    Q: RawState,
248{
249    type Target = [Rule<Q, A>];
250
251    fn deref(&self) -> &Self::Target {
252        &self.rules
253    }
254}
255
256impl<Q, A> core::ops::DerefMut for InstructionSet<Q, A>
257where
258    Q: RawState,
259{
260    fn deref_mut(&mut self) -> &mut Self::Target {
261        &mut self.rules
262    }
263}
264
265impl<Q, A> core::ops::Index<Head<Q, A>> for InstructionSet<Q, A>
266where
267    Q: RawState + PartialEq,
268    A: PartialEq,
269{
270    type Output = Tail<Q, A>;
271
272    fn index(&self, index: Head<Q, A>) -> &Self::Output {
273        self.get(&index).unwrap()
274    }
275}
276
277impl<Q, A> From<Vec<Rule<Q, A>>> for InstructionSet<Q, A>
278where
279    Q: RawState + Default,
280{
281    fn from(rules: Vec<Rule<Q, A>>) -> Self {
282        Self::from_rules(rules)
283    }
284}
285
286impl<Q, A> Extend<Rule<Q, A>> for InstructionSet<Q, A>
287where
288    Q: RawState,
289{
290    fn extend<I: IntoIterator<Item = Rule<Q, A>>>(&mut self, iter: I) {
291        self.rules_mut().extend(iter)
292    }
293}
294
295impl<Q, A> Extend<(Head<Q, A>, Tail<Q, A>)> for InstructionSet<Q, A>
296where
297    Q: RawState,
298{
299    fn extend<I: IntoIterator<Item = (Head<Q, A>, Tail<Q, A>)>>(&mut self, iter: I) {
300        self.rules_mut()
301            .extend(iter.into_iter().map(|(head, tail)| Rule { head, tail }))
302    }
303}
304
305impl<Q, A> FromIterator<Rule<Q, A>> for InstructionSet<Q, A>
306where
307    Q: RawState + Default,
308{
309    fn from_iter<I: IntoIterator<Item = Rule<Q, A>>>(iter: I) -> Self {
310        Self {
311            initial_state: State::default(),
312            rules: iter.into_iter().collect::<RuleVec<Q, A>>(),
313        }
314    }
315}
316
317impl<Q, A> FromIterator<(Head<Q, A>, Tail<Q, A>)> for InstructionSet<Q, A>
318where
319    Q: RawState + Default,
320{
321    fn from_iter<I: IntoIterator<Item = (Head<Q, A>, Tail<Q, A>)>>(iter: I) -> Self {
322        Self::from_rules(iter.into_iter().map(|(head, tail)| Rule { head, tail }))
323    }
324}
325
326impl<Q, A> IntoIterator for InstructionSet<Q, A>
327where
328    Q: RawState,
329{
330    type Item = Rule<Q, A>;
331    type IntoIter = vec::IntoIter<Self::Item>;
332
333    fn into_iter(self) -> Self::IntoIter {
334        self.rules.into_iter()
335    }
336}