use std::any::Any;
use anyhow::{bail, Result};
use crate::types::{Deserializable, Field};
pub trait Readable: Sized {
fn read(reader: &mut Deserialize) -> Result<Self>;
}
impl Readable for String {
fn read(reader: &mut Deserialize) -> Result<Self> {
match reader.buf.iter().position(|&byte| byte == 0) {
Some(pos) => {
let string = str::from_utf8(&reader.buf[..pos])?.to_string();
reader.advance(pos + 1);
Ok(string)
}
None => {
bail!("unterminated c-string")
}
}
}
}
impl Readable for u8 {
fn read(reader: &mut Deserialize) -> Result<Self> {
let bytes = reader.read_bytes(1)?;
Ok(u8::from_le_bytes(bytes.try_into()?))
}
}
impl Readable for u16 {
fn read(reader: &mut Deserialize) -> Result<Self> {
let bytes = reader.read_bytes(2)?;
Ok(u16::from_le_bytes(bytes.try_into()?))
}
}
impl Readable for u32 {
fn read(reader: &mut Deserialize) -> Result<Self> {
let bytes = reader.read_bytes(4)?;
Ok(u32::from_le_bytes(bytes.try_into()?))
}
}
impl Readable for u64 {
fn read(reader: &mut Deserialize) -> Result<Self> {
let bytes = reader.read_bytes(8)?;
Ok(u64::from_le_bytes(bytes.try_into()?))
}
}
impl Readable for u128 {
fn read(reader: &mut Deserialize) -> Result<Self> {
let bytes = reader.read_bytes(16)?;
Ok(u128::from_le_bytes(bytes.try_into()?))
}
}
impl<T: Deserializable> Readable for T {
fn read(reader: &mut Deserialize) -> Result<Self> {
let structure = T::get_structure();
let mut fields = Vec::new();
for i in 0..structure.fields.len() {
let field: Box<dyn Any> = match structure.fields.get(&i) {
Some(field) => match field {
Field::String => Box::new(reader.read::<String>()?),
Field::U8 => Box::new(reader.read::<u8>()?),
Field::U16 => Box::new(reader.read::<u16>()?),
Field::U32 => Box::new(reader.read::<u32>()?),
Field::U64 => Box::new(reader.read::<u64>()?),
Field::U128 => Box::new(reader.read::<u128>()?),
Field::Struct => Box::new(reader.read::<T>()?),
Field::Vector => Box::new(reader.read::<Vec<T>>()?),
},
None => bail!("field index {} not found", i),
};
fields.push(field);
}
T::construct(fields)
}
}
impl<T: Readable> Readable for Vec<T> {
fn read(reader: &mut Deserialize) -> Result<Self> {
let size = reader.read::<usize>()?;
let mut vec: Vec<T> = Vec::with_capacity(size);
for _ in 0..size {
vec.push(reader.read::<T>()?);
}
Ok(vec)
}
}
impl Readable for usize {
fn read(reader: &mut Deserialize) -> Result<Self> {
let size = match reader.arch {
Some(arch) => match arch {
0 => 4, 1 => 8, _ => bail!("invalid architecture {}", arch),
},
None => bail!("no architecture specified"),
};
let bytes = reader.read_bytes(size)?;
let value = match size {
4 => {
let arr: [u8; 4] = bytes.try_into()?;
u32::from_le_bytes(arr) as u64
}
8 => {
let arr: [u8; 8] = bytes.try_into()?;
u64::from_le_bytes(arr)
}
_ => bail!("unsupported size: {}", size),
};
let usize_val =
usize::try_from(value).map_err(|_| anyhow::anyhow!("value does not fit in usize"))?;
if usize::BITS < 64 && value > u32::MAX as u64 {
bail!("value does not fit in 32-bit usize");
}
Ok(usize_val)
}
}
pub struct Deserialize<'a> {
buf: &'a [u8],
arch: Option<u8>,
}
impl<'a> Deserialize<'a> {
pub fn new(buf: &'a [u8], header: &[u8], version: u16) -> Result<Self> {
Self { buf, arch: None }.init(header, version)
}
pub fn read<T: Readable>(&mut self) -> Result<T> {
T::read(self)
}
pub fn read_bytes(&mut self, bytes: usize) -> Result<&[u8]> {
if self.buf.len() < bytes {
bail!("not enough bytes")
}
let result = &self.buf[..bytes];
self.advance(bytes);
Ok(result)
}
fn advance(&mut self, len: usize) {
self.buf = &self.buf[len..];
}
fn assert_header(&mut self, header: &[u8]) -> Result<()> {
if !self.buf.starts_with(header) {
bail!("buffer does not start with header")
}
self.advance(header.len());
Ok(())
}
fn assert_version(&mut self, version: u16) -> Result<()> {
if self.read::<u16>()? != version {
bail!("version does not match")
}
Ok(())
}
fn read_arch(&mut self) -> Result<()> {
self.arch = Some(self.read::<u8>()?);
Ok(())
}
fn init(mut self, header: &[u8], version: u16) -> Result<Self> {
self.assert_header(header)?;
self.assert_version(version)?;
self.read_arch()?;
Ok(self)
}
}