use crate::{State, Stack};
#[derive(Debug)]
struct PackedStates<const ONE_FOURTH_OF_MAX_DEPTH: usize>([u8; ONE_FOURTH_OF_MAX_DEPTH]);
impl<const ONE_FOURTH_OF_MAX_DEPTH: usize> PackedStates<ONE_FOURTH_OF_MAX_DEPTH> {
#[inline(always)]
fn get(&self, i: usize) -> State {
let mut entry = self.0[i >> 2];
entry >>= (i & 0b11) * 2;
entry &= 0b11;
match entry {
0 => State::Object,
1 => State::Array,
2 => State::Unknown,
3 => panic!("`PackedStates` was written to with a non-existent `State`"),
_ => unreachable!("masked by 0b11"),
}
}
#[inline(always)]
fn set(&mut self, i: usize, kind: State) {
let two_bits = match kind {
State::Object => 0,
State::Array => 1,
State::Unknown => 2,
};
let shift = (i & 0b11) * 2;
self.0[i >> 2] &= !(0b00000011 << shift);
self.0[i >> 2] |= two_bits << shift;
}
}
#[derive(Clone, Copy, Debug)]
#[allow(dead_code)]
pub enum StackError {
StackTooDeep,
}
#[derive(Debug)]
pub struct ConstStack<const ONE_FOURTH_OF_MAX_DEPTH: usize> {
items: PackedStates<{ ONE_FOURTH_OF_MAX_DEPTH }>,
depth: usize,
}
impl<const ONE_FOURTH_OF_MAX_DEPTH: usize> Stack for ConstStack<ONE_FOURTH_OF_MAX_DEPTH> {
type Error = StackError;
#[inline(always)]
fn empty() -> Self {
Self { items: PackedStates([0; ONE_FOURTH_OF_MAX_DEPTH]), depth: 0 }
}
#[inline(always)]
fn depth(&self) -> usize {
self.depth
}
#[inline(always)]
fn peek(&self) -> Option<State> {
let i = self.depth.checked_sub(1)?;
Some(self.items.get(i))
}
#[inline(always)]
fn pop(&mut self) -> Option<State> {
let i = self.depth.checked_sub(1)?;
self.depth -= 1;
Some(self.items.get(i))
}
#[inline(always)]
fn push(&mut self, state: State) -> Result<(), StackError> {
if self.depth == (4 * ONE_FOURTH_OF_MAX_DEPTH) {
Err(StackError::StackTooDeep)?;
}
self.items.set(self.depth, state);
self.depth += 1;
Ok(())
}
}