use thiserror::Error;
use crate::enums::endian::Endian;
#[derive(Error, Debug, PartialEq)]
pub enum FromBytesError {
#[error("{0:?} trailing bytes were given")]
Trailing(usize),
}
pub trait FromBytes<const N: usize> {
fn from_bytes(bytes: [u8; N], endian: Endian) -> Self;
fn from_multiple_bytes(
bytes: &[u8],
endian: Endian,
) -> Result<impl Iterator<Item = Self>, FromBytesError>
where
Self: Sized,
{
match bytes.len() % N {
0 => {}
x => return Err(FromBytesError::Trailing(x)),
}
Ok(bytes
.chunks_exact(N)
.map(|x| x.try_into().unwrap())
.map(move |x| Self::from_bytes(x, endian)))
}
fn add_bytes(
bytes: &[u8],
endian: Endian,
numbers: &mut Vec<Self>,
) -> Result<(), FromBytesError>
where
Self: Sized,
{
match Self::from_multiple_bytes(bytes, endian) {
Ok(i) => {
numbers.extend(i);
Ok(())
}
Err(e @ FromBytesError::Trailing(x)) => {
numbers
.extend(Self::from_multiple_bytes(&bytes[0..bytes.len() - x], endian).unwrap());
Err(e)
}
}
}
}
macro_rules! implement_from_bytes {
($name:ident, $n:literal) => {
impl FromBytes<$n> for $name {
fn from_bytes(bytes: [u8; $n], endian: Endian) -> Self {
match endian {
Endian::Big => Self::from_be_bytes(bytes),
Endian::Little => Self::from_le_bytes(bytes),
}
}
}
};
}
implement_from_bytes!(u16, 2);
implement_from_bytes!(i16, 2);
implement_from_bytes!(u32, 4);
implement_from_bytes!(i32, 4);
implement_from_bytes!(f32, 4);
implement_from_bytes!(u64, 8);
implement_from_bytes!(i64, 8);
implement_from_bytes!(f64, 8);
#[cfg(test)]
mod tests {
use super::*;
use FromBytesError::Trailing;
#[test]
fn test_add_two_bytes() {
let mut v: Vec<u16> = Vec::new();
assert_eq!(
u16::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0, 100], Endian::Big, &mut v),
Err(Trailing(1))
);
assert_eq!(
u16::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0, 100], Endian::Little, &mut v),
Err(Trailing(1))
);
u16::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0], Endian::Big, &mut v).unwrap();
u16::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0], Endian::Little, &mut v).unwrap();
assert_eq!(
v.as_slice(),
&[258, 260, 2, 512, 513, 1025, 512, 2, 258, 260, 2, 512, 513, 1025, 512, 2]
);
}
#[test]
fn test_add_four_bytes() {
let mut v: Vec<u32> = Vec::new();
assert_eq!(
u32::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0, 100], Endian::Big, &mut v),
Err(Trailing(1))
);
assert_eq!(
u32::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0, 100], Endian::Little, &mut v),
Err(Trailing(1))
);
u32::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0], Endian::Big, &mut v).unwrap();
u32::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0], Endian::Little, &mut v).unwrap();
assert_eq!(
v.as_slice(),
&[16908548, 131584, 67174913, 131584, 16908548, 131584, 67174913, 131584]
);
}
#[test]
fn test_add_eight_bytes() {
let mut v: Vec<u64> = Vec::new();
assert_eq!(
u64::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0, 100], Endian::Big, &mut v),
Err(Trailing(1))
);
assert_eq!(
u64::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0, 100], Endian::Little, &mut v),
Err(Trailing(1))
);
u64::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0], Endian::Big, &mut v).unwrap();
u64::add_bytes(&[1, 2, 1, 4, 0, 2, 2, 0], Endian::Little, &mut v).unwrap();
assert_eq!(
v.as_slice(),
&[
72621660682977792,
565149043851777,
72621660682977792,
565149043851777
]
);
}
}