#[cfg(test)]
mod tests;
use std::convert::TryInto;
use std::mem;
use crate::error::Error;
use crate::take_bytes::TakeBytes;
pub trait FromBytes
where
Self: Sized,
{
fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error>;
}
impl FromBytes for bool {
fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
let val: u8 = FromBytes::from_bytes(source)?;
Ok(val != 0)
}
}
macro_rules! impl_from_bytes_for_primitive {
($type:ty) => {
impl FromBytes for $type {
fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
let mut buf = [0; mem::size_of::<$type>()];
source.take_bytes(&mut buf)?;
Ok(<$type>::from_be_bytes(buf))
}
}
};
}
impl_from_bytes_for_primitive!(i8);
impl_from_bytes_for_primitive!(i16);
impl_from_bytes_for_primitive!(i32);
impl_from_bytes_for_primitive!(i64);
impl_from_bytes_for_primitive!(u8);
impl_from_bytes_for_primitive!(u16);
impl_from_bytes_for_primitive!(u32);
impl_from_bytes_for_primitive!(u64);
impl_from_bytes_for_primitive!(f32);
impl_from_bytes_for_primitive!(f64);
impl FromBytes for usize {
fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
let mut buf = [0; mem::size_of::<u64>()];
source.take_bytes(&mut buf)?;
Ok(u64::from_be_bytes(buf) as usize)
}
}
impl FromBytes for char {
fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
let n: u32 = FromBytes::from_bytes(source)?;
char::from_u32(n).ok_or_else(|| Error::InvalidChar(n))
}
}
impl<FB: FromBytes, const COUNT: usize> FromBytes for [FB; COUNT] {
fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
let mut vec = vec![];
for _i in 0..COUNT {
vec.push(FromBytes::from_bytes(source)?);
}
Ok(vec
.try_into()
.unwrap_or_else(|_| panic!("should never be reached")))
}
}
impl<FB: FromBytes> FromBytes for Vec<FB> {
fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
let len = usize::from_bytes(source)?;
let mut vec = Vec::with_capacity(len);
for _ in 0..len {
vec.push(FromBytes::from_bytes(source)?);
}
Ok(vec)
}
}
impl FromBytes for String {
fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
let len = usize::from_bytes(source)?;
let mut vec = vec![0; len];
source.take_bytes(&mut vec)?;
String::from_utf8(vec).map_err(Error::InvalidString)
}
}
impl<T: FromBytes> FromBytes for Option<T> {
fn from_bytes<TB: TakeBytes>(source: &mut TB) -> Result<Self, Error> {
let n: u8 = FromBytes::from_bytes(source)?;
if n == 0 {
Ok(None)
} else {
Ok(Some(FromBytes::from_bytes(source)?))
}
}
}
impl FromBytes for () {
fn from_bytes<TB: TakeBytes>(_source: &mut TB) -> Result<Self, Error> {
Ok(())
}
}