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 #[cfg(not(has_int_to_from_bytes))] 6 use core::mem::transmute; 7 8 pub trait NumBytes: 9 Debug 10 + AsRef<[u8]> 11 + AsMut<[u8]> 12 + PartialEq 13 + Eq 14 + PartialOrd 15 + Ord 16 + Hash 17 + Borrow<[u8]> 18 + BorrowMut<[u8]> 19 { 20 } 21 22 impl<T> NumBytes for T where 23 T: Debug 24 + AsRef<[u8]> 25 + AsMut<[u8]> 26 + PartialEq 27 + Eq 28 + PartialOrd 29 + Ord 30 + Hash 31 + Borrow<[u8]> 32 + BorrowMut<[u8]> 33 + ?Sized 34 { 35 } 36 37 pub trait ToBytes { 38 type Bytes: NumBytes; 39 40 /// Return the memory representation of this number as a byte array in big-endian byte order. 41 /// 42 /// # Examples 43 /// 44 /// ``` 45 /// use num_traits::ToBytes; 46 /// 47 /// let bytes = ToBytes::to_be_bytes(&0x12345678u32); 48 /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]); 49 /// ``` to_be_bytes(&self) -> Self::Bytes50 fn to_be_bytes(&self) -> Self::Bytes; 51 52 /// Return the memory representation of this number as a byte array in little-endian byte order. 53 /// 54 /// # Examples 55 /// 56 /// ``` 57 /// use num_traits::ToBytes; 58 /// 59 /// let bytes = ToBytes::to_le_bytes(&0x12345678u32); 60 /// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]); 61 /// ``` to_le_bytes(&self) -> Self::Bytes62 fn to_le_bytes(&self) -> Self::Bytes; 63 64 /// Return the memory representation of this number as a byte array in native byte order. 65 /// 66 /// As the target platform's native endianness is used, 67 /// portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. 68 /// 69 /// [`to_be_bytes`]: #method.to_be_bytes 70 /// [`to_le_bytes`]: #method.to_le_bytes 71 /// 72 /// # Examples 73 /// 74 /// ``` 75 /// use num_traits::ToBytes; 76 /// 77 /// #[cfg(target_endian = "big")] 78 /// let expected = [0x12, 0x34, 0x56, 0x78]; 79 /// 80 /// #[cfg(target_endian = "little")] 81 /// let expected = [0x78, 0x56, 0x34, 0x12]; 82 /// 83 /// let bytes = ToBytes::to_ne_bytes(&0x12345678u32); 84 /// assert_eq!(bytes, expected) 85 /// ``` to_ne_bytes(&self) -> Self::Bytes86 fn to_ne_bytes(&self) -> Self::Bytes { 87 #[cfg(target_endian = "big")] 88 let bytes = self.to_be_bytes(); 89 #[cfg(target_endian = "little")] 90 let bytes = self.to_le_bytes(); 91 bytes 92 } 93 } 94 95 pub trait FromBytes: Sized { 96 type Bytes: NumBytes + ?Sized; 97 98 /// Create a number from its representation as a byte array in big endian. 99 /// 100 /// # Examples 101 /// 102 /// ``` 103 /// use num_traits::FromBytes; 104 /// 105 /// let value: u32 = FromBytes::from_be_bytes(&[0x12, 0x34, 0x56, 0x78]); 106 /// assert_eq!(value, 0x12345678); 107 /// ``` from_be_bytes(bytes: &Self::Bytes) -> Self108 fn from_be_bytes(bytes: &Self::Bytes) -> Self; 109 110 /// Create a number from its representation as a byte array in little endian. 111 /// 112 /// # Examples 113 /// 114 /// ``` 115 /// use num_traits::FromBytes; 116 /// 117 /// let value: u32 = FromBytes::from_le_bytes(&[0x78, 0x56, 0x34, 0x12]); 118 /// assert_eq!(value, 0x12345678); 119 /// ``` from_le_bytes(bytes: &Self::Bytes) -> Self120 fn from_le_bytes(bytes: &Self::Bytes) -> Self; 121 122 /// Create a number from its memory representation as a byte array in native endianness. 123 /// 124 /// As the target platform's native endianness is used, 125 /// portable code likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as appropriate instead. 126 /// 127 /// [`from_be_bytes`]: #method.from_be_bytes 128 /// [`from_le_bytes`]: #method.from_le_bytes 129 /// 130 /// # Examples 131 /// 132 /// ``` 133 /// use num_traits::FromBytes; 134 /// 135 /// #[cfg(target_endian = "big")] 136 /// let bytes = [0x12, 0x34, 0x56, 0x78]; 137 /// 138 /// #[cfg(target_endian = "little")] 139 /// let bytes = [0x78, 0x56, 0x34, 0x12]; 140 /// 141 /// let value: u32 = FromBytes::from_ne_bytes(&bytes); 142 /// assert_eq!(value, 0x12345678) 143 /// ``` from_ne_bytes(bytes: &Self::Bytes) -> Self144 fn from_ne_bytes(bytes: &Self::Bytes) -> Self { 145 #[cfg(target_endian = "big")] 146 let this = Self::from_be_bytes(bytes); 147 #[cfg(target_endian = "little")] 148 let this = Self::from_le_bytes(bytes); 149 this 150 } 151 } 152 153 macro_rules! float_to_from_bytes_impl { 154 ($T:ty, $L:expr) => { 155 #[cfg(has_float_to_from_bytes)] 156 impl ToBytes for $T { 157 type Bytes = [u8; $L]; 158 159 #[inline] 160 fn to_be_bytes(&self) -> Self::Bytes { 161 <$T>::to_be_bytes(*self) 162 } 163 164 #[inline] 165 fn to_le_bytes(&self) -> Self::Bytes { 166 <$T>::to_le_bytes(*self) 167 } 168 169 #[inline] 170 fn to_ne_bytes(&self) -> Self::Bytes { 171 <$T>::to_ne_bytes(*self) 172 } 173 } 174 175 #[cfg(has_float_to_from_bytes)] 176 impl FromBytes for $T { 177 type Bytes = [u8; $L]; 178 179 #[inline] 180 fn from_be_bytes(bytes: &Self::Bytes) -> Self { 181 <$T>::from_be_bytes(*bytes) 182 } 183 184 #[inline] 185 fn from_le_bytes(bytes: &Self::Bytes) -> Self { 186 <$T>::from_le_bytes(*bytes) 187 } 188 189 #[inline] 190 fn from_ne_bytes(bytes: &Self::Bytes) -> Self { 191 <$T>::from_ne_bytes(*bytes) 192 } 193 } 194 195 #[cfg(not(has_float_to_from_bytes))] 196 impl ToBytes for $T { 197 type Bytes = [u8; $L]; 198 199 #[inline] 200 fn to_be_bytes(&self) -> Self::Bytes { 201 ToBytes::to_be_bytes(&self.to_bits()) 202 } 203 204 #[inline] 205 fn to_le_bytes(&self) -> Self::Bytes { 206 ToBytes::to_le_bytes(&self.to_bits()) 207 } 208 209 #[inline] 210 fn to_ne_bytes(&self) -> Self::Bytes { 211 ToBytes::to_ne_bytes(&self.to_bits()) 212 } 213 } 214 215 #[cfg(not(has_float_to_from_bytes))] 216 impl FromBytes for $T { 217 type Bytes = [u8; $L]; 218 219 #[inline] 220 fn from_be_bytes(bytes: &Self::Bytes) -> Self { 221 Self::from_bits(FromBytes::from_be_bytes(bytes)) 222 } 223 224 #[inline] 225 fn from_le_bytes(bytes: &Self::Bytes) -> Self { 226 Self::from_bits(FromBytes::from_le_bytes(bytes)) 227 } 228 229 #[inline] 230 fn from_ne_bytes(bytes: &Self::Bytes) -> Self { 231 Self::from_bits(FromBytes::from_ne_bytes(bytes)) 232 } 233 } 234 }; 235 } 236 237 macro_rules! int_to_from_bytes_impl { 238 ($T:ty, $L:expr) => { 239 #[cfg(has_int_to_from_bytes)] 240 impl ToBytes for $T { 241 type Bytes = [u8; $L]; 242 243 #[inline] 244 fn to_be_bytes(&self) -> Self::Bytes { 245 <$T>::to_be_bytes(*self) 246 } 247 248 #[inline] 249 fn to_le_bytes(&self) -> Self::Bytes { 250 <$T>::to_le_bytes(*self) 251 } 252 253 #[inline] 254 fn to_ne_bytes(&self) -> Self::Bytes { 255 <$T>::to_ne_bytes(*self) 256 } 257 } 258 259 #[cfg(has_int_to_from_bytes)] 260 impl FromBytes for $T { 261 type Bytes = [u8; $L]; 262 263 #[inline] 264 fn from_be_bytes(bytes: &Self::Bytes) -> Self { 265 <$T>::from_be_bytes(*bytes) 266 } 267 268 #[inline] 269 fn from_le_bytes(bytes: &Self::Bytes) -> Self { 270 <$T>::from_le_bytes(*bytes) 271 } 272 273 #[inline] 274 fn from_ne_bytes(bytes: &Self::Bytes) -> Self { 275 <$T>::from_ne_bytes(*bytes) 276 } 277 } 278 279 #[cfg(not(has_int_to_from_bytes))] 280 impl ToBytes for $T { 281 type Bytes = [u8; $L]; 282 283 #[inline] 284 fn to_be_bytes(&self) -> Self::Bytes { 285 <$T as ToBytes>::to_ne_bytes(&<$T>::to_be(*self)) 286 } 287 288 #[inline] 289 fn to_le_bytes(&self) -> Self::Bytes { 290 <$T as ToBytes>::to_ne_bytes(&<$T>::to_le(*self)) 291 } 292 293 #[inline] 294 fn to_ne_bytes(&self) -> Self::Bytes { 295 unsafe { transmute(*self) } 296 } 297 } 298 299 #[cfg(not(has_int_to_from_bytes))] 300 impl FromBytes for $T { 301 type Bytes = [u8; $L]; 302 303 #[inline] 304 fn from_be_bytes(bytes: &Self::Bytes) -> Self { 305 Self::from_be(<Self as FromBytes>::from_ne_bytes(bytes)) 306 } 307 308 #[inline] 309 fn from_le_bytes(bytes: &Self::Bytes) -> Self { 310 Self::from_le(<Self as FromBytes>::from_ne_bytes(bytes)) 311 } 312 313 #[inline] 314 fn from_ne_bytes(bytes: &Self::Bytes) -> Self { 315 unsafe { transmute(*bytes) } 316 } 317 } 318 }; 319 } 320 321 int_to_from_bytes_impl!(u8, 1); 322 int_to_from_bytes_impl!(u16, 2); 323 int_to_from_bytes_impl!(u32, 4); 324 int_to_from_bytes_impl!(u64, 8); 325 int_to_from_bytes_impl!(u128, 16); 326 #[cfg(target_pointer_width = "64")] 327 int_to_from_bytes_impl!(usize, 8); 328 #[cfg(target_pointer_width = "32")] 329 int_to_from_bytes_impl!(usize, 4); 330 331 int_to_from_bytes_impl!(i8, 1); 332 int_to_from_bytes_impl!(i16, 2); 333 int_to_from_bytes_impl!(i32, 4); 334 int_to_from_bytes_impl!(i64, 8); 335 int_to_from_bytes_impl!(i128, 16); 336 #[cfg(target_pointer_width = "64")] 337 int_to_from_bytes_impl!(isize, 8); 338 #[cfg(target_pointer_width = "32")] 339 int_to_from_bytes_impl!(isize, 4); 340 341 float_to_from_bytes_impl!(f32, 4); 342 float_to_from_bytes_impl!(f64, 8); 343 344 #[cfg(test)] 345 mod tests { 346 use super::*; 347 348 macro_rules! check_to_from_bytes { 349 ($( $ty:ty )+) => {$({ 350 let n = 1; 351 let be = <$ty as ToBytes>::to_be_bytes(&n); 352 let le = <$ty as ToBytes>::to_le_bytes(&n); 353 let ne = <$ty as ToBytes>::to_ne_bytes(&n); 354 355 assert_eq!(*be.last().unwrap(), 1); 356 assert_eq!(*le.first().unwrap(), 1); 357 if cfg!(target_endian = "big") { 358 assert_eq!(*ne.last().unwrap(), 1); 359 } else { 360 assert_eq!(*ne.first().unwrap(), 1); 361 } 362 363 assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n); 364 assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n); 365 if cfg!(target_endian = "big") { 366 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n); 367 } else { 368 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n); 369 } 370 })+} 371 } 372 373 #[test] convert_between_int_and_bytes()374 fn convert_between_int_and_bytes() { 375 check_to_from_bytes!(u8 u16 u32 u64 u128 usize); 376 check_to_from_bytes!(i8 i16 i32 i64 i128 isize); 377 } 378 379 #[test] convert_between_float_and_bytes()380 fn convert_between_float_and_bytes() { 381 macro_rules! check_to_from_bytes { 382 ($( $ty:ty )+) => {$( 383 let n: $ty = 3.14; 384 385 let be = <$ty as ToBytes>::to_be_bytes(&n); 386 let le = <$ty as ToBytes>::to_le_bytes(&n); 387 let ne = <$ty as ToBytes>::to_ne_bytes(&n); 388 389 assert_eq!(<$ty as FromBytes>::from_be_bytes(&be), n); 390 assert_eq!(<$ty as FromBytes>::from_le_bytes(&le), n); 391 if cfg!(target_endian = "big") { 392 assert_eq!(ne, be); 393 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&be), n); 394 } else { 395 assert_eq!(ne, le); 396 assert_eq!(<$ty as FromBytes>::from_ne_bytes(&le), n); 397 } 398 )+} 399 } 400 401 check_to_from_bytes!(f32 f64); 402 } 403 } 404