recode 0.4.1

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

#[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<B: Buf> Decoder<B> for $t {
                type Error = crate::Error;

                #[inline]
                fn decode(buf: &mut B) -> Result<Self, Self::Error> {
                    const FULL_EN: usize = std::mem::size_of::<$t>();

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

                    Ok(buf.[<get_ $t>]())
                }
            }

            impl<B: BufMut> Encoder<B> for $t {
                type Error = std::convert::Infallible;

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

                    Ok(())
                }

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

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

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

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

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

                #[inline]
                fn size_of(_: &usize, _: &B) -> 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(&bytes));

                    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);
}