futures-byteorder 1.0.1

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

use crate::{BigEndian, LittleEndian};

pub trait Sealed {}

pub trait ByteArray: Sealed + Default + Borrow<[u8]> + BorrowMut<[u8]> + Copy {}

/// A trait defining byte order conversion behavior.
///
/// This trait is implemented by [`BigEndian`], [`LittleEndian`], and their type aliases
/// to define how numeric values should be converted to and from byte representations.
///
/// # Examples
///
/// ```
/// use futures_byteorder::{Endianness, BigEndian, Representable};
///
/// let value: u16 = 0x1234;
/// let bytes = BigEndian::from_representable(&value);
/// assert_eq!(bytes, [0x12, 0x34]);
///
/// let decoded = BigEndian::to_representable::<u16>(&bytes);
/// assert_eq!(decoded, 0x1234);
/// ```
pub trait Endianness: Sealed {
    /// Converts a representable value to its byte representation using this endianness.
    ///
    /// # Examples
    ///
    /// ```
    /// use futures_byteorder::{Endianness, LittleEndian};
    ///
    /// let value: u32 = 0x12345678;
    /// let bytes = LittleEndian::from_representable(&value);
    /// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]);
    /// ```
    fn from_representable<R: Representable>(representable: &R) -> R::Representation;

    /// Converts a byte representation to a representable value using this endianness.
    ///
    /// # Examples
    ///
    /// ```
    /// use futures_byteorder::{Endianness, BigEndian};
    ///
    /// let bytes = [0x12, 0x34, 0x56, 0x78];
    /// let value = BigEndian::to_representable::<u32>(&bytes);
    /// assert_eq!(value, 0x12345678);
    /// ```
    fn to_representable<R: Representable>(representation: &R::Representation) -> R;
}

/// A trait for types that can be represented as a fixed-size byte array.
///
/// This trait is implemented for all primitive integer types (`u8`-`u128`, `i8`-`i128`)
/// and floating-point types (`f32`, `f64`). It provides methods for converting between
/// the type and its byte representation in both little-endian and big-endian formats.
///
/// # Examples
///
/// ```
/// use futures_byteorder::Representable;
///
/// let value: u16 = 0x1234;
/// let le_bytes = value.to_le_bytes();
/// let be_bytes = value.to_be_bytes();
///
/// assert_eq!(le_bytes, [0x34, 0x12]);
/// assert_eq!(be_bytes, [0x12, 0x34]);
///
/// assert_eq!(u16::from_le_bytes(le_bytes), value);
/// assert_eq!(u16::from_be_bytes(be_bytes), value);
/// ```
pub trait Representable {
    /// The byte array type that represents this type.
    ///
    /// For example, `u16::Representation` is `[u8; 2]`, and `u64::Representation` is `[u8; 8]`.
    type Representation: ByteArray;

    /// Creates a value from its little-endian byte representation.
    fn from_le_bytes(bytes: &Self::Representation) -> Self;

    /// Creates a value from its big-endian byte representation
    fn from_be_bytes(bytes: &Self::Representation) -> Self;

    /// Returns the little-endian byte representation of this value.
    fn to_le_bytes(&self) -> Self::Representation;

    /// Returns the big-endian byte representation of this value.
    fn to_be_bytes(&self) -> Self::Representation;
}

impl<const N: usize> Sealed for [u8; N] {}
impl<const N: usize> ByteArray for [u8; N] where [u8; N]: Default + Borrow<[u8]> + BorrowMut<[u8]> {}

impl Sealed for BigEndian {}
impl Endianness for BigEndian {
    fn from_representable<R: Representable>(representable: &R) -> R::Representation {
        representable.to_be_bytes()
    }

    fn to_representable<R: Representable>(representation: &R::Representation) -> R {
        R::from_be_bytes(representation)
    }
}

impl Sealed for LittleEndian {}
impl Endianness for LittleEndian {
    fn from_representable<R: Representable>(representable: &R) -> R::Representation {
        representable.to_le_bytes()
    }

    fn to_representable<R: Representable>(representation: &R::Representation) -> R {
        R::from_le_bytes(representation)
    }
}

macro_rules! impl_representable {
    ($($num:ty),* $(,)?) => {
        $(impl Representable for $num {
            type Representation = [u8; std::mem::size_of::<$num>()];

            fn from_le_bytes(bytes: &Self::Representation) -> Self {
                Self::from_le_bytes(*bytes)
            }

            fn from_be_bytes(bytes: &Self::Representation) -> Self {
                Self::from_be_bytes(*bytes)
            }

            fn to_le_bytes(&self) -> Self::Representation {
                Self::to_le_bytes(*self)
            }

            fn to_be_bytes(&self) -> Self::Representation {
                Self::to_be_bytes(*self)
            }
        })*
    }
}

impl_representable!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64);