futures-byteorder 1.0.1

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

use futures_lite::{AsyncWriteExt, io};

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

/// Wraps a type that implements [`AsyncWriteExt`] to extend its functionality with methods for
/// writing 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 AsyncWriteBytes<'a, W>(&'a mut W)
where
    W: AsyncWriteExt + Unpin;

impl<W> Deref for AsyncWriteBytes<'_, W>
where
    W: AsyncWriteExt + Unpin,
{
    type Target = W;

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

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

impl<'a, W> AsyncWriteBytes<'a, W>
where
    W: AsyncWriteExt + 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(writer: &'a mut W) -> Self {
        Self(writer)
    }

    /// # Errors
    /// This method returns the same errors as [`AsyncWriteExt::write_all`].
    pub async fn write_representable<E, Re>(&mut self, value: Re) -> io::Result<()>
    where
        E: Endianness,
        Re: Representable,
    {
        let buffer = E::from_representable(&value);
        self.write_all(buffer.borrow()).await
    }

    /// # Errors
    /// This method returns the same errors as [`AsyncWriteExt::write_all`].
    #[inline]
    pub async fn write_u8(&mut self, value: u8) -> io::Result<()> {
        self.write_all(&[value]).await
    }

    /// # Errors
    /// This method returns the same errors as [`AsyncWriteExt::write_all`].
    #[inline]
    pub async fn write_i8(&mut self, value: i8) -> io::Result<()> {
        self.write_all(&[value.cast_unsigned()]).await
    }
}

macro_rules! impl_async_write_bytes {
     ($(($num:ty, $write_name:ident, $write_name_ne:ident)),* $(,)?) => {
        impl<W> AsyncWriteBytes<'_, W> where W: AsyncWriteExt + Unpin {
            $(
                    /// # Errors
                    /// This method returns the same errors as [`AsyncWriteExt::write_all`].
                    #[inline]
                    pub async fn $write_name<E: Endianness>(&mut self, value: $num) -> io::Result<()> {
                        self.write_representable::<E, $num>(value).await
                    }

                    /// # Errors
                    /// This method returns the same errors as [`AsyncWriteExt::write_all`].
                    ///
                    /// Note: This writes using [`NativeEndian`], not `NetworkEndian`!
                    #[inline]
                    pub async fn $write_name_ne(&mut self, value: $num) -> io::Result<()> {
                        self.write_representable::<NativeEndian, $num>(value).await
                    }

            )*
        }
    };
}

impl_async_write_bytes!(
    (u16, write_u16, write_u16_ne),
    (u32, write_u32, write_u32_ne),
    (u64, write_u64, write_u64_ne),
    (u128, write_u128, write_u128_ne),
    (i16, write_i16, write_i16_ne),
    (i32, write_i32, write_i32_ne),
    (i64, write_i64, write_i64_ne),
    (i128, write_i128, write_i128_ne),
    (f32, write_f32, write_f32_ne),
    (f64, write_f64, write_f64_ne),
);

impl<'a, W> From<&'a mut W> for AsyncWriteBytes<'a, W>
where
    W: AsyncWriteExt + Unpin,
{
    fn from(writer: &'a mut W) -> Self {
        Self::new(writer)
    }
}