use crate::{
deserializer::{
constants::ARRAY, consumed::Consumed, number::read_unsigned_int, read::read_exact_bytes,
},
error::{Result, TypedStreamError},
};
use alloc::{vec, vec::Vec};
#[derive(Debug, Clone, PartialEq)]
pub enum Type<'a> {
Utf8String,
EmbeddedData,
Object,
SignedInt,
UnsignedInt,
Float,
Double,
String(&'a str),
Array(usize),
Unknown(u8),
}
impl<'a> Type<'a> {
#[inline]
pub(crate) fn from_byte(byte: u8) -> Self {
match byte {
0x40 => Self::Object,
0x2B => Self::Utf8String,
0x2A => Self::EmbeddedData,
0x66 => Self::Float,
0x64 => Self::Double,
0x63 | 0x69 | 0x6c | 0x71 | 0x73 => Self::SignedInt,
0x43 | 0x49 | 0x4c | 0x51 | 0x53 => Self::UnsignedInt,
other => Self::Unknown(other),
}
}
#[inline]
pub(crate) fn new_string(str: &'a str) -> Self {
Self::String(str)
}
pub(crate) fn get_array_length(types: &'_ [u8]) -> Option<Vec<Type<'_>>> {
if types.first() == Some(&0x5b) {
let len =
types[1..]
.iter()
.take_while(|a| a.is_ascii_digit())
.fold(None, |acc, ch| {
char::from_u32(u32::from(*ch))?
.to_digit(10)
.map(|b| acc.unwrap_or(0) * 10 + b)
})?;
return Some(vec![Type::Array(len as usize)]);
}
None
}
pub(crate) fn read_new_type(data: &'_ [u8]) -> Result<Consumed<Vec<Type<'_>>>> {
let type_length = read_unsigned_int(data)?;
let type_bytes = read_exact_bytes(
&data[type_length.bytes_consumed..],
type_length.value as usize,
)?;
if type_bytes.first() == Some(&ARRAY) {
return Ok(Consumed::new(
Type::get_array_length(type_bytes).ok_or(TypedStreamError::InvalidArray(0))?,
type_length.bytes_consumed + type_bytes.len(),
));
}
Ok(Consumed::new(
type_bytes.iter().copied().map(Type::from_byte).collect(),
type_length.bytes_consumed + type_bytes.len(),
))
}
}