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
61pub 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
73pub fn input_flush(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
75 push_state.input_stack.flush();
76}
77
78pub 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
93pub fn input_next(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
95 push_state.input_stack.pop();
96}
97
98pub 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
110pub 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
117pub fn output_flush(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
121 push_state.output_stack.flush();
122}
123
124pub 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
131pub 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}