1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
    Appellation: programs <module>
    Contrib: FL03 <jo3mccain@icloud.com>
    Description: ... summary ...
*/
use crate::states::{State, Stateful, States};
use crate::turing::{Head, Instruction};
use crate::{Extend, Resultant, Symbolic};
use serde::{Deserialize, Serialize};
use std::mem::replace;

#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Program<S: Symbolic> {
    alphabet: Vec<S>,
    instructions: Vec<Instruction<S>>,
    final_state: State<States>,
}

impl<S: Symbolic> Program<S> {
    pub fn new(alphabet: Vec<S>, final_state: State) -> Self {
        let s: i64 = final_state.state().clone().into();
        let capacity = alphabet.len() * s as usize;
        let instructions = Vec::with_capacity(capacity);

        Self {
            alphabet,
            instructions,
            final_state,
        }
    }
    /// Returns an owned instance of the current program's alphabet
    pub fn alphabet(&self) -> &Vec<S> {
        &self.alphabet
    }
    pub fn default_symbol(&self) -> &S {
        &self.alphabet.first().unwrap()
    }
    /// Returns an owned instance of the current [Instruction] set
    pub fn instructions(&self) -> &Vec<Instruction<S>> {
        &self.instructions
    }
    /// Returns an owned instance of the final state
    pub fn final_state(&self) -> &State {
        &self.final_state
    }
    /// Given some [Head], find the coresponding [Instruction]
    pub fn get(&self, head: Head<S>) -> Resultant<&Instruction<S>> {
        if self.final_state().clone().state() < head.state().clone().state() {
            return Err("The provided head is greater than the final state...".to_string());
        }
        if let Some(v) = self
            .instructions()
            .iter()
            .find(|inst: &&Instruction<S>| inst.head().clone() == head)
        {
            return Ok(v);
        }
        Err("Failed to find instructions for the provided head...".to_string())
    }
    /// Insert a new [Instruction] set into the program
    pub fn insert(&mut self, inst: Instruction<S>) -> Resultant<Option<Instruction<S>>> {
        if inst.head().state() == &State::from(States::invalid()) {
            return Err("Set error: Instruction cannot have 0 state in head...".to_string());
        }
        if !self.alphabet().contains(inst.head().symbol())
            || !self.alphabet().contains(inst.tail().symbol())
        {
            return Err(
                "The provided instruction set fails to be represented within the alphabet..."
                    .to_string(),
            );
        }
        if self.final_state().clone().state() < inst.head().state().clone().state()
            || self.final_state().clone().state() < inst.tail().state().clone().state()
        {
            return Err("Instructions have states greater than the ones availible...".to_string());
        }
        let position = self
            .instructions()
            .iter()
            .position(|cand: &Instruction<S>| cand.head() == inst.head());

        match position {
            Some(index) => Ok(Some(replace(&mut self.instructions[index], inst))),
            None => {
                self.instructions.push(inst);
                Ok(None)
            }
        }
    }
}

impl<S: Symbolic> Extend<Instruction<S>> for Program<S> {
    fn extend<T: IntoIterator<Item = Instruction<S>>>(&mut self, iter: T) -> Result<(), String> {
        for i in iter {
            self.insert(i)?;
        }
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::states::{State, States};
    use crate::turing::{Instruction, Move};

    #[test]
    fn test_program() {
        let inst = Instruction::from((
            State::from(States::valid()),
            "a",
            State::from(States::valid()),
            "b",
            Move::Right,
        ));
        let alphabet = vec!["a", "b", "c"];
        let mut program = Program::new(alphabet, State::from(States::invalid()));

        assert!(program.insert(inst.clone()).is_ok());
        assert!(program.get(inst.head().clone()).is_ok())
    }
}