1 use core::borrow::{Borrow, BorrowMut}; 2 use core::cmp::{Eq, Ord, PartialEq, PartialOrd}; 3 use core::fmt::Debug; 4 use core::hash::Hash; 5 6 pub trait NumBytes: 7 Debug 8 + AsRef<[u8]> 9 + AsMut<[u8]> 10 + PartialEq 11 + Eq 12 + PartialOrd 13 + Ord 14 + Hash 15 + Borrow<[u8]> 16 + BorrowMut<[u8]> 17 { 18 } 19 20 impl<T> NumBytes for T where 21 T: Debug 22 + AsRef<[u8]> 23 + AsMut<[u8]> 24 + PartialEq 25 + Eq 26 + PartialOrd 27 + Ord 28 + Hash 29 + Borrow<[u8]> 30 + BorrowMut<[u8]> 31 + ?Sized 32 { 33 } 34 35 pub trait ToBytes { 36 type Bytes: NumBytes; 37 38 /// Return the memory representation of this number as a byte array in big-endian byte order. 39 /// 40 /// # Examples 41 /// 42 /// ``` 43 /// use num_traits::ToBytes; 44 /// 45 /// let bytes = ToBytes::to_be_bytes(&0x12345678u32); 46 /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]); 47 /// ``` to_be_bytes(&self) -> Self::Bytes48 fn to_be_bytes(&self) -> Self::Bytes; 49 50 /// Return the memory representation of this number as a byte array in little-endian byte order. 51 /// 52 /// # Examples 53 /// 54 /// ``` 55 /// use num_traits::ToBytes; 56 /// 57 /// let bytes = ToBytes::to_le_bytes(&0x12345678u32); 58 /// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]); 59 /// ``` to_le_bytes(&self) -> Self::Bytes60 fn to_le_bytes(&self) -> Self::Bytes; 61 62 /// Return the memory representation of this number as a byte array in native byte order. 63 /// 64 /// As the target platform's native endianness is used, 65 /// portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. 66 /// 67 /// [`to_be_bytes`]: #method.to_be_bytes 68 /// [`to_le_bytes`]: #method.to_le_bytes 69 /// 70 /// # Examples 71 /// 72 /// ``` 73 /// use num_traits::ToBytes; 74 /// 75 /// #[cfg(target_endian = "big")] 76 /// let expected = [0x12, 0x34, 0x56, 0x78]; 77 /// 78 /// #[cfg(target_endian = "little")] 79 /// let expected = [0x78, 0x56, 0x34, 0x12]; 80 /// 81 /// let bytes = ToBytes::to_ne_bytes(&0x12345678u32); 82 /// assert_eq!(bytes, expected) 83 /// ``` to_ne_bytes(&self) -> Self::Bytes84 fn to_ne_bytes(&self) -> Self::Bytes { 85 #[cfg(target_endian = "big")] 86 let bytes = self.to_be_bytes(); 87 #[cfg(target_endian = "little")] 88 let bytes = self.to_le_bytes(); 89 bytes 90 } 91 } 92 93 pub trait FromBytes: Sized { 94 type Bytes: NumBytes + ?Sized; 95 96 /// Create a number from its representation as a byte array in big endian. 97 /// 98 /// # Examples 99 /// 100 /// ``` 101 /// use num_traits::FromBytes; 102 /// 103 /// let value: u32 = FromBytes::from_be_bytes(&[0x12, 0x34, 0x56, 0x78]); 104 /// assert_eq!(value, 0x12345678); 105 /// ``` from_be_bytes(bytes: &Self::Bytes) -> Self106 fn from_be_bytes(bytes: &Self::Bytes) -> Self; 107 108 /// Create a number from its representation as a byte array in little endian. 109 /// 110 /// # Examples 111 /// 112 /// ``` 113 /// use num_traits::FromBytes; 114 /// 115 /// let value: u32 = FromBytes::from_le_bytes(&[0x78, 0x56, 0x34, 0x12]); 116 /// assert_eq!(value, 0x12345678); 117 /// ``` from_le_bytes(bytes: &Self::Bytes) -> Self118 fn from_le_bytes(bytes: &Self::Bytes) -> Self; 119 120 /// Create a number from its memory representation as a byte array in native endianness. 121 /// 122 /// As the target platform's native endianness is used, 123 /// portable code likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as appropriate instead. 124 /// 125 /// [`from_be_bytes`]: #method.from_be_bytes 126 /// [`from_le_bytes`]: #method.from_le_bytes 127 /// 128 /// # Examples 129 /// 130 /// ``` 131 /// use num_traits::FromBytes; 132 /// 133 /// #[cfg(target_endian = "big")] 134 /// let bytes = [0x12, 0x34, 0x56, 0x78]; 135 /// 136 /// #[cfg(target_endian = "little")] 137 /// let bytes = [0x78, 0x56, 0x34, 0x12]; 138 /// 139 /// let value: u32 = FromBytes::from_ne_bytes(&bytes); 140 /// assert_eq!(value, 0x12345678) 141 /// ``` from_ne_bytes(bytes: &Self::Bytes) -> Self142 fn from_ne_bytes(bytes: &Self::Bytes) -> Self { 143 #[cfg(target_endian = "big")] 144 let this = Self::from_be_bytes(bytes); 145 #[cfg(target_endian = "little")] 146 let this = Self::from_le_bytes(bytes); 147 this 148 } 149 } 150 151 macro_rules! float_to_from_bytes_impl { 152 ($T:ty, $L:expr) => { 153 impl ToBytes for $T { 154 type Bytes = [u8; $L]; 155 156 #[inline] 157 fn to_be_bytes(&self) -> Self::Bytes { 158 <$T>::to_be_bytes(*self) 159 } 160 161 #[inline] 162 fn to_le_bytes(&self) -> Self::Bytes { 163 <$T>::to_le_bytes(*self) 164 } 165 166 #[inline] 167 fn to_ne_bytes(&self) -> Self::Bytes { 168 <$T>::to_ne_bytes(*self) 169 } 170 } 171 172 impl FromBytes for $T { 173 type Bytes = [u8; $L]; 174 175 #[inline] 176 fn from_be_bytes(bytes: &Self::Bytes) -> Self { 177 <$T>::from_be_bytes(*bytes) 178 } 179 180 #[inline] 181 fn from_le_bytes(bytes: &Self::Bytes) -> Self { 182 <$T>::from_le_bytes(*bytes) 183 } 184 185 #[inline] 186 fn from_ne_bytes(bytes: &Self::Bytes) -> Self { 187 <$T>::from_ne_bytes(*bytes) 188 } 189 } 190 }; 191 } 192 193 macro_rules! int_to_from_bytes_impl { 194 ($T:ty, $L:expr) => { 195 impl ToBytes for $T { 196 type Bytes = [u8; $L]; 197 198 #[inline] 199 fn to_be_bytes(&self) -> Self::Bytes { 200 <$T>::to_be_bytes(*self) 201 } 202 203 #[inline] 204 fn to_le_bytes(&self) -> Self::Bytes { 205 <$T>::to_le_bytes(*self) 206 } 207 208 #[inline] 209 fn to_ne_bytes(&self) -> Self::Bytes { 210 <$T>::to_ne_bytes(*self) 211 } 212 } 213 214 impl FromBytes for $T { 215 type Bytes = [u8; $L]; 216 217 #[inline] 218 fn from_be_bytes(bytes: &Self::Bytes) -> Self { 219 <$T>::from_be_bytes(*bytes) 220 } 221 222 #[inline] 223 fn from_le_bytes(bytes: &Self::Bytes) -> Self { 224 <$T>::from_le_bytes(*bytes) 225 } 226 227 #[inline] 228 fn from_ne_bytes(bytes: &Self::Bytes) -> Self { 229 <$T>::from_ne_bytes(*bytes) 230 } 231 } 232 }; 233 } 234 235 int_to_from_bytes_impl!(u8, 1); 236 int_to_from_bytes_impl!(u16, 2); 237 int_to_from_bytes_impl!(u32, 4); 238 int_to_from_bytes_impl!(u64, 8); 239 int_to_from_bytes_impl!(u128, 16); 240 #[cfg(target_pointer_width = "64")] 241 int_to_from_bytes_impl!(usize, 8); 242 #[cfg(target_pointer_width = "32")] 243 int_to_from_bytes_impl!(usize, 4); 244 245 int_to_from_bytes_impl!(i8, 1); 246 int_to_from_bytes_impl!(i16, 2); 247 int_to_from_bytes_impl!(i32, 4); 248 int_to_from_bytes_impl!(i64, 8); 249 int_to_from_bytes_impl!(i128, 16); 250 #[cfg(target_pointer_width = "64")] 251 int_to_from_bytes_impl!(isize, 8); 252 #[cfg(target_pointer_width = "32")] 253 int_to_from_bytes_impl!(isize, 4); 254 255 float_to_from_bytes_impl!(f32, 4); 256 float_to_from_bytes_impl!(f64, 8); 257 258 #[cfg(test)] 259 mod tests { 260 use super::*; 261 262 macro_rules! check_to_from_bytes { 263 ($( $ty:ty )+) => {$({ 264 let n = 1; 265 let be = <$ty as ToBytes>::to_be_bytes(&n); 266 let le = <$ty as ToBytes>::to_le_bytes(&n); 267 let ne = <$ty as ToBytes>::to_ne_bytes(&n); 268 269 assert_eq!(*be.last().unwrap(), 1); 270 assert_eq!(*le.first().unwrap(), 1); 271 if cfg!(target_endian = "big") { 272 assert_eq!(*ne.last().unwrap(), 1); 273 } else { 274 assert_eq!(*ne.first().unwrap(), 1); 275 } 276 277 assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n); 278 assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n); 279 if cfg!(target_endian = "big") { 280 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n); 281 } else { 282 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n); 283 } 284 })+} 285 } 286 287 #[test] convert_between_int_and_bytes()288 fn convert_between_int_and_bytes() { 289 check_to_from_bytes!(u8 u16 u32 u64 u128 usize); 290 check_to_from_bytes!(i8 i16 i32 i64 i128 isize); 291 } 292 293 #[test] convert_between_float_and_bytes()294 fn convert_between_float_and_bytes() { 295 macro_rules! check_to_from_bytes { 296 ($( $ty:ty )+) => {$( 297 let n: $ty = 3.14; 298 299 let be = <$ty as ToBytes>::to_be_bytes(&n); 300 let le = <$ty as ToBytes>::to_le_bytes(&n); 301 let ne = <$ty as ToBytes>::to_ne_bytes(&n); 302 303 assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n); 304 assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n); 305 if cfg!(target_endian = "big") { 306 assert_eq!(ne, be); 307 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n); 308 } else { 309 assert_eq!(ne, le); 310 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n); 311 } 312 )+} 313 } 314 315 check_to_from_bytes!(f32 f64); 316 } 317 } 318