futures-byteorder 1.0.1

A modern async byteorder library for the smol/futures-lite ecosystem
Documentation
use std::borrow::BorrowMut;
use std::ops::{Deref, DerefMut};

use futures_lite::{AsyncReadExt, io};

use crate::{Endianness, NativeEndian, Representable};

/// Wraps a type that implements [`AsyncReadExt`] to extend its functionality with methods for
/// reading numbers (for [`futures_lite::io`]).
///
/// Note: This is a struct wrapper instead of a trait like in the original `byteorder` crate because
/// it would require for either extremely painful code or to import the heavy proc-macro crate that
/// is `async-trait`
#[repr(transparent)]
pub struct AsyncReadBytes<'a, R>(&'a mut R)
where
    R: AsyncReadExt + Unpin;

impl<R> Deref for AsyncReadBytes<'_, R>
where
    R: AsyncReadExt + Unpin,
{
    type Target = R;

    fn deref(&self) -> &Self::Target {
        self.0
    }
}

impl<R> DerefMut for AsyncReadBytes<'_, R>
where
    R: AsyncReadExt + Unpin,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.0
    }
}

impl<'a, R> AsyncReadBytes<'a, R>
where
    R: AsyncReadExt + Unpin,
{
    /// Creates a new `AsyncReadBytes` wrapper around the given reader.
    ///
    /// # Examples
    ///
    /// ```
    /// use futures_byteorder::AsyncReadBytes;
    /// use futures_lite::io::Cursor;
    ///
    /// let data = vec![0x12, 0x34];
    /// let mut reader = Cursor::new(data);
    /// let reader = AsyncReadBytes::new(&mut reader);
    /// ```
    #[must_use]
    pub const fn new(reader: &'a mut R) -> Self {
        Self(reader)
    }

    /// # Errors
    /// This method returns the same errors as [`AsyncReadExt::read_exact`].
    pub async fn read_representable<E, Re>(&mut self) -> io::Result<Re>
    where
        E: Endianness,
        Re: Representable,
    {
        let mut buffer = Re::Representation::default();
        self.read_exact(buffer.borrow_mut()).await?;
        Ok(E::to_representable(&buffer))
    }

    /// # Errors
    /// This method returns the same errors as [`AsyncReadExt::read_exact`].
    #[inline]
    pub async fn read_u8(&mut self) -> io::Result<u8> {
        self.read_representable::<NativeEndian, u8>().await
    }

    /// # Errors
    /// This method returns the same errors as [`AsyncReadExt::read_exact`].
    #[inline]
    pub async fn read_i8(&mut self) -> io::Result<i8> {
        self.read_representable::<NativeEndian, i8>().await
    }
}

macro_rules! impl_async_read_bytes {
    ($(($num:ty, $read_name:ident, $read_name_ne:ident)),* $(,)?) => {
        impl<R> AsyncReadBytes<'_, R> where R: AsyncReadExt + Unpin {
            $(
                /// # Errors
                /// This method returns the same errors as [`AsyncReadExt::read_exact`].
                #[inline]
                pub async fn $read_name<E: Endianness>(&mut self) -> io::Result<$num> {
                    self.read_representable::<E, $num>().await
                }

                /// # Errors
                /// This method returns the same errors as [`AsyncReadExt::read_exact`].
                #[inline]
                pub async fn $read_name_ne(&mut self) -> io::Result<$num> {
                    self.read_representable::<NativeEndian, $num>().await
                }
            )*
        }
    };
}

impl_async_read_bytes!(
    (u16, read_u16, read_u16_ne),
    (u32, read_u32, read_u32_ne),
    (u64, read_u64, read_u64_ne),
    (u128, read_u128, read_u128_ne),
    (i16, read_i16, read_i16_ne),
    (i32, read_i32, read_i32_ne),
    (i64, read_i64, read_i64_ne),
    (i128, read_i128, read_i128_ne),
    (f32, read_f32, read_f32_ne),
    (f64, read_f64, read_f64_ne),
);

impl<'a, R> From<&'a mut R> for AsyncReadBytes<'a, R>
where
    R: AsyncReadExt + Unpin,
{
    fn from(reader: &'a mut R) -> Self {
        Self::new(reader)
    }
}