pushr/push/
io.rs

1use crate::push::instructions::Instruction;
2use crate::push::instructions::InstructionCache;
3use crate::push::state::PushState;
4use crate::push::stack::PushPrint;
5use crate::push::vector::{BoolVector,IntVector};
6use std::collections::HashMap;
7use std::fmt;
8
9#[derive(Clone, Debug, Default)]
10pub struct PushMessage {
11    pub header: IntVector,
12    pub body: BoolVector,
13}
14
15impl PushMessage {
16    pub fn new(header: IntVector, body: BoolVector) -> Self {
17        Self { header: header, body: body}
18    }
19}
20
21impl PushPrint for PushMessage {
22   fn to_pstring(&self) -> String {
23       self.to_string()
24   }
25}
26
27impl fmt::Display for PushMessage {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        let msg_str = format!("{}&{}", self.header.to_string(), self.body.to_string());
30        write!(f, "{}", msg_str)
31    }
32}
33
34impl PartialEq for PushMessage {
35    fn eq(&self, other: &Self) -> bool {
36        self.header.values == other.header.values && self.body.values == other.body.values
37    }
38}
39
40pub fn load_io_instructions(map: &mut HashMap<String, Instruction>) {
41    map.insert(
42        String::from("INPUT.AVAILABLE"),
43        Instruction::new(input_available),
44    );
45    map.insert(String::from("INPUT.GET"), Instruction::new(input_get));
46    map.insert(String::from("INPUT.NEXT"), Instruction::new(input_next));
47    map.insert(String::from("INPUT.READ"), Instruction::new(input_read));
48    map.insert(
49        String::from("INPUT.STACKDEPTH"),
50        Instruction::new(input_stack_depth),
51    );
52
53    map.insert(String::from("OUTPUT.FLUSH"), Instruction::new(output_flush));
54    map.insert(String::from("OUTPUT.WRITE"), Instruction::new(output_write));
55    map.insert(
56        String::from("OUTPUT.STACKDEPTH"),
57        Instruction::new(output_stack_depth),
58    );
59}
60
61/////////////////////////////////////// INPUT //////////////////////////////////////////
62
63/// INPUT.AVAILABLE: This instruction pushes true to the BOOLEAN stack if the input
64/// stack is not empty and false otherwise.
65pub fn input_available(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
66    if push_state.input_stack.size() > 0 {
67        push_state.bool_stack.push(true);
68    } else {
69        push_state.bool_stack.push(false);
70    }
71}
72
73/// INPUT.FLUSH: Empties the INPUT stack.
74pub fn input_flush(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
75    push_state.input_stack.flush();
76}
77
78/// INPUT.GET: Pushes the nth bit of the first element of the FIFO queue to the
79/// BOOLEAN stack. The index n is taken from the INTEGER stack.
80pub fn input_get(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
81    if let Some(index) = push_state.int_stack.pop() {
82        let input_size = push_state.input_stack.size();
83        if input_size > 0 {
84            if let Some(input) = push_state.input_stack.peek_oldest() {
85                let list_index =
86                    i32::max(i32::min(input.body.values.len() as i32 - 1, index), 0) as usize;
87                push_state.bool_stack.push(input.body.values[list_index]);
88            }
89        }
90    }
91}
92
93/// INPUT.NEXT: Removes the first element of the input FIFO queue.
94pub fn input_next(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
95    push_state.input_stack.pop();
96}
97
98/// INPUT.READ: This instruction reads the input stack as a FIFO queue. If non empty
99/// it pushes a copy of the bottom item to the BOOLVECTOR stack.
100pub fn input_read(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
101    let input_size = push_state.input_stack.size();
102    if input_size > 0 {
103        if let Some(input) = push_state.input_stack.copy_oldest() {
104            push_state.bool_vector_stack.push(input.body);
105            push_state.int_vector_stack.push(input.header);
106        }
107    }
108}
109
110/// INPUT.STACKDEPTH: Pushes the stack depth onto the INTEGER stack.
111pub fn input_stack_depth(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
112    push_state
113        .int_stack
114        .push(push_state.input_stack.size() as i32);
115}
116
117/////////////////////////////////////// OUTPUT /////////////////////////////////////////
118
119/// OUTPUT.FLUSH: Empties the OUTPUT stack.
120pub fn output_flush(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
121    push_state.output_stack.flush();
122}
123
124/// OUTPUT.STACKDEPTH: Pushes the stack depth onto the INTEGER stack.
125pub fn output_stack_depth(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
126    push_state
127        .int_stack
128        .push(push_state.output_stack.size() as i32);
129}
130
131/// OUTPUT.WRITE: Creates a messages from the top items of the INTVECTOR stack (header) and
132/// the BOOLVECTOR stack (body) and pushes it to the OUTPUT stack.
133pub fn output_write(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
134    if let Some(body) = push_state.bool_vector_stack.pop() {
135        if let Some(header) = push_state.int_vector_stack.pop() {
136            push_state.output_stack.push(PushMessage::new(header, body));
137        }
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144    use crate::push::vector::BoolVector;
145
146    pub fn icache() -> InstructionCache {
147        InstructionCache::new(vec![])
148    }
149
150    #[test]
151    fn input_available_pushes_boolean() {
152        let mut test_state = PushState::new();
153        input_available(&mut test_state, &icache());
154        assert_eq!(test_state.bool_stack.pop().unwrap(), false);
155        test_state
156            .input_stack
157            .push(PushMessage::new(IntVector::new(vec![]), BoolVector::from_int_array(vec![0, 0, 0, 1])));
158        input_available(&mut test_state, &icache());
159        assert_eq!(test_state.bool_stack.pop().unwrap(), true);
160    }
161
162    #[test]
163    fn input_get_pushes_input_bit() {
164        let mut test_state = PushState::new();
165        test_state.int_stack.push(1);
166        test_state
167            .input_stack
168            .push(PushMessage::new(IntVector::new(vec![]), BoolVector::from_int_array(vec![0, 1, 0, 1])));
169        input_get(&mut test_state, &icache());
170        assert_eq!(test_state.bool_stack.pop().unwrap(), true);
171    }
172
173    #[test]
174    fn input_read_pushes_bottom_if_available() {
175        let mut test_state = PushState::new();
176        input_read(&mut test_state, &icache());
177
178        let header = IntVector::new(vec![]);
179        let body1 = BoolVector::from_int_array(vec![1, 1]);
180        let body2 = BoolVector::from_int_array(vec![0, 0]);
181        test_state.input_stack.push(PushMessage::new(header.clone(), body1));
182        test_state.input_stack.push(PushMessage::new(header.clone(), body2));
183
184        input_read(&mut test_state, &icache());
185        assert_eq!(
186            test_state.bool_vector_stack.pop().unwrap(),
187            BoolVector::from_int_array(vec![1, 1])
188        );
189    }
190
191    #[test]
192    fn output_write_pushes_top_item() {
193        let mut test_state = PushState::new();
194
195        let test_header = IntVector::new(vec![]);
196        test_state.int_vector_stack.push(test_header.clone());
197        test_state.int_vector_stack.push(test_header);
198        let test_vec1 = BoolVector::from_int_array(vec![1, 1]);
199        let test_vec2 = BoolVector::from_int_array(vec![0, 0]);
200        test_state.bool_vector_stack.push(test_vec1);
201        test_state.bool_vector_stack.push(test_vec2);
202
203        output_write(&mut test_state, &icache());
204        assert_eq!(
205            test_state.output_stack.pop().unwrap(),
206            PushMessage::new(IntVector::new(vec![]), BoolVector::from_int_array(vec![0, 0]))
207        );
208    }
209}