From 51df9728ab08465749af8b8e22c78a6372d44562 Mon Sep 17 00:00:00 2001 From: Flier Lu Date: Thu, 28 Feb 2019 18:31:44 +0800 Subject: [PATCH 1/6] convert between integer and byte array --- src/int.rs | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 36 ++++----------- 2 files changed, 142 insertions(+), 27 deletions(-) diff --git a/src/int.rs b/src/int.rs index 22f2713..225a3c9 100644 --- a/src/int.rs +++ b/src/int.rs @@ -1,3 +1,4 @@ +use core::mem::size_of; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use bounds::Bounded; @@ -5,6 +6,11 @@ use ops::checked::*; use ops::saturating::Saturating; use {Num, NumCast}; +pub trait Layout { + /// The type representation as a byte array. + type Bytes; +} + pub trait PrimInt: Sized + Copy @@ -25,6 +31,7 @@ pub trait PrimInt: + CheckedMul + CheckedDiv + Saturating + + Layout { /// Returns the number of ones in the binary representation of `self`. /// @@ -278,6 +285,98 @@ pub trait PrimInt: /// assert_eq!(2i32.pow(4), 16); /// ``` fn pow(self, exp: u32) -> Self; + + /// Return the memory representation of this integer as a byte array in big-endian byte order. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let bytes = 0x12345678u32.to_be_bytes(); + /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]); + /// ``` + fn to_be_bytes(self) -> Self::Bytes; + + /// Return the memory representation of this integer as a byte array in little-endian byte order. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let bytes = 0x12345678u32.to_le_bytes(); + /// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]); + /// ``` + fn to_le_bytes(self) -> Self::Bytes; + + /// Return the memory representation of this integer as a byte array in native byte order. + /// + /// As the target platform's native endianness is used, + /// portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. + /// + /// [`to_be_bytes`]: #method.to_be_bytes + /// [`to_le_bytes`]: #method.to_le_bytes + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let bytes = 0x12345678u32.to_ne_bytes(); + /// assert_eq!(bytes, if cfg!(target_endian = "big") { + /// [0x12, 0x34, 0x56, 0x78] + /// } else { + /// [0x78, 0x56, 0x34, 0x12] + /// }); + /// ``` + fn to_ne_bytes(self) -> Self::Bytes; + + /// Create an integer value from its representation as a byte array in big endian. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let value = u32::from_be_bytes([0x12, 0x34, 0x56, 0x78]); + /// assert_eq!(value, 0x12345678); + /// ``` + fn from_be_bytes(bytes: Self::Bytes) -> Self; + + /// Create an integer value from its representation as a byte array in little endian. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let value = u32::from_le_bytes([0x78, 0x56, 0x34, 0x12]); + /// assert_eq!(value, 0x12345678); + /// ``` + fn from_le_bytes(bytes: Self::Bytes) -> Self; + + /// Create an integer value from its memory representation as a byte array in native endianness. + /// + /// As the target platform's native endianness is used, + /// portable code likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as appropriate instead. + /// + /// [`from_be_bytes`]: #method.from_be_bytes + /// [`from_le_bytes`]: #method.from_le_bytes + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let value = u32::from_ne_bytes(if cfg!(target_endian = "big") { + /// [0x12, 0x34, 0x56, 0x78] + /// } else { + /// [0x78, 0x56, 0x34, 0x12] + /// }); + /// assert_eq!(value, 0x12345678); + /// ``` + fn from_ne_bytes(bytes: Self::Bytes) -> Self; } macro_rules! prim_int_impl { @@ -362,6 +461,40 @@ macro_rules! prim_int_impl { fn pow(self, exp: u32) -> Self { <$T>::pow(self, exp) } + + #[inline] + fn to_be_bytes(self) -> Self::Bytes { + <$T>::to_be_bytes(self) + } + + #[inline] + fn to_le_bytes(self) -> Self::Bytes { + <$T>::to_le_bytes(self) + } + + #[inline] + fn to_ne_bytes(self) -> Self::Bytes { + <$T>::to_ne_bytes(self) + } + + #[inline] + fn from_be_bytes(bytes: Self::Bytes) -> Self { + <$T>::from_be_bytes(bytes) + } + + #[inline] + fn from_le_bytes(bytes: Self::Bytes) -> Self { + <$T>::from_le_bytes(bytes) + } + + #[inline] + fn from_ne_bytes(bytes: Self::Bytes) -> Self { + <$T>::from_ne_bytes(bytes) + } + } + + impl Layout for $T { + type Bytes = [u8; size_of::<$T>()]; } }; } diff --git a/src/lib.rs b/src/lib.rs index 5a25bab..76f4e55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,7 @@ pub use float::FloatConst; // pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`. pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive}; pub use identities::{one, zero, One, Zero}; -pub use int::PrimInt; +pub use int::{Layout, PrimInt}; pub use ops::checked::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, }; @@ -90,13 +90,12 @@ pub trait NumOps: { } -impl NumOps for T -where +impl NumOps for T where T: Add + Sub + Mul + Div - + Rem, + + Rem { } @@ -105,22 +104,14 @@ where /// /// This is automatically implemented for types which implement the operators. pub trait NumRef: Num + for<'r> NumOps<&'r Self> {} -impl NumRef for T -where - T: Num + for<'r> NumOps<&'r T>, -{ -} +impl NumRef for T where T: Num + for<'r> NumOps<&'r T> {} /// The trait for references which implement numeric operations, taking the /// second operand either by value or by reference. /// /// This is automatically implemented for types which implement the operators. pub trait RefNum: NumOps + for<'r> NumOps<&'r Base, Base> {} -impl RefNum for T -where - T: NumOps + for<'r> NumOps<&'r Base, Base>, -{ -} +impl RefNum for T where T: NumOps + for<'r> NumOps<&'r Base, Base> {} /// The trait for types implementing numeric assignment operators (like `+=`). /// @@ -130,9 +121,8 @@ pub trait NumAssignOps: { } -impl NumAssignOps for T -where - T: AddAssign + SubAssign + MulAssign + DivAssign + RemAssign, +impl NumAssignOps for T where + T: AddAssign + SubAssign + MulAssign + DivAssign + RemAssign { } @@ -140,22 +130,14 @@ where /// /// This is automatically implemented for types which implement the operators. pub trait NumAssign: Num + NumAssignOps {} -impl NumAssign for T -where - T: Num + NumAssignOps, -{ -} +impl NumAssign for T where T: Num + NumAssignOps {} /// The trait for `NumAssign` types which also implement assignment operations /// taking the second operand by reference. /// /// This is automatically implemented for types which implement the operators. pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {} -impl NumAssignRef for T -where - T: NumAssign + for<'r> NumAssignOps<&'r T>, -{ -} +impl NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {} macro_rules! int_trait_impl { ($name:ident for $($t:ty)*) => ($( From 05f660c03d5b670d4ae81e3f04fbcc6304ddbc0e Mon Sep 17 00:00:00 2001 From: Flier Lu Date: Thu, 28 Feb 2019 19:05:06 +0800 Subject: [PATCH 2/6] backward compatibility with feature gate --- Cargo.toml | 4 +++ build.rs | 9 +++++++ src/int.rs | 72 ++++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 70 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 672b4c2..179f2e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,11 @@ features = ["std"] [dependencies] +[build-dependencies] +rustc_version = "0.2" + [features] default = ["std"] std = [] i128 = [] +int_to_from_bytes = [] diff --git a/build.rs b/build.rs index fd60866..2188e95 100644 --- a/build.rs +++ b/build.rs @@ -1,3 +1,5 @@ +extern crate rustc_version; + use std::env; use std::io::Write; use std::process::{Command, Stdio}; @@ -8,6 +10,13 @@ fn main() { } else if env::var_os("CARGO_FEATURE_I128").is_some() { panic!("i128 support was not detected!"); } + + match rustc_version::version() { + Ok(ref version) if version.major >= 1 && version.minor >= 32 => { + println!("cargo:rustc-cfg=int_to_from_bytes"); + } + _ => {} + } } /// Test if a code snippet can be compiled diff --git a/src/int.rs b/src/int.rs index 225a3c9..c1d5694 100644 --- a/src/int.rs +++ b/src/int.rs @@ -1,4 +1,4 @@ -use core::mem::size_of; +use core::mem::transmute; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use bounds::Bounded; @@ -380,7 +380,7 @@ pub trait PrimInt: } macro_rules! prim_int_impl { - ($T:ty, $S:ty, $U:ty) => { + ($T:ty, $S:ty, $U:ty, $L:expr) => { impl PrimInt for $T { #[inline] fn count_ones(self) -> u32 { @@ -462,55 +462,97 @@ macro_rules! prim_int_impl { <$T>::pow(self, exp) } + #[cfg(feature = "int_to_from_bytes")] #[inline] fn to_be_bytes(self) -> Self::Bytes { <$T>::to_be_bytes(self) } + #[cfg(feature = "int_to_from_bytes")] #[inline] fn to_le_bytes(self) -> Self::Bytes { <$T>::to_le_bytes(self) } + #[cfg(feature = "int_to_from_bytes")] #[inline] fn to_ne_bytes(self) -> Self::Bytes { <$T>::to_ne_bytes(self) } + #[cfg(feature = "int_to_from_bytes")] #[inline] fn from_be_bytes(bytes: Self::Bytes) -> Self { <$T>::from_be_bytes(bytes) } + #[cfg(feature = "int_to_from_bytes")] #[inline] fn from_le_bytes(bytes: Self::Bytes) -> Self { <$T>::from_le_bytes(bytes) } + #[cfg(feature = "int_to_from_bytes")] #[inline] fn from_ne_bytes(bytes: Self::Bytes) -> Self { <$T>::from_ne_bytes(bytes) } + + #[cfg(not(feature = "int_to_from_bytes"))] + #[inline] + fn to_be_bytes(self) -> Self::Bytes { + <$T>::to_ne_bytes(<$T>::to_be(self)) + } + + #[cfg(not(feature = "int_to_from_bytes"))] + #[inline] + fn to_le_bytes(self) -> Self::Bytes { + <$T>::to_ne_bytes(<$T>::to_le(self)) + } + + #[cfg(not(feature = "int_to_from_bytes"))] + #[inline] + fn to_ne_bytes(self) -> Self::Bytes { + unsafe { transmute(self) } + } + + #[cfg(not(feature = "int_to_from_bytes"))] + #[inline] + fn from_be_bytes(bytes: Self::Bytes) -> Self { + Self::from_be(Self::from_ne_bytes(bytes)) + } + + #[cfg(not(feature = "int_to_from_bytes"))] + #[inline] + fn from_le_bytes(bytes: Self::Bytes) -> Self { + Self::from_le(Self::from_ne_bytes(bytes)) + } + + #[cfg(not(feature = "int_to_from_bytes"))] + #[inline] + fn from_ne_bytes(bytes: Self::Bytes) -> Self { + unsafe { transmute(bytes) } + } } impl Layout for $T { - type Bytes = [u8; size_of::<$T>()]; + type Bytes = [u8; $L]; } }; } // prim_int_impl!(type, signed, unsigned); -prim_int_impl!(u8, i8, u8); -prim_int_impl!(u16, i16, u16); -prim_int_impl!(u32, i32, u32); -prim_int_impl!(u64, i64, u64); +prim_int_impl!(u8, i8, u8, 1); +prim_int_impl!(u16, i16, u16, 2); +prim_int_impl!(u32, i32, u32, 4); +prim_int_impl!(u64, i64, u64, 8); #[cfg(has_i128)] -prim_int_impl!(u128, i128, u128); -prim_int_impl!(usize, isize, usize); -prim_int_impl!(i8, i8, u8); -prim_int_impl!(i16, i16, u16); -prim_int_impl!(i32, i32, u32); -prim_int_impl!(i64, i64, u64); +prim_int_impl!(u128, i128, u128, 16); +prim_int_impl!(usize, isize, usize, 8); +prim_int_impl!(i8, i8, u8, 1); +prim_int_impl!(i16, i16, u16, 2); +prim_int_impl!(i32, i32, u32, 4); +prim_int_impl!(i64, i64, u64, 8); #[cfg(has_i128)] -prim_int_impl!(i128, i128, u128); -prim_int_impl!(isize, isize, usize); +prim_int_impl!(i128, i128, u128, 16); +prim_int_impl!(isize, isize, usize, 8); From 45c399ffa755e29893916532610a14f1b70ea358 Mon Sep 17 00:00:00 2001 From: Flier Lu Date: Thu, 28 Feb 2019 19:15:18 +0800 Subject: [PATCH 3/6] check `int_to_from_bytes` feature on stable channel --- build.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 2188e95..138f831 100644 --- a/build.rs +++ b/build.rs @@ -11,10 +11,16 @@ fn main() { panic!("i128 support was not detected!"); } - match rustc_version::version() { - Ok(ref version) if version.major >= 1 && version.minor >= 32 => { + match rustc_version::version_meta() { + Ok(ref meta) if meta.semver.major >= 1 && meta.semver.minor >= 32 => { println!("cargo:rustc-cfg=int_to_from_bytes"); } + Ok(ref meta) + if env::var_os("CARGO_FEATURE_INT_TO_FROM_BYTES").is_some() + && meta.channel == rustc_version::Channel::Stable => + { + panic!("`int_to_from_bytes` support was not stabilizations!"); + } _ => {} } } From 316120c6113478abc56831ed0afd872d45a5fc21 Mon Sep 17 00:00:00 2001 From: Flier Lu Date: Fri, 1 Mar 2019 17:18:44 +0800 Subject: [PATCH 4/6] extract `IntToFromBytes` trait --- Cargo.toml | 4 -- build.rs | 24 +++++---- src/int.rs | 126 +++++------------------------------------------ src/lib.rs | 3 +- src/ops/bytes.rs | 95 +++++++++++++++++++++++++++++++++++ src/ops/mod.rs | 1 + 6 files changed, 121 insertions(+), 132 deletions(-) create mode 100644 src/ops/bytes.rs diff --git a/Cargo.toml b/Cargo.toml index 179f2e6..672b4c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,11 +18,7 @@ features = ["std"] [dependencies] -[build-dependencies] -rustc_version = "0.2" - [features] default = ["std"] std = [] i128 = [] -int_to_from_bytes = [] diff --git a/build.rs b/build.rs index 138f831..3e425e3 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,3 @@ -extern crate rustc_version; - use std::env; use std::io::Write; use std::process::{Command, Stdio}; @@ -11,17 +9,17 @@ fn main() { panic!("i128 support was not detected!"); } - match rustc_version::version_meta() { - Ok(ref meta) if meta.semver.major >= 1 && meta.semver.minor >= 32 => { - println!("cargo:rustc-cfg=int_to_from_bytes"); - } - Ok(ref meta) - if env::var_os("CARGO_FEATURE_INT_TO_FROM_BYTES").is_some() - && meta.channel == rustc_version::Channel::Stable => - { - panic!("`int_to_from_bytes` support was not stabilizations!"); - } - _ => {} + if probe(r#" + fn main() { + let bytes = 0x1234567890123456u64.to_ne_bytes(); + + assert_eq!(bytes, if cfg!(target_endian = "big") { + [0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56] + } else { + [0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12] + }); + }"#) { + println!("cargo:rustc-cfg=int_to_from_bytes"); } } diff --git a/src/int.rs b/src/int.rs index c1d5694..ab9853c 100644 --- a/src/int.rs +++ b/src/int.rs @@ -2,15 +2,11 @@ use core::mem::transmute; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use bounds::Bounded; +use ops::bytes::IntToFromBytes; use ops::checked::*; use ops::saturating::Saturating; use {Num, NumCast}; -pub trait Layout { - /// The type representation as a byte array. - type Bytes; -} - pub trait PrimInt: Sized + Copy @@ -31,7 +27,7 @@ pub trait PrimInt: + CheckedMul + CheckedDiv + Saturating - + Layout + + IntToFromBytes { /// Returns the number of ones in the binary representation of `self`. /// @@ -285,98 +281,6 @@ pub trait PrimInt: /// assert_eq!(2i32.pow(4), 16); /// ``` fn pow(self, exp: u32) -> Self; - - /// Return the memory representation of this integer as a byte array in big-endian byte order. - /// - /// # Examples - /// - /// ``` - /// use num_traits::PrimInt; - /// - /// let bytes = 0x12345678u32.to_be_bytes(); - /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]); - /// ``` - fn to_be_bytes(self) -> Self::Bytes; - - /// Return the memory representation of this integer as a byte array in little-endian byte order. - /// - /// # Examples - /// - /// ``` - /// use num_traits::PrimInt; - /// - /// let bytes = 0x12345678u32.to_le_bytes(); - /// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]); - /// ``` - fn to_le_bytes(self) -> Self::Bytes; - - /// Return the memory representation of this integer as a byte array in native byte order. - /// - /// As the target platform's native endianness is used, - /// portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. - /// - /// [`to_be_bytes`]: #method.to_be_bytes - /// [`to_le_bytes`]: #method.to_le_bytes - /// - /// # Examples - /// - /// ``` - /// use num_traits::PrimInt; - /// - /// let bytes = 0x12345678u32.to_ne_bytes(); - /// assert_eq!(bytes, if cfg!(target_endian = "big") { - /// [0x12, 0x34, 0x56, 0x78] - /// } else { - /// [0x78, 0x56, 0x34, 0x12] - /// }); - /// ``` - fn to_ne_bytes(self) -> Self::Bytes; - - /// Create an integer value from its representation as a byte array in big endian. - /// - /// # Examples - /// - /// ``` - /// use num_traits::PrimInt; - /// - /// let value = u32::from_be_bytes([0x12, 0x34, 0x56, 0x78]); - /// assert_eq!(value, 0x12345678); - /// ``` - fn from_be_bytes(bytes: Self::Bytes) -> Self; - - /// Create an integer value from its representation as a byte array in little endian. - /// - /// # Examples - /// - /// ``` - /// use num_traits::PrimInt; - /// - /// let value = u32::from_le_bytes([0x78, 0x56, 0x34, 0x12]); - /// assert_eq!(value, 0x12345678); - /// ``` - fn from_le_bytes(bytes: Self::Bytes) -> Self; - - /// Create an integer value from its memory representation as a byte array in native endianness. - /// - /// As the target platform's native endianness is used, - /// portable code likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as appropriate instead. - /// - /// [`from_be_bytes`]: #method.from_be_bytes - /// [`from_le_bytes`]: #method.from_le_bytes - /// - /// # Examples - /// - /// ``` - /// use num_traits::PrimInt; - /// - /// let value = u32::from_ne_bytes(if cfg!(target_endian = "big") { - /// [0x12, 0x34, 0x56, 0x78] - /// } else { - /// [0x78, 0x56, 0x34, 0x12] - /// }); - /// assert_eq!(value, 0x12345678); - /// ``` - fn from_ne_bytes(bytes: Self::Bytes) -> Self; } macro_rules! prim_int_impl { @@ -461,83 +365,77 @@ macro_rules! prim_int_impl { fn pow(self, exp: u32) -> Self { <$T>::pow(self, exp) } + } + + #[cfg(feature = "int_to_from_bytes")] + impl IntToFromBytes for $T { + type Bytes = [u8; $L]; - #[cfg(feature = "int_to_from_bytes")] #[inline] fn to_be_bytes(self) -> Self::Bytes { <$T>::to_be_bytes(self) } - #[cfg(feature = "int_to_from_bytes")] #[inline] fn to_le_bytes(self) -> Self::Bytes { <$T>::to_le_bytes(self) } - #[cfg(feature = "int_to_from_bytes")] #[inline] fn to_ne_bytes(self) -> Self::Bytes { <$T>::to_ne_bytes(self) } - #[cfg(feature = "int_to_from_bytes")] #[inline] fn from_be_bytes(bytes: Self::Bytes) -> Self { <$T>::from_be_bytes(bytes) } - #[cfg(feature = "int_to_from_bytes")] #[inline] fn from_le_bytes(bytes: Self::Bytes) -> Self { <$T>::from_le_bytes(bytes) } - #[cfg(feature = "int_to_from_bytes")] #[inline] fn from_ne_bytes(bytes: Self::Bytes) -> Self { <$T>::from_ne_bytes(bytes) } + } + + #[cfg(not(feature = "int_to_from_bytes"))] + impl IntToFromBytes for $T { + type Bytes = [u8; $L]; - #[cfg(not(feature = "int_to_from_bytes"))] #[inline] fn to_be_bytes(self) -> Self::Bytes { <$T>::to_ne_bytes(<$T>::to_be(self)) } - #[cfg(not(feature = "int_to_from_bytes"))] #[inline] fn to_le_bytes(self) -> Self::Bytes { <$T>::to_ne_bytes(<$T>::to_le(self)) } - #[cfg(not(feature = "int_to_from_bytes"))] #[inline] fn to_ne_bytes(self) -> Self::Bytes { unsafe { transmute(self) } } - #[cfg(not(feature = "int_to_from_bytes"))] #[inline] fn from_be_bytes(bytes: Self::Bytes) -> Self { Self::from_be(Self::from_ne_bytes(bytes)) } - #[cfg(not(feature = "int_to_from_bytes"))] #[inline] fn from_le_bytes(bytes: Self::Bytes) -> Self { Self::from_le(Self::from_ne_bytes(bytes)) } - #[cfg(not(feature = "int_to_from_bytes"))] #[inline] fn from_ne_bytes(bytes: Self::Bytes) -> Self { unsafe { transmute(bytes) } } } - - impl Layout for $T { - type Bytes = [u8; $L]; - } }; } diff --git a/src/lib.rs b/src/lib.rs index 76f4e55..d6bef05 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,8 @@ pub use float::FloatConst; // pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`. pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive}; pub use identities::{one, zero, One, Zero}; -pub use int::{Layout, PrimInt}; +pub use int::PrimInt; +pub use ops::bytes::IntToFromBytes; pub use ops::checked::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, }; diff --git a/src/ops/bytes.rs b/src/ops/bytes.rs new file mode 100644 index 0000000..b07d3e0 --- /dev/null +++ b/src/ops/bytes.rs @@ -0,0 +1,95 @@ +pub trait IntToFromBytes { + type Bytes; + + /// Return the memory representation of this integer as a byte array in big-endian byte order. + /// + /// # Examples + /// + /// ``` + /// use num_traits::IntToFromBytes; + /// + /// let bytes = 0x12345678u32.to_be_bytes(); + /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]); + /// ``` + fn to_be_bytes(self) -> Self::Bytes; + + /// Return the memory representation of this integer as a byte array in little-endian byte order. + /// + /// # Examples + /// + /// ``` + /// use num_traits::IntToFromBytes; + /// + /// let bytes = 0x12345678u32.to_le_bytes(); + /// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]); + /// ``` + fn to_le_bytes(self) -> Self::Bytes; + + /// Return the memory representation of this integer as a byte array in native byte order. + /// + /// As the target platform's native endianness is used, + /// portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. + /// + /// [`to_be_bytes`]: #method.to_be_bytes + /// [`to_le_bytes`]: #method.to_le_bytes + /// + /// # Examples + /// + /// ``` + /// use num_traits::IntToFromBytes; + /// + /// let bytes = 0x12345678u32.to_ne_bytes(); + /// assert_eq!(bytes, if cfg!(target_endian = "big") { + /// [0x12, 0x34, 0x56, 0x78] + /// } else { + /// [0x78, 0x56, 0x34, 0x12] + /// }); + /// ``` + fn to_ne_bytes(self) -> Self::Bytes; + + /// Create an integer value from its representation as a byte array in big endian. + /// + /// # Examples + /// + /// ``` + /// use num_traits::IntToFromBytes; + /// + /// let value = u32::from_be_bytes([0x12, 0x34, 0x56, 0x78]); + /// assert_eq!(value, 0x12345678); + /// ``` + fn from_be_bytes(bytes: Self::Bytes) -> Self; + + /// Create an integer value from its representation as a byte array in little endian. + /// + /// # Examples + /// + /// ``` + /// use num_traits::IntToFromBytes; + /// + /// let value = u32::from_le_bytes([0x78, 0x56, 0x34, 0x12]); + /// assert_eq!(value, 0x12345678); + /// ``` + fn from_le_bytes(bytes: Self::Bytes) -> Self; + + /// Create an integer value from its memory representation as a byte array in native endianness. + /// + /// As the target platform's native endianness is used, + /// portable code likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as appropriate instead. + /// + /// [`from_be_bytes`]: #method.from_be_bytes + /// [`from_le_bytes`]: #method.from_le_bytes + /// + /// # Examples + /// + /// ``` + /// use num_traits::IntToFromBytes; + /// + /// let value = u32::from_ne_bytes(if cfg!(target_endian = "big") { + /// [0x12, 0x34, 0x56, 0x78] + /// } else { + /// [0x78, 0x56, 0x34, 0x12] + /// }); + /// assert_eq!(value, 0x12345678); + /// ``` + fn from_ne_bytes(bytes: Self::Bytes) -> Self; +} diff --git a/src/ops/mod.rs b/src/ops/mod.rs index fd1695d..b39dd4a 100644 --- a/src/ops/mod.rs +++ b/src/ops/mod.rs @@ -3,3 +3,4 @@ pub mod inv; pub mod mul_add; pub mod saturating; pub mod wrapping; +pub mod bytes; \ No newline at end of file From 2d2cba0b26da06745aa06486c0479b6227b38f07 Mon Sep 17 00:00:00 2001 From: Flier Lu Date: Fri, 1 Mar 2019 18:24:20 +0800 Subject: [PATCH 5/6] extract int_to_from_bytes_impl macro --- src/int.rs | 97 +++++++----------------------------------------- src/ops/bytes.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 84 deletions(-) diff --git a/src/int.rs b/src/int.rs index ab9853c..d7bda34 100644 --- a/src/int.rs +++ b/src/int.rs @@ -1,4 +1,3 @@ -use core::mem::transmute; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use bounds::Bounded; @@ -284,7 +283,7 @@ pub trait PrimInt: } macro_rules! prim_int_impl { - ($T:ty, $S:ty, $U:ty, $L:expr) => { + ($T:ty, $S:ty, $U:ty) => { impl PrimInt for $T { #[inline] fn count_ones(self) -> u32 { @@ -366,91 +365,21 @@ macro_rules! prim_int_impl { <$T>::pow(self, exp) } } - - #[cfg(feature = "int_to_from_bytes")] - impl IntToFromBytes for $T { - type Bytes = [u8; $L]; - - #[inline] - fn to_be_bytes(self) -> Self::Bytes { - <$T>::to_be_bytes(self) - } - - #[inline] - fn to_le_bytes(self) -> Self::Bytes { - <$T>::to_le_bytes(self) - } - - #[inline] - fn to_ne_bytes(self) -> Self::Bytes { - <$T>::to_ne_bytes(self) - } - - #[inline] - fn from_be_bytes(bytes: Self::Bytes) -> Self { - <$T>::from_be_bytes(bytes) - } - - #[inline] - fn from_le_bytes(bytes: Self::Bytes) -> Self { - <$T>::from_le_bytes(bytes) - } - - #[inline] - fn from_ne_bytes(bytes: Self::Bytes) -> Self { - <$T>::from_ne_bytes(bytes) - } - } - - #[cfg(not(feature = "int_to_from_bytes"))] - impl IntToFromBytes for $T { - type Bytes = [u8; $L]; - - #[inline] - fn to_be_bytes(self) -> Self::Bytes { - <$T>::to_ne_bytes(<$T>::to_be(self)) - } - - #[inline] - fn to_le_bytes(self) -> Self::Bytes { - <$T>::to_ne_bytes(<$T>::to_le(self)) - } - - #[inline] - fn to_ne_bytes(self) -> Self::Bytes { - unsafe { transmute(self) } - } - - #[inline] - fn from_be_bytes(bytes: Self::Bytes) -> Self { - Self::from_be(Self::from_ne_bytes(bytes)) - } - - #[inline] - fn from_le_bytes(bytes: Self::Bytes) -> Self { - Self::from_le(Self::from_ne_bytes(bytes)) - } - - #[inline] - fn from_ne_bytes(bytes: Self::Bytes) -> Self { - unsafe { transmute(bytes) } - } - } }; } // prim_int_impl!(type, signed, unsigned); -prim_int_impl!(u8, i8, u8, 1); -prim_int_impl!(u16, i16, u16, 2); -prim_int_impl!(u32, i32, u32, 4); -prim_int_impl!(u64, i64, u64, 8); +prim_int_impl!(u8, i8, u8); +prim_int_impl!(u16, i16, u16); +prim_int_impl!(u32, i32, u32); +prim_int_impl!(u64, i64, u64); #[cfg(has_i128)] -prim_int_impl!(u128, i128, u128, 16); -prim_int_impl!(usize, isize, usize, 8); -prim_int_impl!(i8, i8, u8, 1); -prim_int_impl!(i16, i16, u16, 2); -prim_int_impl!(i32, i32, u32, 4); -prim_int_impl!(i64, i64, u64, 8); +prim_int_impl!(u128, i128, u128); +prim_int_impl!(usize, isize, usize); +prim_int_impl!(i8, i8, u8); +prim_int_impl!(i16, i16, u16); +prim_int_impl!(i32, i32, u32); +prim_int_impl!(i64, i64, u64); #[cfg(has_i128)] -prim_int_impl!(i128, i128, u128, 16); -prim_int_impl!(isize, isize, usize, 8); +prim_int_impl!(i128, i128, u128); +prim_int_impl!(isize, isize, usize); diff --git a/src/ops/bytes.rs b/src/ops/bytes.rs index b07d3e0..802f0cf 100644 --- a/src/ops/bytes.rs +++ b/src/ops/bytes.rs @@ -1,3 +1,5 @@ +use core::mem::transmute; + pub trait IntToFromBytes { type Bytes; @@ -93,3 +95,93 @@ pub trait IntToFromBytes { /// ``` fn from_ne_bytes(bytes: Self::Bytes) -> Self; } + +macro_rules! int_to_from_bytes_impl { + ($T:ty, $L:expr) => { + #[cfg(feature = "int_to_from_bytes")] + impl IntToFromBytes for $T { + type Bytes = [u8; $L]; + + #[inline] + fn to_be_bytes(self) -> Self::Bytes { + <$T>::to_be_bytes(self) + } + + #[inline] + fn to_le_bytes(self) -> Self::Bytes { + <$T>::to_le_bytes(self) + } + + #[inline] + fn to_ne_bytes(self) -> Self::Bytes { + <$T>::to_ne_bytes(self) + } + + #[inline] + fn from_be_bytes(bytes: Self::Bytes) -> Self { + <$T>::from_be_bytes(bytes) + } + + #[inline] + fn from_le_bytes(bytes: Self::Bytes) -> Self { + <$T>::from_le_bytes(bytes) + } + + #[inline] + fn from_ne_bytes(bytes: Self::Bytes) -> Self { + <$T>::from_ne_bytes(bytes) + } + } + + #[cfg(not(feature = "int_to_from_bytes"))] + impl IntToFromBytes for $T { + type Bytes = [u8; $L]; + + #[inline] + fn to_be_bytes(self) -> Self::Bytes { + <$T>::to_ne_bytes(<$T>::to_be(self)) + } + + #[inline] + fn to_le_bytes(self) -> Self::Bytes { + <$T>::to_ne_bytes(<$T>::to_le(self)) + } + + #[inline] + fn to_ne_bytes(self) -> Self::Bytes { + unsafe { transmute(self) } + } + + #[inline] + fn from_be_bytes(bytes: Self::Bytes) -> Self { + Self::from_be(Self::from_ne_bytes(bytes)) + } + + #[inline] + fn from_le_bytes(bytes: Self::Bytes) -> Self { + Self::from_le(Self::from_ne_bytes(bytes)) + } + + #[inline] + fn from_ne_bytes(bytes: Self::Bytes) -> Self { + unsafe { transmute(bytes) } + } + } + }; +} + +// int_to_from_bytes_impl!(type, signed, unsigned); +int_to_from_bytes_impl!(u8, 1); +int_to_from_bytes_impl!(u16, 2); +int_to_from_bytes_impl!(u32, 4); +int_to_from_bytes_impl!(u64, 8); +#[cfg(has_i128)] +int_to_from_bytes_impl!(u128, 16); +int_to_from_bytes_impl!(usize, 8); +int_to_from_bytes_impl!(i8, 1); +int_to_from_bytes_impl!(i16, 2); +int_to_from_bytes_impl!(i32, 4); +int_to_from_bytes_impl!(i64, 8); +#[cfg(has_i128)] +int_to_from_bytes_impl!(i128, 16); +int_to_from_bytes_impl!(isize, 8); From 51a9e6114d64f90b5f1401944f76691d51130c50 Mon Sep 17 00:00:00 2001 From: Flier Lu Date: Fri, 8 Mar 2019 15:22:00 +0800 Subject: [PATCH 6/6] bind traits for Bytes --- src/ops/bytes.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ops/bytes.rs b/src/ops/bytes.rs index 802f0cf..9ceddb5 100644 --- a/src/ops/bytes.rs +++ b/src/ops/bytes.rs @@ -1,7 +1,21 @@ +use core::borrow::{Borrow, BorrowMut}; +use core::cmp::{Eq, Ord, PartialEq, PartialOrd}; +use core::fmt::Debug; +use core::hash::Hash; use core::mem::transmute; pub trait IntToFromBytes { - type Bytes; + type Bytes: Debug + + AsRef<[u8]> + + AsMut<[u8]> + + PartialEq + + Eq + + PartialOrd + + Ord + + Hash + + Borrow<[u8]> + + BorrowMut<[u8]> + + Default; /// Return the memory representation of this integer as a byte array in big-endian byte order. ///