//! # Endian Type //! //! `endiantype` is an `no-std`, endian-aware implementation of primitive types like `u8`, `u16`, etc. //! //! All endian types are implemented in a transparent way that it can directly replace the original //! types with almost zero overhead. //! //! ## Usage //! Add this to your Cargo.toml //! ``` //! endiantype = "0.1.3" //! ``` //! to use in a `[no_std]` environment, you need to disable default features. //! ``` //! endiantype = { version = "0.1.3", default-features = false} //! ``` //! and import endian-ware types from this crate. //! ``` //! use endiantype::types::*; //! ``` //! //! ## Features //! Here is some features of `endian_type` crate. //! ### [no-std] Support //! This crate can be used without `std` support with no requirements or additional features needed //! as it only relies on `core`. //! ### Drop-in replacement //! This crate provides sufficient default operations for endian-aware types. //! //! For example, you can directly compare a primitive type with a endian-aware type. //! ``` //! use endiantype::*; //! let num_le = u16_le::from_native(10); //! assert!(num_le < 11); //! ``` //! Other bit-wise ops like `&`, `|` and arithmetic ops like `+`, `-` are also supported. //! ``` //! use endiantype::*; //! let a = u32_le::from_native(1); //! let b = u32_be::from_native(2); //! assert!(a+b == 3); //! ``` #![cfg_attr(not(feature = "std"), no_std)] use core::cmp::Ordering; use core::ops::{Add, BitAnd, BitOr, BitXor, Sub}; pub use types::*; /// # Little endian types /// ## Example /// ``` /// use endiantype::*; /// // endian types can be created from native types; /// let deadbeef = u32_le::from_native(0xdeadbeef); /// assert!(deadbeef == 0xdeadbeef); /// // or use `From` trait of native types; /// let deadbeef: u32_le = 0xdeadbeef.into(); /// assert!(deadbeef == 0xdeadbeef); /// // or use `From` trait of another endian types; /// let deadbeef: u32_le = u32_be::from_native(0xdeadbeef).into(); /// assert!(deadbeef == 0xdeadbeef); /// ``` #[derive(Copy, Clone, Debug, Hash)] #[repr(transparent)] pub struct LittleEndian(T); /// # Big endian types /// ## Example /// ``` /// use endiantype::*; /// // endian types can be created from native types; /// let deadbeef = u32_be::from_native(0xdeadbeef); /// assert!(deadbeef == 0xdeadbeef); /// // or use `From` trait of native types; /// let deadbeef: u32_be = 0xdeadbeef.into(); /// assert!(deadbeef == 0xdeadbeef); /// // or use `From` trait of another endian types; /// let deadbeef: u32_be = u32_le::from_native(0xdeadbeef).into(); /// assert!(deadbeef == 0xdeadbeef); /// ``` #[derive(Copy, Clone, Debug, Hash)] #[repr(transparent)] pub struct BigEndian(T); macro_rules! impl_endian { ($type_name:ident) => { impl_endian_base!($type_name); impl_endian_from_native!($type_name, LittleEndian); impl_endian_from_native!($type_name, BigEndian); impl_endian_from_each!($type_name); impl_endian_op!($type_name, BitAnd, bitand); impl_endian_op!($type_name, BitOr, bitor); impl_endian_op!($type_name, BitXor, bitxor); impl_endian_op!($type_name, Add, add); impl_endian_op!($type_name, Sub, sub); impl_endian_cmp!($type_name, PartialEq, eq, bool); impl_endian_cmp!($type_name, PartialOrd, partial_cmp, Option); }; } macro_rules! impl_endian_base { ($type_name: ident) => { impl BigEndian<$type_name> { pub const fn from_native(data: $type_name) -> Self { Self(data.to_be()) } pub const fn new(data: $type_name) -> Self { Self(data) } pub fn to_native(&self) -> $type_name { match () { #[cfg(target_endian = "big")] () => self.0, #[cfg(target_endian = "little")] () => self.0.swap_bytes(), } } } impl LittleEndian<$type_name> { pub const fn from_native(data: $type_name) -> Self { Self(data.to_le()) } pub const fn new(data: $type_name) -> Self { Self(data) } pub fn to_native(&self) -> $type_name { match () { #[cfg(target_endian = "big")] () => self.0.swap_bytes(), #[cfg(target_endian = "little")] () => self.0, } } } }; } macro_rules! impl_endian_from_native { ($type_name: ident, $endian_name: ident) => { impl From<$endian_name<$type_name>> for $type_name { #[inline] fn from(data: $endian_name<$type_name>) -> Self { data.to_native() } } impl From<$type_name> for $endian_name<$type_name> { #[inline] fn from(data: $type_name) -> Self { $endian_name::<$type_name>::from_native(data) } } }; } macro_rules! impl_endian_from_each { ($type_name: ident) => { impl From> for BigEndian<$type_name> { #[inline] fn from(data: LittleEndian<$type_name>) -> Self { Self(data.0.swap_bytes()) } } impl From> for LittleEndian<$type_name> { #[inline] fn from(data: BigEndian<$type_name>) -> Self { Self(data.0.swap_bytes()) } } }; } macro_rules! impl_endian_cmp_each { ($type_name: ident, $endian_name: ident, $other_endian_name: ident, $trait_name: ident, $trait_func_name: ident, $return_type: ty) => { impl $trait_name<$other_endian_name<$type_name>> for $endian_name<$type_name> { #[inline] fn $trait_func_name(&self, rhs: &$other_endian_name<$type_name>) -> $return_type { self.to_native().$trait_func_name(&rhs.to_native()) } } }; } macro_rules! impl_endian_cmp_native { ($type_name: ident, $endian_name: ident, $trait_name: ident, $trait_func_name: ident, $return_type: ty) => { impl $trait_name<$type_name> for $endian_name<$type_name> { #[inline] fn $trait_func_name(&self, rhs: &$type_name) -> $return_type { self.to_native().$trait_func_name(rhs) } } impl $trait_name<$endian_name<$type_name>> for $type_name { #[inline] fn $trait_func_name(&self, rhs: &$endian_name<$type_name>) -> $return_type { self.$trait_func_name(&rhs.to_native()) } } }; } macro_rules! impl_endian_op_each { ($type_name: ident, $endian_name: ident, $other_endian_name: ident, $trait_name: ident, $trait_func_name: ident) => { impl $trait_name<$other_endian_name<$type_name>> for $endian_name<$type_name> { type Output = $endian_name<$type_name>; #[inline] fn $trait_func_name(self, rhs: $other_endian_name<$type_name>) -> Self { $endian_name::<$type_name>::from_native( self.to_native().$trait_func_name(rhs.to_native()), ) } } }; } macro_rules! impl_endian_op_native { ($type_name: ident, $endian_name: ident, $trait_name: ident, $trait_func_name: ident) => { impl $trait_name<$type_name> for $endian_name<$type_name> { type Output = $endian_name<$type_name>; #[inline] fn $trait_func_name(self, rhs: $type_name) -> Self { $endian_name::<$type_name>::from_native(self.to_native().$trait_func_name(rhs)) } } impl $trait_name<$endian_name<$type_name>> for $type_name { type Output = $type_name; #[inline] fn $trait_func_name(self, rhs: $endian_name<$type_name>) -> Self { self.$trait_func_name(rhs.to_native()) } } }; } macro_rules! impl_endian_op { ($type_name: ident, $trait_name: ident, $trait_func_name: ident) => { impl_endian_op_each!( $type_name, BigEndian, BigEndian, $trait_name, $trait_func_name ); impl_endian_op_each!( $type_name, LittleEndian, LittleEndian, $trait_name, $trait_func_name ); impl_endian_op_each!( $type_name, BigEndian, LittleEndian, $trait_name, $trait_func_name ); impl_endian_op_each!( $type_name, LittleEndian, BigEndian, $trait_name, $trait_func_name ); impl_endian_op_native!($type_name, BigEndian, $trait_name, $trait_func_name); impl_endian_op_native!($type_name, LittleEndian, $trait_name, $trait_func_name); }; } macro_rules! impl_endian_cmp { ($type_name: ident, $trait_name: ident, $trait_func_name: ident, $return_type: ty) => { impl_endian_cmp_each!( $type_name, BigEndian, LittleEndian, $trait_name, $trait_func_name, $return_type ); impl_endian_cmp_each!( $type_name, LittleEndian, BigEndian, $trait_name, $trait_func_name, $return_type ); impl_endian_cmp_each!( $type_name, LittleEndian, LittleEndian, $trait_name, $trait_func_name, $return_type ); impl_endian_cmp_each!( $type_name, BigEndian, BigEndian, $trait_name, $trait_func_name, $return_type ); impl_endian_cmp_native!( $type_name, BigEndian, $trait_name, $trait_func_name, $return_type ); impl_endian_cmp_native!( $type_name, LittleEndian, $trait_name, $trait_func_name, $return_type ); }; } impl_endian!(u8); impl_endian!(u16); impl_endian!(u32); impl_endian!(u64); impl_endian!(u128); impl_endian!(usize); impl_endian!(i8); impl_endian!(i16); impl_endian!(i32); impl_endian!(i64); impl_endian!(i128); impl_endian!(isize); #[allow(non_camel_case_types)] pub mod types { pub type u8_le = super::LittleEndian; pub type u16_le = super::LittleEndian; pub type u32_le = super::LittleEndian; pub type u64_le = super::LittleEndian; pub type u128_le = super::LittleEndian; pub type usize_le = super::LittleEndian; pub type i8_le = super::LittleEndian; pub type i16_le = super::LittleEndian; pub type i32_le = super::LittleEndian; pub type i64_le = super::LittleEndian; pub type i128_le = super::LittleEndian; pub type isize_le = super::LittleEndian; pub type u8_be = super::BigEndian; pub type u16_be = super::BigEndian; pub type u32_be = super::BigEndian; pub type u64_be = super::BigEndian; pub type u128_be = super::BigEndian; pub type usize_be = super::BigEndian; pub type i8_be = super::BigEndian; pub type i16_be = super::BigEndian; pub type i32_be = super::BigEndian; pub type i64_be = super::BigEndian; pub type i128_be = super::BigEndian; pub type isize_be = super::BigEndian; }