pub mod stackoverflow;
use std::{fmt, ptr};
use stackoverflow::StackOverflow;
use crate::utils::array_debug::DebugArray;
#[derive(Clone)]
pub struct Stack {
pub vec: Vec<u8>,
}
impl Default for Stack {
fn default() -> Self {
Self {
vec: Vec::with_capacity(4095),
}
}
}
impl Stack {
#[inline]
#[must_use]
pub fn total_space(&self) -> usize {
self.vec.capacity()
}
#[inline]
#[must_use]
pub fn used_space(&self) -> usize {
self.vec.len()
}
#[inline]
#[must_use]
#[allow(clippy::arithmetic_side_effects)]
pub fn space_left(&self) -> usize {
self.total_space() - self.used_space()
}
#[inline]
#[warn(warnings)]
pub unsafe fn set_used_space(&mut self, new_len: usize) {
unsafe {
self.vec.set_len(new_len);
}
}
pub fn push_byte(&mut self, byte: u8) -> Result<(), StackOverflow> {
if self.space_left() == 0 {
return Err(StackOverflow);
}
self.vec.push(byte);
Ok(())
}
pub fn pop_byte(&mut self) -> Option<u8> {
self.vec.pop()
}
pub fn push_bytes(&mut self, bytes: &[u8]) -> Result<(), StackOverflow> {
let len = self.used_space();
let bytes_len = bytes.len();
self.alloc(bytes_len)?;
let dst = unsafe { self.vec.as_mut_ptr().add(len) };
unsafe {
ptr::copy(bytes.as_ptr(), dst, bytes_len);
}
Ok(())
}
pub fn alloc(&mut self, bytes: usize) -> Result<(), StackOverflow> {
if bytes > self.space_left() {
return Err(StackOverflow);
}
for _ in 0..bytes {
self.vec.push(0);
}
Ok(())
}
pub unsafe fn dealloc(&mut self, bytes: usize) -> Result<(), StackOverflow> {
let len = self.used_space();
if bytes > len {
Err(StackOverflow)
} else {
#[allow(clippy::arithmetic_side_effects)]
let new_len = self.used_space() - bytes;
unsafe {
self.set_used_space(new_len);
}
Ok(())
}
}
pub fn pop_u16(&mut self) -> Option<u16> {
let mut array = [0, 0];
array[1] = self.pop_byte()?;
array[0] = self.pop_byte()?;
Some(u16::from_be_bytes(array))
}
pub fn pop_u32(&mut self) -> Option<u32> {
let mut array = [0, 0, 0, 0];
array[3] = self.pop_byte()?;
array[2] = self.pop_byte()?;
array[1] = self.pop_byte()?;
array[0] = self.pop_byte()?;
Some(u32::from_be_bytes(array))
}
pub fn pop_u64(&mut self) -> Option<u64> {
let mut array = [0, 0, 0, 0, 0, 0, 0, 0];
array[7] = self.pop_byte()?;
array[6] = self.pop_byte()?;
array[5] = self.pop_byte()?;
array[4] = self.pop_byte()?;
array[3] = self.pop_byte()?;
array[2] = self.pop_byte()?;
array[1] = self.pop_byte()?;
array[0] = self.pop_byte()?;
Some(u64::from_be_bytes(array))
}
}
impl fmt::Debug for Stack {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
#[allow(clippy::indexing_slicing)]
let last = self.used_space().checked_sub(16).map(|n| &self.vec[n..]);
f.write_fmt(format_args!(
"{}/{} {:?}",
self.used_space(),
self.total_space(),
&DebugArray::debug(self.vec.get(0..16).unwrap_or(&[]), true, last,)
))
}
}