esoteric_vm/machine/stack/
mod.rs1pub mod stackoverflow;
6
7use std::{fmt, ptr};
8
9use stackoverflow::StackOverflow;
10
11use crate::utils::array_debug::DebugArray;
12
13#[derive(Clone)]
21pub struct Stack {
22 pub vec: Vec<u8>,
24}
25
26impl Default for Stack {
27 fn default() -> Self {
28 Self {
29 vec: Vec::with_capacity(4095),
30 }
31 }
32}
33
34impl Stack {
35 #[inline]
37 #[must_use]
38 pub fn total_space(&self) -> usize {
39 self.vec.capacity()
40 }
41 #[inline]
43 #[must_use]
44 pub fn used_space(&self) -> usize {
45 self.vec.len()
46 }
47 #[inline]
49 #[must_use]
50 #[allow(clippy::arithmetic_side_effects)]
51 pub fn space_left(&self) -> usize {
52 self.total_space() - self.used_space()
53 }
54
55 #[inline]
63 #[warn(warnings)]
64 pub unsafe fn set_used_space(&mut self, new_len: usize) {
65 unsafe {
67 self.vec.set_len(new_len);
68 }
69 }
70
71 pub fn push_byte(&mut self, byte: u8) -> Result<(), StackOverflow> {
77 if self.space_left() == 0 {
78 return Err(StackOverflow);
79 }
80 self.vec.push(byte);
81 Ok(())
82 }
83 pub fn pop_byte(&mut self) -> Option<u8> {
87 self.vec.pop()
88 }
89
90 pub fn push_bytes(&mut self, bytes: &[u8]) -> Result<(), StackOverflow> {
98 let len = self.used_space();
99 let bytes_len = bytes.len();
100
101 self.alloc(bytes_len)?;
102
103 let dst = unsafe { self.vec.as_mut_ptr().add(len) };
105
106 unsafe {
108 ptr::copy(bytes.as_ptr(), dst, bytes_len);
109 }
110
111 Ok(())
112 }
113
114 pub fn alloc(&mut self, bytes: usize) -> Result<(), StackOverflow> {
120 if bytes > self.space_left() {
121 return Err(StackOverflow);
122 }
123 for _ in 0..bytes {
124 self.vec.push(0);
125 }
126 Ok(())
127 }
128 pub unsafe fn dealloc(&mut self, bytes: usize) -> Result<(), StackOverflow> {
141 let len = self.used_space();
142 if bytes > len {
143 Err(StackOverflow)
144 } else {
145 #[allow(clippy::arithmetic_side_effects)]
146 let new_len = self.used_space() - bytes;
147
148 unsafe {
150 self.set_used_space(new_len);
151 }
152
153 Ok(())
154 }
155 }
156 pub fn pop_u16(&mut self) -> Option<u16> {
158 let mut array = [0, 0];
159
160 array[1] = self.pop_byte()?;
161 array[0] = self.pop_byte()?;
162
163 Some(u16::from_be_bytes(array))
164 }
165 pub fn pop_u32(&mut self) -> Option<u32> {
167 let mut array = [0, 0, 0, 0];
168
169 array[3] = self.pop_byte()?;
170 array[2] = self.pop_byte()?;
171 array[1] = self.pop_byte()?;
172 array[0] = self.pop_byte()?;
173
174 Some(u32::from_be_bytes(array))
175 }
176 pub fn pop_u64(&mut self) -> Option<u64> {
178 let mut array = [0, 0, 0, 0, 0, 0, 0, 0];
179
180 array[7] = self.pop_byte()?;
181 array[6] = self.pop_byte()?;
182 array[5] = self.pop_byte()?;
183 array[4] = self.pop_byte()?;
184 array[3] = self.pop_byte()?;
185 array[2] = self.pop_byte()?;
186 array[1] = self.pop_byte()?;
187 array[0] = self.pop_byte()?;
188
189 Some(u64::from_be_bytes(array))
190 }
191}
192
193impl fmt::Debug for Stack {
194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195 #[allow(clippy::indexing_slicing)]
196 let last = self.used_space().checked_sub(16).map(|n| &self.vec[n..]);
197
198 f.write_fmt(format_args!(
199 "{}/{} {:?}",
200 self.used_space(),
201 self.total_space(),
202 &DebugArray::debug(self.vec.get(0..16).unwrap_or(&[]), true, last,)
203 ))
204 }
205}