#[cfg(test)]
mod tests;
use eyre::{ensure, Result};
use generic_array::{ArrayLength, GenericArray};
use std::io::{Read, Write};
use tinyvec::{Array, ArrayVec};
pub trait Binable: Sized {
fn decode_from(rdr: &mut impl Read) -> Result<Self>;
fn encode_into(&self, wtr: &mut impl Write) -> Result<()>;
}
macro_rules! impl_bin_prim {
($($type:ty),+ $(,)?) => {
$(
impl Binable for $type {
fn decode_from(rdr: &mut impl Read) -> Result<Self> {
let mut buf = [0u8; std::mem::size_of::<$type>()];
rdr.read_exact(&mut buf)?;
Ok(<$type>::from_le_bytes(buf))
}
fn encode_into(&self, wtr: &mut impl Write) -> Result<()> {
let bytes = self.to_le_bytes();
wtr.write_all(&bytes).map_err(|err| err.into())
}
}
)*
};
}
impl_bin_prim!(f32, f64, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
macro_rules! impl_bin_tuple {
($type1:ident $(, $types:ident)* $(,)?) => {
#[allow(non_snake_case)]
impl<$type1: Binable, $($types: Binable),*> Binable for ($type1, $($types),*) {
fn decode_from(rdr: &mut impl Read) -> Result<Self> {
Ok((
$type1::decode_from(rdr)?,
$($types::decode_from(rdr)?),*
))
}
fn encode_into(&self, wtr: &mut impl Write) -> Result<()> {
let ($type1, $($types),*) = self;
$type1.encode_into(wtr)?;
$($types.encode_into(wtr)?;)*
Ok(())
}
}
impl_bin_tuple!($($types),*);
};
() => {};
}
impl_bin_tuple!(T1, T2, T3, T4, T5, T6);
impl Binable for () {
fn decode_from(_rdr: &mut impl Read) -> Result<Self> {
Ok(())
}
fn encode_into(&self, _wtr: &mut impl Write) -> Result<()> {
Ok(())
}
}
impl<B: Binable> Binable for Option<B> {
fn decode_from(rdr: &mut impl Read) -> Result<Self> {
let is_some = u8::decode_from(rdr)? == 1;
Ok(if is_some {
Some(B::decode_from(rdr)?)
} else {
None
})
}
fn encode_into(&self, wtr: &mut impl Write) -> Result<()> {
match self {
Some(t) => {
1u8.encode_into(wtr)?;
t.encode_into(wtr)
}
None => 0u8.encode_into(wtr),
}
}
}
impl<B: Binable + Default, const N: usize> Binable for [B; N] {
fn decode_from(rdr: &mut impl Read) -> Result<Self> {
let mut barr = [0u8; N].map(|_| B::default());
for b in &mut barr {
*b = B::decode_from(rdr)?;
}
Ok(barr)
}
fn encode_into(&self, wtr: &mut impl Write) -> Result<()> {
self.iter().try_for_each(|b| b.encode_into(wtr))
}
}
impl<B: Binable + Default, N: ArrayLength> Binable for GenericArray<B, N> {
fn decode_from(rdr: &mut impl Read) -> Result<Self> {
let mut garr = Self::default();
for b in &mut garr {
*b = B::decode_from(rdr)?
}
Ok(garr)
}
fn encode_into(&self, wtr: &mut impl Write) -> Result<()> {
self.iter().try_for_each(|v| v.encode_into(wtr))
}
}
impl<B: Binable, A: Array<Item = B>> Binable for ArrayVec<A> {
fn decode_from(rdr: &mut impl Read) -> Result<Self> {
let len = u16::decode_from(rdr)?;
let mut av = Self::new();
for _ in 0..len {
ensure!(
av.try_push(B::decode_from(rdr)?).is_none(),
"failed to push to the ArrayVec: already full"
);
}
Ok(av)
}
fn encode_into(&self, wtr: &mut impl Write) -> Result<()> {
(self.len() as u16).encode_into(wtr)?;
self.iter().try_for_each(|v| v.encode_into(wtr))
}
}
impl<B: Binable> Binable for Vec<B> {
fn decode_from(rdr: &mut impl Read) -> Result<Self> {
let len = u16::decode_from(rdr)?;
let mut v = Vec::with_capacity(len as usize);
for _ in 0..len {
v.push(B::decode_from(rdr)?);
}
Ok(v)
}
fn encode_into(&self, wtr: &mut impl Write) -> Result<()> {
(self.len() as u16).encode_into(wtr)?;
self.iter().try_for_each(|v| v.encode_into(wtr))
}
}
#[macro_export]
macro_rules! impl_bin_fields {
($($field:tt),+) => {
#[inline]
fn decode_from(rdr: &mut impl ::std::io::prelude::Read) -> eyre::Result<Self> {
Ok(Self {
$($field: $crate::Binable::decode_from(rdr)?),+
})
}
#[inline]
fn encode_into(&self, wtr: &mut impl ::std::io::prelude::Write) -> eyre::Result<()> {
$(self.$field.encode_into(wtr)?;)+
Ok(())
}
};
}