xuko 0.10.0

Rust utility library
Documentation
//! Number Endianness

/// Byte order of a number
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum Endian {
    /// Big endian
    Big,
    /// Little endian
    Little,
}

impl Endian {
    /// The target endianness of the host machine
    #[cfg(target_endian = "little")]
    pub const TARGET: Self = Self::Little;
    #[cfg(target_endian = "big")]
    pub const TARGET: Self = Self::Big;

    /// Alias for [`Self::TARGET`]
    pub const HOST_ENDIAN: Self = Self::TARGET;

    /// Get [`Endianness`] from the byte representation of an number
    pub fn from_bytes(b: &[u8]) -> Endian {
        if b.is_sorted_by(|b1, b2| b1 <= b2) {
            Endian::Big
        } else {
            Endian::Little
        }
    }

    /// Swap the endianness of `self`
    pub fn swap(self) -> Endian {
        match self {
            Endian::Big => Endian::Little,
            Endian::Little => Endian::Big,
        }
    }
}

/// Same as [`Endianness::swap`]
impl core::ops::Not for Endian {
    type Output = Endian;
    fn not(self) -> Self::Output {
        self.swap()
    }
}

/// Will return the target endian
impl Default for Endian {
    fn default() -> Self {
        Self::TARGET
    }
}

/// Convert numbers to bytes, regardless of endianness
pub trait ToBytes: Sized {
    /// Type of bytes
    type Bytes: AsRef<[u8]>;

    /// Convert this number to its raw byte representation
    fn to_bytes(self) -> Self::Bytes;

    /// Get the endianness of the number
    fn endianness(self) -> Endian {
        let x = self.to_bytes();
        Endian::from_bytes(x.as_ref())
    }
}

macro_rules! impl_to_bytes {
    ($type:ty) => {
        impl ToBytes for $type {
            type Bytes = [u8; ::core::mem::size_of::<$type>()];

            fn to_bytes(self) -> Self::Bytes {
                #[allow(unnecessary_transmutes)]
                unsafe {
                    core::mem::transmute(self)
                }
            }
        }
    };
}

impl_to_bytes!(u8);
impl_to_bytes!(u16);
impl_to_bytes!(u32);
impl_to_bytes!(u64);
impl_to_bytes!(u128);

impl_to_bytes!(i8);
impl_to_bytes!(i16);
impl_to_bytes!(i32);
impl_to_bytes!(i64);
impl_to_bytes!(i128);

impl_to_bytes!(f32);
impl_to_bytes!(f64);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn endianness() {
        let x: i32 = 43;

        assert_eq!(x.endianness(), Endian::TARGET);
        assert_eq!(x.to_be().endianness(), Endian::Big);

        let y: f32 = 7.9;
        assert_eq!(y.endianness(), Endian::TARGET);
    }
}