use crate::Value;
use std::iter;
use std::mem;
use thiserror::Error;
#[derive(Debug, Error)]
#[error("tried to access out-of-bounds stack entry")]
pub struct StackError(());
#[derive(Debug, Clone)]
pub struct Stack {
stack: Vec<Value>,
stack_top: usize,
}
impl Stack {
pub const fn new() -> Self {
Self {
stack: Vec::new(),
stack_top: 0,
}
}
pub fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = Value>,
{
self.stack.extend(iter);
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
stack: Vec::with_capacity(capacity),
stack_top: 0,
}
}
pub fn clear(&mut self) {
self.stack.clear();
self.stack_top = 0;
}
#[inline]
pub fn peek(&mut self) -> Option<&Value> {
self.stack.last()
}
#[inline]
pub fn last(&self) -> Result<&Value, StackError> {
self.stack.last().ok_or_else(|| StackError(()))
}
pub fn at_offset(&self, offset: usize) -> Result<&Value, StackError> {
self.stack_top
.checked_add(offset)
.and_then(|n| self.stack.get(n))
.ok_or_else(|| StackError(()))
}
pub fn at_offset_from_top(&self, offset: usize) -> Result<&Value, StackError> {
match self
.stack
.len()
.checked_sub(offset)
.filter(|n| *n >= self.stack_top)
.and_then(|n| self.stack.get(n))
{
Some(value) => Ok(value),
None => Err(StackError(())),
}
}
pub fn at_offset_mut(&mut self, offset: usize) -> Result<&mut Value, StackError> {
let n = match self.stack_top.checked_add(offset) {
Some(n) => n,
None => return Err(StackError(())),
};
match self.stack.get_mut(n) {
Some(value) => Ok(value),
None => Err(StackError(())),
}
}
pub fn push<T>(&mut self, value: T)
where
Value: From<T>,
{
self.stack.push(Value::from(value));
}
pub fn pop(&mut self) -> Result<Value, StackError> {
if self.stack.len() == self.stack_top {
return Err(StackError(()));
}
self.stack.pop().ok_or_else(|| StackError(()))
}
pub fn popn(&mut self, count: usize) -> Result<(), StackError> {
drop(self.drain_stack_top(count)?);
Ok(())
}
pub fn is_empty(&self) -> bool {
self.stack.is_empty()
}
pub fn len(&self) -> usize {
self.stack.len()
}
pub fn iter(&self) -> impl Iterator<Item = &Value> + '_ {
self.stack.iter()
}
pub fn pop_sequence(&mut self, count: usize) -> Result<Vec<Value>, StackError> {
Ok(self.drain_stack_top(count)?.collect::<Vec<_>>())
}
pub(crate) fn drain_stack_top(
&mut self,
count: usize,
) -> Result<impl DoubleEndedIterator<Item = Value> + '_, StackError> {
match self.stack.len().checked_sub(count) {
Some(start) if start >= self.stack_top => Ok(self.stack.drain(start..)),
_ => Err(StackError(())),
}
}
pub(crate) fn swap_stack_top(&mut self, count: usize) -> Result<usize, StackError> {
match self.stack.len().checked_sub(count) {
Some(new_top) => Ok(mem::replace(&mut self.stack_top, new_top)),
None => Err(StackError(())),
}
}
pub(crate) fn check_stack_top(&self) -> Result<(), StackError> {
if self.stack.len() == self.stack_top {
return Ok(());
}
Err(StackError(()))
}
pub(crate) fn pop_stack_top(&mut self, stack_top: usize) -> Result<(), StackError> {
self.check_stack_top()?;
self.stack_top = stack_top;
Ok(())
}
}
impl iter::FromIterator<Value> for Stack {
fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
Self {
stack: iter.into_iter().collect(),
stack_top: 0,
}
}
}
impl From<Vec<Value>> for Stack {
fn from(stack: Vec<Value>) -> Self {
Self {
stack,
stack_top: 0,
}
}
}