binable 0.1.0

Minimal library for encoding (decoding) types to (from) binary.
Documentation
#[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(())
        }
    };
}