use std::{array::TryFromSliceError, fmt::Debug};
use mini_udp_derive::derive_for;
use thiserror::Error;
pub trait StaticByteRepr {
const BYTE_LEN: usize;
}
pub trait ByteRepr: Debug + Sized {
const MIN_BYTE_LEN: usize;
const MAX_BYTE_LEN: usize;
fn byte_len(&self) -> usize;
fn write_to_bytes(&self, bytes: &mut [u8]) -> Result<(), ByteReprError>;
fn from_bytes(bytes: &[u8]) -> Result<Self, ByteReprError>;
}
pub trait ByteReprExt: ByteRepr {
fn write_many<'a, I>(values: I, bytes: &mut [u8]) -> (usize, usize)
where
I: IntoIterator<Item = &'a Self>,
Self: 'a,
{
let mut ptr = 0;
let mut i = 0;
for v in values {
if bytes.len() - ptr < v.byte_len() || v.write_to_bytes(&mut bytes[ptr..]).is_err() {
return (i, ptr);
}
ptr += v.byte_len();
i += 1;
}
(i, ptr)
}
fn read_many(bytes: &[u8]) -> Result<(Vec<Self>, usize), ByteReprError> {
let mut ptr = 0;
let mut out = vec![];
while bytes.len() > ptr && bytes.len() - ptr >= Self::MIN_BYTE_LEN {
let v = Self::from_bytes(&bytes[ptr..])?;
ptr += v.byte_len();
out.push(v);
}
Ok((out, ptr))
}
}
impl<T: ByteRepr> ByteReprExt for T {}
#[derive(Error, Debug)]
pub enum ByteReprError {
#[error("The provided byte slice is too short")]
SliceTooShort,
#[error("Encountered an unexpected value")]
InvalidValue,
}
impl From<TryFromSliceError> for ByteReprError {
fn from(_value: TryFromSliceError) -> Self {
Self::SliceTooShort
}
}
derive_for!(());
derive_for!(bool);
derive_for!(u8);
derive_for!(i8);
derive_for!(u16);
derive_for!(i16);
derive_for!(u32);
derive_for!(i32);
derive_for!(f32);
derive_for!(u64);
derive_for!(i64);
derive_for!(f64);
derive_for!(usize);
derive_for!(isize);
derive_for!(u128);
derive_for!(i128);
derive_for!(String);
derive_for!(std::borrow::Cow<'a, T>, <'a, T> where T: ByteRepr + ToOwned<Owned = T>);
derive_for!(Option<T>, <T> where T: ByteRepr);
derive_for!([T; N], <T, const N: usize> where T: ByteRepr + Default);
derive_for!(Vec<T>, <T> where T: ByteRepr);