io_ext 0.2.0

Read & Write extensions to deal with primitive types
Documentation
use std::mem::size_of as sof;
use std::io::{Read, Result};

macro_rules! impl_read {
    ($($type:ty),*) => {
        $(
            paste::paste! {
                #[inline]
                fn [<read_ $type _ne>](&mut self) -> $type {
                    let mut buf: [u8; sof::<$type>()] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
                    self.read_exact(&mut buf).expect("Read failed");
                    <$type>::from_ne_bytes(buf)
                }
            
                #[inline]
                fn [<read_ $type _ne_checked>](&mut self) -> Result<$type> {
                    let mut buf: [u8; sof::<$type>()] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
                    self.read_exact(&mut buf)?;
                    Ok(<$type>::from_ne_bytes(buf))
                }
                
                #[inline]
                fn [<read_ $type>](&mut self) -> $type {
                    let mut buf: [u8; sof::<$type>()] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
                    self.read_exact(&mut buf).expect("Read failed");
                    <$type>::from_be_bytes(buf)
                }
            
                #[inline]
                fn [<read_ $type _checked>](&mut self) -> Result<$type> {
                    let mut buf: [u8; sof::<$type>()] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
                    self.read_exact(&mut buf)?;
                    Ok(<$type>::from_be_bytes(buf))
                }
                
                #[inline]
                fn [<read_ $type _le>](&mut self) -> $type {
                    let mut buf: [u8; sof::<$type>()] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
                    self.read_exact(&mut buf).expect("Read failed");
                    <$type>::from_le_bytes(buf)
                }
            
                #[inline]
                fn [<read_ $type _le_checked>](&mut self) -> Result<$type> {
                    let mut buf: [u8; sof::<$type>()] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
                    self.read_exact(&mut buf)?;
                    Ok(<$type>::from_le_bytes(buf))
                }
            }
        )*
    };
}

/// # Read extension
/// All methods at first pull `n` bytes from reader and then interprets them with specified endianess.
/// Where `n` is size of type in bytes.
/// # Panics
/// If [`std::io::Read::read_exact`] will return an error, **ALL** methods that doesn't end with `_checked` will panic.
/// All `_checked` methods will return an error in that case.
/// # Provided methods:
/// * `read_*_ne` - Native-endian
/// * `read_*_be` - Big-endian
/// * `read_*_le` - Little-endian
/// # Example
/// ```
/// use io_ext::ReadExt;
/// 
/// let buf = b"\x00\x01\x20\x00";
/// let mut slice = &buf[..];
/// // Note: &[u8] implements Read trait
///
/// assert_eq!(slice.read_u16(), 1);
/// assert_eq!(slice.read_i16_le_checked().unwrap(), 0x20 as i16);
///
/// // You can handle error on *_checked methods. Others will panic in that canse.
/// assert!(slice.read_u8_checked().is_err());
///
/// // Would panic!
/// // assert!(slice.read_u8() == 0); 
/// ```
pub trait ReadExt: Read {
    #[inline]
    fn read_u8(&mut self) -> u8 {
        let mut v = 0u8;
        self.read_exact(std::slice::from_mut(&mut v)).expect("Read failed");
        v
    }

    #[inline]
    fn read_u8_checked(&mut self) -> Result<u8> {
        let mut v = 0u8;
        self.read_exact(std::slice::from_mut(&mut v))?;
        Ok(v)
    }

    impl_read!(f32, f64, u16, i16, u32, i32, u64, i64, u128, i128);
}

impl<R> ReadExt for R 
where
    R: Read
{ }