#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum Endian {
Big,
Little,
}
impl Endian {
#[cfg(target_endian = "little")]
pub const TARGET: Self = Self::Little;
#[cfg(target_endian = "big")]
pub const TARGET: Self = Self::Big;
pub const HOST_ENDIAN: Self = Self::TARGET;
pub fn from_bytes(b: &[u8]) -> Endian {
if b.is_sorted_by(|b1, b2| b1 <= b2) {
Endian::Big
} else {
Endian::Little
}
}
pub fn swap(self) -> Endian {
match self {
Endian::Big => Endian::Little,
Endian::Little => Endian::Big,
}
}
}
impl core::ops::Not for Endian {
type Output = Endian;
fn not(self) -> Self::Output {
self.swap()
}
}
impl Default for Endian {
fn default() -> Self {
Self::TARGET
}
}
pub trait ToBytes: Sized {
type Bytes: AsRef<[u8]>;
fn to_bytes(self) -> Self::Bytes;
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);
}
}