use crate::error::*;
use alloc::string::ToString;
use core::{ffi::CStr, mem};
pub fn str_from_bytes(bytes: &[u8]) -> Result<&str> {
CStr::from_bytes_until_nul(bytes)
.map_err(|e| Error::Malformed(e.to_string()))?
.to_str()
.map_err(|e| Error::Malformed(e.to_string()))
}
pub enum SkipPos {
Cur(usize),
Rel(usize),
}
pub struct ByteReader<'a> {
bytes: &'a [u8],
pos: usize,
rel_pos: Option<usize>,
}
impl<'a> ByteReader<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
Self {
bytes,
pos: 0,
rel_pos: None,
}
}
pub fn new_with_rel(bytes: &'a [u8], pos: usize) -> Self {
Self {
bytes,
pos: 0,
rel_pos: Some(pos),
}
}
pub fn bytes(&self) -> &'a [u8] {
self.bytes
}
pub fn remaining_bytes(&self) -> &'a [u8] {
&self.bytes[self.pos..]
}
pub fn bytes_at(&self, pos: usize) -> Result<&'a [u8]> {
self.bytes
.get(self.pos_to_rel(pos)..)
.ok_or(Error::InsufficientBuffer)
}
pub fn rel_pos(&self) -> Option<usize> {
self.rel_pos
}
pub fn pos_to_rel(&self, pos: usize) -> usize {
pos - self.rel_pos.unwrap_or(0)
}
pub fn skip(&mut self, pos: SkipPos) -> &mut Self {
match pos {
SkipPos::Cur(v) => self.pos += v,
SkipPos::Rel(v) => self.pos = self.pos_to_rel(v),
}
self
}
pub fn read<T>(&mut self) -> Result<&'a T>
where
T: FromBytes,
{
let res = T::from_bytes(
self.bytes
.get(self.pos..)
.ok_or(Error::InsufficientBuffer)?,
)?;
self.pos += mem::size_of::<T>();
Ok(res)
}
pub fn read_at<T>(&self, pos: usize) -> Result<&'a T>
where
T: FromBytes,
{
T::from_bytes(
self.bytes
.get(self.pos_to_rel(pos)..)
.ok_or(Error::InsufficientBuffer)?,
)
}
}
pub unsafe trait FromBytes: Copy {
fn from_bytes(bytes: &[u8]) -> Result<&Self>
where
Self: Sized,
{
if mem::size_of::<Self>() > 0 && bytes.len() < mem::size_of::<Self>() {
return Err(Error::InsufficientBuffer);
}
if bytes.as_ptr() as usize % mem::align_of::<Self>() != 0 {
return Err(Error::Misaligned);
}
Ok(unsafe { &*(bytes.as_ptr().cast()) })
}
}
#[macro_export]
macro_rules! impl_from_bytes {
($($struct_name:ident),+ $(,)?) => {
$(
unsafe impl FromBytes for $struct_name { }
)+
}
}
impl_from_bytes!(u8, u16, u32, u64);