recode 0.5.0-alpha.3

Reusable encoding/decoding constructs for Rust
Documentation
use crate::{
    bytes::{Buf, BufMut, BytesMut},
    util::EncoderExt,
    Decoder,
    Encoder,
    RawDecoder,
};

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TryFromIntError(pub(crate) ());

impl From<std::num::TryFromIntError> for TryFromIntError {
    #[inline]
    fn from(_: std::num::TryFromIntError) -> TryFromIntError {
        TryFromIntError(())
    }
}

impl From<std::convert::Infallible> for TryFromIntError {
    #[inline]
    fn from(_: std::convert::Infallible) -> TryFromIntError {
        TryFromIntError(())
    }
}

impl std::fmt::Display for TryFromIntError {
    #[inline]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("integer overflow")
    }
}

impl std::error::Error for TryFromIntError {}
macro_rules! impl_int {
    ($t:ty) => {
        paste::paste! {
            impl Decoder for $t {
                type Error = crate::Error;

                #[inline]
                fn decode(buf: &mut BytesMut) -> Result<Self, Self::Error> {
                    let (num, off) = Self::raw_decode(buf)?;
                    buf.advance(off);

                    Ok(num)
                }

                #[inline]
                fn has_enough_bytes(buf: &BytesMut) -> bool {
                    buf.remaining() >= std::mem::size_of::<$t>()
                }
            }

            impl RawDecoder for $t {
                type Error = crate::Error;

                fn raw_decode<'a>(
                    buf: &'a [u8]
                ) -> Result<($t, usize), Self::Error>
                where
                    $t: 'a
                {
                    const FULL_LEN: usize = std::mem::size_of::<$t>();

                    if buf.len() < FULL_LEN {
                        return Err(crate::Error::BytesNeeded {
                            needed: FULL_LEN - buf.remaining(),
                            full_len: FULL_LEN,
                            available: buf.remaining(),
                        });
                    }

                    let arr: [u8; FULL_LEN] = buf[..FULL_LEN]
                        .try_into()
                        .unwrap();

                    Ok((<$t>::from_be_bytes(arr), FULL_LEN))
                }
            }

            impl Encoder for $t {
                type Error = std::convert::Infallible;

                #[inline]
                fn encode(item: &$t, buf: &mut BytesMut) -> Result<(), Self::Error> {
                    buf.[<put_ $t>](*item);

                    Ok(())
                }

                #[inline]
                fn size_of(_: &$t) -> usize {
                    std::mem::size_of::<$t>()
                }
            }

            impl Decoder<usize> for $t {
                type Error = crate::Error;

                #[inline]
                fn decode(buf: &mut BytesMut) -> Result<usize, Self::Error> {
                    usize::try_from(<Self as Decoder>::decode(buf)?)
                        .map_err(TryFromIntError::from)
                        .map_err(Into::into)
                }

                #[inline]
                fn has_enough_bytes(buf: &BytesMut) -> bool {
                    <Self as Decoder>::has_enough_bytes(buf)
                }
            }

            impl RawDecoder<usize> for $t {
                type Error = crate::Error;

                #[inline]
                fn raw_decode<'a>(
                    buf: &'a [u8]
                ) -> Result<(usize, usize), Self::Error>
                where
                    $t: 'a
                {
                    let (value, rx) = <Self as RawDecoder>::raw_decode(buf)?;
                    let value = value.try_into().map_err(TryFromIntError::from)?;

                    Ok((value, rx))
                }
            }

            impl Encoder<usize> for $t {
                type Error = crate::Error;

                #[inline]
                fn encode(item: &usize, buf: &mut BytesMut) -> Result<(), Self::Error> {
                    Self::try_from(*item)
                        .map_err(TryFromIntError::from)?
                        .encode_to(buf)
                        .map_err(Into::into)
                }

                #[inline]
                fn size_of(_: &usize) -> usize {
                    std::mem::size_of::<$t>()
                }
            }
        }
    };
}

impl_int!(i8);
impl_int!(u8);

impl_int!(i16);
impl_int!(u16);

impl_int!(i32);
impl_int!(u32);

impl_int!(i64);
impl_int!(u64);

impl_int!(i128);
impl_int!(u128);

#[cfg(test)]
mod tests {
    use bytes::BytesMut;
    use fake::Fake;

    use crate::util::EncoderExt;

    macro_rules! test_int {
        ($t:ty) => {
            paste::paste! {
                #[test]
                fn [<test_ $t>]() {
                    const LEN: usize = std::mem::size_of::<$t>();
                    const MAX: $t = <$t>::MAX;

                    let value: $t = (0..MAX).fake();

                    if stringify!($t).starts_with("u") {
                        assert_eq!(MAX.trailing_ones() as usize, LEN * 8);
                    } else {
                        assert_eq!(MAX.trailing_ones() as usize, LEN * 8 - 1);
                    }

                    assert_eq!(value & !MAX, 0);

                    let mut bytes = BytesMut::new();

                    assert_eq!(LEN, value.size());

                    value.encode_to(&mut bytes).unwrap();

                    assert_eq!(LEN, bytes.len());
                    assert_eq!(&value.to_be_bytes()[..], &bytes[..]);
                }
            }
        };
    }

    test_int!(i8);
    test_int!(u8);

    test_int!(i16);
    test_int!(u16);

    test_int!(i32);
    test_int!(u32);

    test_int!(i64);
    test_int!(u64);

    test_int!(i128);
    test_int!(u128);
}