1use core::borrow::{Borrow, BorrowMut};
2use core::cmp::{Eq, Ord, PartialEq, PartialOrd};
3use core::fmt::Debug;
4use core::hash::Hash;
5
6pub 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
20impl<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
35pub trait ToBytes {
36 type Bytes: NumBytes;
37
38 fn to_be_bytes(&self) -> Self::Bytes;
49
50 fn to_le_bytes(&self) -> Self::Bytes;
61
62 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
93pub trait FromBytes: Sized {
94 type Bytes: NumBytes + ?Sized;
95
96 fn from_be_bytes(bytes: &Self::Bytes) -> Self;
107
108 fn from_le_bytes(bytes: &Self::Bytes) -> Self;
119
120 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
151macro_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
193macro_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
235int_to_from_bytes_impl!(u8, 1);
236int_to_from_bytes_impl!(u16, 2);
237int_to_from_bytes_impl!(u32, 4);
238int_to_from_bytes_impl!(u64, 8);
239int_to_from_bytes_impl!(u128, 16);
240#[cfg(target_pointer_width = "64")]
241int_to_from_bytes_impl!(usize, 8);
242#[cfg(target_pointer_width = "32")]
243int_to_from_bytes_impl!(usize, 4);
244
245int_to_from_bytes_impl!(i8, 1);
246int_to_from_bytes_impl!(i16, 2);
247int_to_from_bytes_impl!(i32, 4);
248int_to_from_bytes_impl!(i64, 8);
249int_to_from_bytes_impl!(i128, 16);
250#[cfg(target_pointer_width = "64")]
251int_to_from_bytes_impl!(isize, 8);
252#[cfg(target_pointer_width = "32")]
253int_to_from_bytes_impl!(isize, 4);
254
255float_to_from_bytes_impl!(f32, 4);
256float_to_from_bytes_impl!(f64, 8);
257
258#[cfg(test)]
259mod 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]
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]
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}