use std::{io, mem::size_of, string::FromUtf8Error};
use thiserror::Error;
use super::{bytereader::ByteReaderError, bytewriter::ByteWriterError};
#[derive(PartialEq, Clone, Copy, Default)]
pub enum Endianness {
#[default]
Little,
Big,
}
trait TInt {}
impl !TInt for String {}
impl !TInt for &str {}
impl TInt for usize {}
impl TInt for u8 {}
impl TInt for u16 {}
impl TInt for u32 {}
impl TInt for u64 {}
impl TInt for u128 {}
impl TInt for isize {}
impl TInt for i8 {}
impl TInt for i16 {}
impl TInt for i32 {}
impl TInt for i64 {}
impl TInt for i128 {}
pub trait TryFromBytes: Sized {
type Bytes;
type Error = TryFromBytesError;
fn try_from_bytes(
bytes: Self::Bytes,
endianness: Endianness,
) -> Result<(Self, usize), Self::Error>;
}
pub trait ToBytes: Sized {
type Bytes;
fn to_bytes(&self, endianness: Endianness) -> Self::Bytes;
}
#[derive(Debug, Error)]
pub enum TryFromBytesError {
#[error("utf-8 error: {0}")]
StringFromBytes(FromUtf8Error),
#[error("array from slice error")]
ArrayFromSlice,
#[error("out of bounds")]
OutOfBounds,
}
impl From<FromUtf8Error> for TryFromBytesError {
fn from(err: FromUtf8Error) -> Self {
Self::StringFromBytes(err)
}
}
impl TryFromBytes for String {
type Bytes = Vec<u8>;
type Error = TryFromBytesError;
fn try_from_bytes(bytes: Self::Bytes, _: Endianness) -> Result<(Self, usize), Self::Error> {
let mut vec: Vec<u8> = Vec::new();
for byte in bytes {
if byte == 0x00 {
break;
}
vec.push(byte);
}
let res = String::from_utf8(vec)?;
let len = res.len();
Ok((res, len + 1))
}
}
impl<T: num_traits::FromBytes<Bytes = [u8; size_of::<T>()]> + TInt> TryFromBytes for T
where
<T as num_traits::FromBytes>::Bytes: Sized + for<'a> TryFrom<&'a [u8]>,
{
type Bytes = Vec<u8>;
type Error = TryFromBytesError;
fn try_from_bytes(
bytes: <Self as TryFromBytes>::Bytes,
endianness: Endianness,
) -> Result<(Self, usize), Self::Error> {
let size = size_of::<T>();
if bytes.len() < size {
return Err(TryFromBytesError::OutOfBounds);
}
let array_bytes: &[u8; size_of::<T>()] = &bytes.as_slice()[..size_of::<T>()]
.try_into()
.or(Err(TryFromBytesError::ArrayFromSlice))?;
Ok((
match endianness {
Endianness::Big => Self::from_be_bytes(array_bytes),
Endianness::Little => Self::from_le_bytes(array_bytes),
},
size_of::<T>(),
))
}
}
impl<T: num_traits::ToBytes + TInt> ToBytes for T
where
<T as num_traits::ToBytes>::Bytes: Sized + Into<Vec<u8>>,
{
type Bytes = Vec<u8>;
fn to_bytes(&self, endianness: Endianness) -> Self::Bytes {
match endianness {
Endianness::Big => self.to_be_bytes().into(),
Endianness::Little => self.to_le_bytes().into(),
}
}
}
impl ToBytes for String {
type Bytes = Vec<u8>;
fn to_bytes(&self, _: Endianness) -> Self::Bytes {
(self.to_owned() + "\0").to_owned().into()
}
}
#[derive(Debug)]
pub enum ByteError {
ByteReaderError(ByteReaderError),
ByteWriterError(ByteWriterError),
IOError(io::Error),
}
impl From<ByteReaderError> for ByteError {
fn from(err: ByteReaderError) -> Self {
Self::ByteReaderError(err)
}
}
impl From<ByteWriterError> for ByteError {
fn from(err: ByteWriterError) -> Self {
Self::ByteWriterError(err)
}
}
impl From<io::Error> for ByteError {
fn from(err: io::Error) -> Self {
Self::IOError(err)
}
}