use glyph_types::Value;
#[derive(Debug, Clone)]
pub struct Stack {
items: Vec<Value>,
max_size: usize,
}
impl Stack {
pub fn new(max_size: usize) -> Self {
Stack {
items: Vec::with_capacity(1024),
max_size,
}
}
pub fn push(&mut self, value: Value) -> Result<(), StackError> {
if self.items.len() >= self.max_size {
return Err(StackError::Overflow);
}
self.items.push(value);
Ok(())
}
pub fn pop(&mut self) -> Result<Value, StackError> {
self.items.pop().ok_or(StackError::Underflow)
}
pub fn peek(&self) -> Result<&Value, StackError> {
self.items.last().ok_or(StackError::Underflow)
}
pub fn peek_n(&self, n: usize) -> Result<&Value, StackError> {
let len = self.items.len();
if n >= len {
return Err(StackError::Underflow);
}
Ok(&self.items[len - n - 1])
}
pub fn dup(&mut self) -> Result<(), StackError> {
let value = self.peek()?.clone();
self.push(value)
}
pub fn swap(&mut self) -> Result<(), StackError> {
let len = self.items.len();
if len < 2 {
return Err(StackError::Underflow);
}
self.items.swap(len - 1, len - 2);
Ok(())
}
pub fn depth(&self) -> usize {
self.items.len()
}
pub fn clear(&mut self) {
self.items.clear();
}
pub fn slice_from(&self, bp: usize) -> &[Value] {
&self.items[bp..]
}
pub fn pop_n(&mut self, n: usize) -> Result<Vec<Value>, StackError> {
if self.items.len() < n {
return Err(StackError::Underflow);
}
let split_at = self.items.len() - n;
Ok(self.items.split_off(split_at))
}
pub fn truncate(&mut self, depth: usize) {
self.items.truncate(depth);
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum StackError {
Overflow,
Underflow,
}
impl std::fmt::Display for StackError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
StackError::Overflow => write!(f, "Stack overflow"),
StackError::Underflow => write!(f, "Stack underflow"),
}
}
}
impl std::error::Error for StackError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_stack_operations() {
let mut stack = Stack::new(100);
stack.push(Value::Int(42)).unwrap();
stack.push(Value::Str("hello".to_string())).unwrap();
assert_eq!(stack.depth(), 2);
assert_eq!(stack.pop().unwrap(), Value::Str("hello".to_string()));
assert_eq!(stack.pop().unwrap(), Value::Int(42));
assert!(matches!(stack.pop(), Err(StackError::Underflow)));
}
#[test]
fn test_stack_overflow() {
let mut stack = Stack::new(2);
stack.push(Value::Int(1)).unwrap();
stack.push(Value::Int(2)).unwrap();
assert!(matches!(
stack.push(Value::Int(3)),
Err(StackError::Overflow)
));
}
#[test]
fn test_dup_swap() {
let mut stack = Stack::new(100);
stack.push(Value::Int(1)).unwrap();
stack.push(Value::Int(2)).unwrap();
stack.dup().unwrap();
assert_eq!(stack.depth(), 3);
assert_eq!(stack.peek().unwrap(), &Value::Int(2));
stack.pop().unwrap(); stack.swap().unwrap();
assert_eq!(stack.pop().unwrap(), Value::Int(1));
assert_eq!(stack.pop().unwrap(), Value::Int(2));
}
}