use core::marker::PhantomData;
use crate::{EpeeError, Stack, io::*};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Type {
Int64 = 1,
Int32 = 2,
Int16 = 3,
Int8 = 4,
Uint64 = 5,
Uint32 = 6,
Uint16 = 7,
Uint8 = 8,
Double = 9,
String = 10,
Bool = 11,
Object = 12,
}
#[derive(Clone, Copy, Debug)]
#[repr(u8)]
pub enum Array {
Unit = 0,
Array = 1 << 7,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) enum TypeOrEntry {
Type(Type),
Entry,
}
impl Type {
pub fn read<'encoding>(reader: &mut impl BytesLike<'encoding>) -> Result<(Self, u64), EpeeError> {
let kind = reader.read_byte()?;
#[expect(clippy::as_conversions)]
let array = kind & (Array::Array as u8);
#[expect(clippy::as_conversions)]
let kind = kind & (!(Array::Array as u8));
let kind = match kind {
1 => Type::Int64,
2 => Type::Int32,
3 => Type::Int16,
4 => Type::Int8,
5 => Type::Uint64,
6 => Type::Uint32,
7 => Type::Uint16,
8 => Type::Uint8,
9 => Type::Double,
10 => Type::String,
11 => Type::Bool,
12 => Type::Object,
_ => Err(EpeeError::UnrecognizedType)?,
};
let len = if array != 0 { read_varint(reader)? } else { 1 };
Ok((kind, len))
}
}
fn read_key<'encoding, B: BytesLike<'encoding>>(
reader: &mut B,
) -> Result<String<'encoding, B>, EpeeError> {
let len = usize::from(reader.read_byte()?);
if len == 0 {
Err(EpeeError::EmptyKey)?;
}
let (len, bytes) = reader.read_bytes(len)?;
Ok(String { len, bytes, _encoding: PhantomData })
}
pub(crate) enum SingleStepResult<'encoding, B: BytesLike<'encoding>> {
Object { fields: usize },
Entry { key: String<'encoding, B>, kind: Type, len: usize },
Unit,
}
impl Stack {
pub(crate) fn single_step<'encoding, B: BytesLike<'encoding>>(
&mut self,
encoding: &mut B,
) -> Result<Option<SingleStepResult<'encoding, B>>, EpeeError> {
let Some(kind) = self.pop() else {
return Ok(None);
};
match kind {
TypeOrEntry::Type(Type::Int64) => {
encoding.advance::<{ core::mem::size_of::<i64>() }>()?;
}
TypeOrEntry::Type(Type::Int32) => {
encoding.advance::<{ core::mem::size_of::<i32>() }>()?;
}
TypeOrEntry::Type(Type::Int16) => {
encoding.advance::<{ core::mem::size_of::<i16>() }>()?;
}
TypeOrEntry::Type(Type::Int8) => {
encoding.advance::<{ core::mem::size_of::<i8>() }>()?;
}
TypeOrEntry::Type(Type::Uint64) => {
encoding.advance::<{ core::mem::size_of::<u64>() }>()?;
}
TypeOrEntry::Type(Type::Uint32) => {
encoding.advance::<{ core::mem::size_of::<u32>() }>()?;
}
TypeOrEntry::Type(Type::Uint16) => {
encoding.advance::<{ core::mem::size_of::<u16>() }>()?;
}
TypeOrEntry::Type(Type::Uint8) => {
encoding.advance::<{ core::mem::size_of::<u8>() }>()?;
}
TypeOrEntry::Type(Type::Double) => {
encoding.advance::<{ core::mem::size_of::<f64>() }>()?;
}
TypeOrEntry::Type(Type::String) => {
read_str(encoding)?;
}
TypeOrEntry::Type(Type::Bool) => {
encoding.advance::<{ core::mem::size_of::<bool>() }>()?;
}
TypeOrEntry::Type(Type::Object) => {
let fields = read_varint(encoding)?;
let fields = usize::try_from(fields).map_err(|_| EpeeError::Short(usize::MAX))?;
self.push(TypeOrEntry::Entry, fields)?;
return Ok(Some(SingleStepResult::Object { fields }));
}
TypeOrEntry::Entry => {
let key = read_key(encoding)?;
let (kind, len) = Type::read(encoding)?;
let len = usize::try_from(len).map_err(|_| EpeeError::Short(usize::MAX))?;
self.push(TypeOrEntry::Type(kind), len)?;
return Ok(Some(SingleStepResult::Entry { key, kind, len }));
}
}
Ok(Some(SingleStepResult::Unit))
}
pub(crate) fn step<'encoding, B: BytesLike<'encoding>>(
&mut self,
encoding: &mut B,
) -> Result<Option<()>, EpeeError> {
let Some((_kind, len)) = self.peek() else { return Ok(None) };
let current_stack_depth = self.depth();
let stop_at_stack_depth = if len.get() > 1 {
current_stack_depth
} else {
current_stack_depth - 1
};
while {
self.single_step(encoding)?;
self.depth() != stop_at_stack_depth
} {}
Ok(Some(()))
}
}