1use core::{
67 convert::{TryFrom, TryInto},
68 fmt::{Binary, Debug, LowerHex, Octal, UpperHex},
69 hash::Hash,
70 num::TryFromIntError,
71};
72
73use super::*;
74
75pub trait ByteOrder:
88 Copy + Clone + Debug + Display + Eq + PartialEq + Ord + PartialOrd + Hash + private::Sealed
89{
90 #[doc(hidden)]
91 const ORDER: Order;
92}
93
94mod private {
95 pub trait Sealed {}
96
97 impl Sealed for super::BigEndian {}
98 impl Sealed for super::LittleEndian {}
99}
100
101#[allow(missing_copy_implementations, missing_debug_implementations)]
102#[doc(hidden)]
103pub enum Order {
104 BigEndian,
105 LittleEndian,
106}
107
108#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
112pub enum BigEndian {}
113
114impl ByteOrder for BigEndian {
115 const ORDER: Order = Order::BigEndian;
116}
117
118impl Display for BigEndian {
119 #[inline]
120 fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
121 match *self {}
122 }
123}
124
125#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
129pub enum LittleEndian {}
130
131impl ByteOrder for LittleEndian {
132 const ORDER: Order = Order::LittleEndian;
133}
134
135impl Display for LittleEndian {
136 #[inline]
137 fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
138 match *self {}
139 }
140}
141
142#[cfg(target_endian = "big")]
147pub type NativeEndian = BigEndian;
148
149#[cfg(target_endian = "little")]
154pub type NativeEndian = LittleEndian;
155
156pub type NetworkEndian = BigEndian;
160
161pub type BE = BigEndian;
163
164pub type LE = LittleEndian;
166
167macro_rules! impl_dbg_trait {
168 ($name:ident, $native:ident) => {
169 impl<O: ByteOrder> Debug for $name<O> {
170 #[inline]
171 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
172 f.debug_tuple(stringify!($name)).field(&self.get()).finish()
174 }
175 }
176 };
177}
178
179macro_rules! impl_dbg_traits {
180 ($name:ident, $native:ident, "floating point number") => {
181 #[cfg(not(no_fp_fmt_parse))]
182 impl_dbg_trait!($name, $native);
183
184 #[cfg(no_fp_fmt_parse)]
185 impl<O: ByteOrder> Debug for $name<O> {
186 #[inline]
187 fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
188 panic!("floating point support is turned off");
189 }
190 }
191 };
192 ($name:ident, $native:ident, "unsigned integer") => {
193 impl_dbg_traits!($name, $native, @all_types);
194 };
195 ($name:ident, $native:ident, "signed integer") => {
196 impl_dbg_traits!($name, $native, @all_types);
197 };
198 ($name:ident, $native:ident, @all_types) => {
199 impl_dbg_trait!($name, $native);
200 };
201}
202
203macro_rules! impl_fmt_trait {
204 ($name:ident, $native:ident, $trait:ident) => {
205 impl<O: ByteOrder> $trait for $name<O> {
206 #[inline(always)]
207 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
208 $trait::fmt(&self.get(), f)
209 }
210 }
211 };
212}
213
214macro_rules! impl_fmt_traits {
215 ($name:ident, $native:ident, "floating point number") => {
216 #[cfg(not(no_fp_fmt_parse))]
217 impl_fmt_trait!($name, $native, Display);
218 };
219 ($name:ident, $native:ident, "unsigned integer") => {
220 impl_fmt_traits!($name, $native, @all_types);
221 };
222 ($name:ident, $native:ident, "signed integer") => {
223 impl_fmt_traits!($name, $native, @all_types);
224 };
225 ($name:ident, $native:ident, @all_types) => {
226 impl_fmt_trait!($name, $native, Display);
227 impl_fmt_trait!($name, $native, Octal);
228 impl_fmt_trait!($name, $native, LowerHex);
229 impl_fmt_trait!($name, $native, UpperHex);
230 impl_fmt_trait!($name, $native, Binary);
231 };
232}
233
234macro_rules! impl_ops_traits {
235 ($name:ident, $native:ident, "floating point number") => {
236 impl_ops_traits!($name, $native, @all_types);
237 impl_ops_traits!($name, $native, @signed_integer_floating_point);
238
239 impl<O: ByteOrder> PartialOrd for $name<O> {
240 #[inline(always)]
241 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
242 self.get().partial_cmp(&other.get())
243 }
244 }
245 };
246 ($name:ident, $native:ident, "unsigned integer") => {
247 impl_ops_traits!($name, $native, @signed_unsigned_integer);
248 impl_ops_traits!($name, $native, @all_types);
249 };
250 ($name:ident, $native:ident, "signed integer") => {
251 impl_ops_traits!($name, $native, @signed_unsigned_integer);
252 impl_ops_traits!($name, $native, @signed_integer_floating_point);
253 impl_ops_traits!($name, $native, @all_types);
254 };
255 ($name:ident, $native:ident, @signed_unsigned_integer) => {
256 impl_ops_traits!(@without_byteorder_swap $name, $native, BitAnd, bitand, BitAndAssign, bitand_assign);
257 impl_ops_traits!(@without_byteorder_swap $name, $native, BitOr, bitor, BitOrAssign, bitor_assign);
258 impl_ops_traits!(@without_byteorder_swap $name, $native, BitXor, bitxor, BitXorAssign, bitxor_assign);
259 impl_ops_traits!(@with_byteorder_swap $name, $native, Shl, shl, ShlAssign, shl_assign);
260 impl_ops_traits!(@with_byteorder_swap $name, $native, Shr, shr, ShrAssign, shr_assign);
261
262 impl<O> core::ops::Not for $name<O> {
263 type Output = $name<O>;
264
265 #[inline(always)]
266 fn not(self) -> $name<O> {
267 let self_native = $native::from_ne_bytes(self.0);
268 $name((!self_native).to_ne_bytes(), PhantomData)
269 }
270 }
271
272 impl<O: ByteOrder> PartialOrd for $name<O> {
273 #[inline(always)]
274 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
275 Some(self.cmp(other))
276 }
277 }
278
279 impl<O: ByteOrder> Ord for $name<O> {
280 #[inline(always)]
281 fn cmp(&self, other: &Self) -> Ordering {
282 self.get().cmp(&other.get())
283 }
284 }
285
286 impl<O: ByteOrder> PartialOrd<$native> for $name<O> {
287 #[inline(always)]
288 fn partial_cmp(&self, other: &$native) -> Option<Ordering> {
289 self.get().partial_cmp(other)
290 }
291 }
292 };
293 ($name:ident, $native:ident, @signed_integer_floating_point) => {
294 impl<O: ByteOrder> core::ops::Neg for $name<O> {
295 type Output = $name<O>;
296
297 #[inline(always)]
298 fn neg(self) -> $name<O> {
299 let self_native: $native = self.get();
300 #[allow(clippy::arithmetic_side_effects)]
301 $name::<O>::new(-self_native)
302 }
303 }
304 };
305 ($name:ident, $native:ident, @all_types) => {
306 impl_ops_traits!(@with_byteorder_swap $name, $native, Add, add, AddAssign, add_assign);
307 impl_ops_traits!(@with_byteorder_swap $name, $native, Div, div, DivAssign, div_assign);
308 impl_ops_traits!(@with_byteorder_swap $name, $native, Mul, mul, MulAssign, mul_assign);
309 impl_ops_traits!(@with_byteorder_swap $name, $native, Rem, rem, RemAssign, rem_assign);
310 impl_ops_traits!(@with_byteorder_swap $name, $native, Sub, sub, SubAssign, sub_assign);
311 };
312 (@with_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => {
313 impl<O: ByteOrder> core::ops::$trait<$name<O>> for $name<O> {
314 type Output = $name<O>;
315
316 #[inline(always)]
317 fn $method(self, rhs: $name<O>) -> $name<O> {
318 let self_native: $native = self.get();
319 let rhs_native: $native = rhs.get();
320 let result_native = core::ops::$trait::$method(self_native, rhs_native);
321 $name::<O>::new(result_native)
322 }
323 }
324
325 impl<O: ByteOrder> core::ops::$trait<$name<O>> for $native {
326 type Output = $name<O>;
327
328 #[inline(always)]
329 fn $method(self, rhs: $name<O>) -> $name<O> {
330 let rhs_native: $native = rhs.get();
331 let result_native = core::ops::$trait::$method(self, rhs_native);
332 $name::<O>::new(result_native)
333 }
334 }
335
336 impl<O: ByteOrder> core::ops::$trait<$native> for $name<O> {
337 type Output = $name<O>;
338
339 #[inline(always)]
340 fn $method(self, rhs: $native) -> $name<O> {
341 let self_native: $native = self.get();
342 let result_native = core::ops::$trait::$method(self_native, rhs);
343 $name::<O>::new(result_native)
344 }
345 }
346
347 impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $name<O> {
348 #[inline(always)]
349 fn $method_assign(&mut self, rhs: $name<O>) {
350 *self = core::ops::$trait::$method(*self, rhs);
351 }
352 }
353
354 impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $native {
355 #[inline(always)]
356 fn $method_assign(&mut self, rhs: $name<O>) {
357 let rhs_native: $native = rhs.get();
358 *self = core::ops::$trait::$method(*self, rhs_native);
359 }
360 }
361
362 impl<O: ByteOrder> core::ops::$trait_assign<$native> for $name<O> {
363 #[inline(always)]
364 fn $method_assign(&mut self, rhs: $native) {
365 *self = core::ops::$trait::$method(*self, rhs);
366 }
367 }
368 };
369 (@without_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => {
376 impl<O: ByteOrder> core::ops::$trait<$name<O>> for $name<O> {
377 type Output = $name<O>;
378
379 #[inline(always)]
380 fn $method(self, rhs: $name<O>) -> $name<O> {
381 let self_native = $native::from_ne_bytes(self.0);
382 let rhs_native = $native::from_ne_bytes(rhs.0);
383 let result_native = core::ops::$trait::$method(self_native, rhs_native);
384 $name(result_native.to_ne_bytes(), PhantomData)
385 }
386 }
387
388 impl<O: ByteOrder> core::ops::$trait<$name<O>> for $native {
389 type Output = $name<O>;
390
391 #[inline(always)]
392 fn $method(self, rhs: $name<O>) -> $name<O> {
393 let rhs_native = $native::from_ne_bytes(rhs.0);
395 let slf_byteorder = $name::<O>::new(self);
397 let slf_native = $native::from_ne_bytes(slf_byteorder.0);
399 let result_native = core::ops::$trait::$method(slf_native, rhs_native);
401 $name(result_native.to_ne_bytes(), PhantomData)
403 }
404 }
405
406 impl<O: ByteOrder> core::ops::$trait<$native> for $name<O> {
407 type Output = $name<O>;
408
409 #[inline(always)]
410 fn $method(self, rhs: $native) -> $name<O> {
411 let rhs_byteorder = $name::<O>::new(rhs);
413 let rhs_native = $native::from_ne_bytes(rhs_byteorder.0);
415 let slf_native = $native::from_ne_bytes(self.0);
417 let result_native = core::ops::$trait::$method(slf_native, rhs_native);
419 $name(result_native.to_ne_bytes(), PhantomData)
421 }
422 }
423
424 impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $name<O> {
425 #[inline(always)]
426 fn $method_assign(&mut self, rhs: $name<O>) {
427 *self = core::ops::$trait::$method(*self, rhs);
428 }
429 }
430
431 impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $native {
432 #[inline(always)]
433 fn $method_assign(&mut self, rhs: $name<O>) {
434 let rhs_native = rhs.get();
436 *self = core::ops::$trait::$method(*self, rhs_native);
438 }
439 }
440
441 impl<O: ByteOrder> core::ops::$trait_assign<$native> for $name<O> {
442 #[inline(always)]
443 fn $method_assign(&mut self, rhs: $native) {
444 *self = core::ops::$trait::$method(*self, rhs);
445 }
446 }
447 };
448}
449
450macro_rules! doc_comment {
451 ($x:expr, $($tt:tt)*) => {
452 #[doc = $x]
453 $($tt)*
454 };
455}
456
457macro_rules! define_max_value_constant {
458 ($name:ident, $bytes:expr, "unsigned integer") => {
459 pub const MAX_VALUE: $name<O> = $name([0xFFu8; $bytes], PhantomData);
465 };
466 ($name:ident, $bytes:expr, "signed integer") => {};
474 ($name:ident, $bytes:expr, "floating point number") => {};
475}
476
477macro_rules! define_type {
478 (
479 $article:ident,
480 $description:expr,
481 $name:ident,
482 $native:ident,
483 $bits:expr,
484 $bytes:expr,
485 $from_be_fn:path,
486 $to_be_fn:path,
487 $from_le_fn:path,
488 $to_le_fn:path,
489 $number_kind:tt,
490 [$($larger_native:ty),*],
491 [$($larger_native_try:ty),*],
492 [$($larger_byteorder:ident),*],
493 [$($larger_byteorder_try:ident),*]
494 ) => {
495 doc_comment! {
496 concat!($description, " stored in a given byte order.
497
498`", stringify!($name), "` is like the native `", stringify!($native), "` type with
499two major differences: First, it has no alignment requirement (its alignment is 1).
500Second, the endianness of its memory layout is given by the type parameter `O`,
501which can be any type which implements [`ByteOrder`]. In particular, this refers
502to [`BigEndian`], [`LittleEndian`], [`NativeEndian`], and [`NetworkEndian`].
503
504", stringify!($article), " `", stringify!($name), "` can be constructed using
505the [`new`] method, and its contained value can be obtained as a native
506`",stringify!($native), "` using the [`get`] method, or updated in place with
507the [`set`] method. In all cases, if the endianness `O` is not the same as the
508endianness of the current platform, an endianness swap will be performed in
509order to uphold the invariants that a) the layout of `", stringify!($name), "`
510has endianness `O` and that, b) the layout of `", stringify!($native), "` has
511the platform's native endianness.
512
513`", stringify!($name), "` implements [`FromBytes`], [`IntoBytes`], and [`Unaligned`],
514making it useful for parsing and serialization. See the module documentation for an
515example of how it can be used for parsing UDP packets.
516
517[`new`]: crate::byteorder::", stringify!($name), "::new
518[`get`]: crate::byteorder::", stringify!($name), "::get
519[`set`]: crate::byteorder::", stringify!($name), "::set
520[`FromBytes`]: crate::FromBytes
521[`IntoBytes`]: crate::IntoBytes
522[`Unaligned`]: crate::Unaligned"),
523 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
524 #[cfg_attr(any(feature = "derive", test), derive(KnownLayout, Immutable, FromBytes, IntoBytes, Unaligned))]
525 #[repr(transparent)]
526 pub struct $name<O>([u8; $bytes], PhantomData<O>);
527 }
528
529 #[cfg(not(any(feature = "derive", test)))]
530 impl_known_layout!(O => $name<O>);
531
532 #[allow(unused_unsafe)] #[allow(clippy::multiple_unsafe_ops_per_block)]
538 const _: () = unsafe {
539 impl_or_verify!(O => Immutable for $name<O>);
540 impl_or_verify!(O => TryFromBytes for $name<O>);
541 impl_or_verify!(O => FromZeros for $name<O>);
542 impl_or_verify!(O => FromBytes for $name<O>);
543 impl_or_verify!(O => IntoBytes for $name<O>);
544 impl_or_verify!(O => Unaligned for $name<O>);
545 };
546
547 impl<O> Default for $name<O> {
548 #[inline(always)]
549 fn default() -> $name<O> {
550 $name::ZERO
551 }
552 }
553
554 impl<O> $name<O> {
555 pub const ZERO: $name<O> = $name([0u8; $bytes], PhantomData);
561
562 define_max_value_constant!($name, $bytes, $number_kind);
563
564 #[must_use = "has no side effects"]
567 #[inline(always)]
568 pub const fn from_bytes(bytes: [u8; $bytes]) -> $name<O> {
569 $name(bytes, PhantomData)
570 }
571
572 #[must_use = "has no side effects"]
576 #[inline(always)]
577 pub const fn to_bytes(self) -> [u8; $bytes] {
578 self.0
579 }
580 }
581
582 impl<O: ByteOrder> $name<O> {
583 maybe_const_trait_bounded_fn! {
584 #[must_use = "has no side effects"]
588 #[inline(always)]
589 pub const fn new(n: $native) -> $name<O> {
590 let bytes = match O::ORDER {
591 Order::BigEndian => $to_be_fn(n),
592 Order::LittleEndian => $to_le_fn(n),
593 };
594
595 $name(bytes, PhantomData)
596 }
597 }
598
599 maybe_const_trait_bounded_fn! {
600 #[must_use = "has no side effects"]
604 #[inline(always)]
605 pub const fn get(self) -> $native {
606 match O::ORDER {
607 Order::BigEndian => $from_be_fn(self.0),
608 Order::LittleEndian => $from_le_fn(self.0),
609 }
610 }
611 }
612
613 #[inline(always)]
617 pub fn set(&mut self, n: $native) {
618 *self = Self::new(n);
619 }
620 }
621
622 impl<O: ByteOrder> From<$name<O>> for [u8; $bytes] {
628 #[inline(always)]
629 fn from(x: $name<O>) -> [u8; $bytes] {
630 x.0
631 }
632 }
633
634 impl<O: ByteOrder> From<[u8; $bytes]> for $name<O> {
635 #[inline(always)]
636 fn from(bytes: [u8; $bytes]) -> $name<O> {
637 $name(bytes, PhantomData)
638 }
639 }
640
641 impl<O: ByteOrder> From<$name<O>> for $native {
642 #[inline(always)]
643 fn from(x: $name<O>) -> $native {
644 x.get()
645 }
646 }
647
648 impl<O: ByteOrder> From<$native> for $name<O> {
649 #[inline(always)]
650 fn from(x: $native) -> $name<O> {
651 $name::new(x)
652 }
653 }
654
655 $(
656 impl<O: ByteOrder> From<$name<O>> for $larger_native {
657 #[inline(always)]
658 fn from(x: $name<O>) -> $larger_native {
659 x.get().into()
660 }
661 }
662 )*
663
664 $(
665 impl<O: ByteOrder> TryFrom<$larger_native_try> for $name<O> {
666 type Error = TryFromIntError;
667 #[inline(always)]
668 fn try_from(x: $larger_native_try) -> Result<$name<O>, TryFromIntError> {
669 $native::try_from(x).map($name::new)
670 }
671 }
672 )*
673
674 $(
675 impl<O: ByteOrder, P: ByteOrder> From<$name<O>> for $larger_byteorder<P> {
676 #[inline(always)]
677 fn from(x: $name<O>) -> $larger_byteorder<P> {
678 $larger_byteorder::new(x.get().into())
679 }
680 }
681 )*
682
683 $(
684 impl<O: ByteOrder, P: ByteOrder> TryFrom<$larger_byteorder_try<P>> for $name<O> {
685 type Error = TryFromIntError;
686 #[inline(always)]
687 fn try_from(x: $larger_byteorder_try<P>) -> Result<$name<O>, TryFromIntError> {
688 x.get().try_into().map($name::new)
689 }
690 }
691 )*
692
693 impl<O> AsRef<[u8; $bytes]> for $name<O> {
694 #[inline(always)]
695 fn as_ref(&self) -> &[u8; $bytes] {
696 &self.0
697 }
698 }
699
700 impl<O> AsMut<[u8; $bytes]> for $name<O> {
701 #[inline(always)]
702 fn as_mut(&mut self) -> &mut [u8; $bytes] {
703 &mut self.0
704 }
705 }
706
707 impl<O> PartialEq<$name<O>> for [u8; $bytes] {
708 #[inline(always)]
709 fn eq(&self, other: &$name<O>) -> bool {
710 self.eq(&other.0)
711 }
712 }
713
714 impl<O> PartialEq<[u8; $bytes]> for $name<O> {
715 #[inline(always)]
716 fn eq(&self, other: &[u8; $bytes]) -> bool {
717 self.0.eq(other)
718 }
719 }
720
721 impl<O: ByteOrder> PartialEq<$native> for $name<O> {
722 #[inline(always)]
723 fn eq(&self, other: &$native) -> bool {
724 self.get().eq(other)
725 }
726 }
727
728 impl_dbg_traits!($name, $native, $number_kind);
729 impl_fmt_traits!($name, $native, $number_kind);
730 impl_ops_traits!($name, $native, $number_kind);
731 };
732}
733
734define_type!(
735 A,
736 "A 16-bit unsigned integer",
737 U16,
738 u16,
739 16,
740 2,
741 u16::from_be_bytes,
742 u16::to_be_bytes,
743 u16::from_le_bytes,
744 u16::to_le_bytes,
745 "unsigned integer",
746 [u32, u64, u128, usize],
747 [u32, u64, u128, usize],
748 [U32, U64, U128, Usize],
749 [U32, U64, U128, Usize]
750);
751define_type!(
752 A,
753 "A 32-bit unsigned integer",
754 U32,
755 u32,
756 32,
757 4,
758 u32::from_be_bytes,
759 u32::to_be_bytes,
760 u32::from_le_bytes,
761 u32::to_le_bytes,
762 "unsigned integer",
763 [u64, u128],
764 [u64, u128],
765 [U64, U128],
766 [U64, U128]
767);
768define_type!(
769 A,
770 "A 64-bit unsigned integer",
771 U64,
772 u64,
773 64,
774 8,
775 u64::from_be_bytes,
776 u64::to_be_bytes,
777 u64::from_le_bytes,
778 u64::to_le_bytes,
779 "unsigned integer",
780 [u128],
781 [u128],
782 [U128],
783 [U128]
784);
785define_type!(
786 A,
787 "A 128-bit unsigned integer",
788 U128,
789 u128,
790 128,
791 16,
792 u128::from_be_bytes,
793 u128::to_be_bytes,
794 u128::from_le_bytes,
795 u128::to_le_bytes,
796 "unsigned integer",
797 [],
798 [],
799 [],
800 []
801);
802define_type!(
803 A,
804 "A word-sized unsigned integer",
805 Usize,
806 usize,
807 mem::size_of::<usize>() * 8,
808 mem::size_of::<usize>(),
809 usize::from_be_bytes,
810 usize::to_be_bytes,
811 usize::from_le_bytes,
812 usize::to_le_bytes,
813 "unsigned integer",
814 [],
815 [],
816 [],
817 []
818);
819define_type!(
820 An,
821 "A 16-bit signed integer",
822 I16,
823 i16,
824 16,
825 2,
826 i16::from_be_bytes,
827 i16::to_be_bytes,
828 i16::from_le_bytes,
829 i16::to_le_bytes,
830 "signed integer",
831 [i32, i64, i128, isize],
832 [i32, i64, i128, isize],
833 [I32, I64, I128, Isize],
834 [I32, I64, I128, Isize]
835);
836define_type!(
837 An,
838 "A 32-bit signed integer",
839 I32,
840 i32,
841 32,
842 4,
843 i32::from_be_bytes,
844 i32::to_be_bytes,
845 i32::from_le_bytes,
846 i32::to_le_bytes,
847 "signed integer",
848 [i64, i128],
849 [i64, i128],
850 [I64, I128],
851 [I64, I128]
852);
853define_type!(
854 An,
855 "A 64-bit signed integer",
856 I64,
857 i64,
858 64,
859 8,
860 i64::from_be_bytes,
861 i64::to_be_bytes,
862 i64::from_le_bytes,
863 i64::to_le_bytes,
864 "signed integer",
865 [i128],
866 [i128],
867 [I128],
868 [I128]
869);
870define_type!(
871 An,
872 "A 128-bit signed integer",
873 I128,
874 i128,
875 128,
876 16,
877 i128::from_be_bytes,
878 i128::to_be_bytes,
879 i128::from_le_bytes,
880 i128::to_le_bytes,
881 "signed integer",
882 [],
883 [],
884 [],
885 []
886);
887define_type!(
888 An,
889 "A word-sized signed integer",
890 Isize,
891 isize,
892 mem::size_of::<isize>() * 8,
893 mem::size_of::<isize>(),
894 isize::from_be_bytes,
895 isize::to_be_bytes,
896 isize::from_le_bytes,
897 isize::to_le_bytes,
898 "signed integer",
899 [],
900 [],
901 [],
902 []
903);
904
905macro_rules! define_float_conversion {
908 ($ty:ty, $bits:ident, $bytes:expr, $mod:ident) => {
909 mod $mod {
910 use super::*;
911
912 define_float_conversion!($ty, $bits, $bytes, from_be_bytes, to_be_bytes);
913 define_float_conversion!($ty, $bits, $bytes, from_le_bytes, to_le_bytes);
914 }
915 };
916 ($ty:ty, $bits:ident, $bytes:expr, $from:ident, $to:ident) => {
917 #[allow(clippy::unnecessary_transmutes)]
920 pub(crate) const fn $from(bytes: [u8; $bytes]) -> $ty {
921 transmute!($bits::$from(bytes))
922 }
923
924 pub(crate) const fn $to(f: $ty) -> [u8; $bytes] {
925 #[allow(clippy::unnecessary_transmutes)]
928 let bits: $bits = transmute!(f);
929 bits.$to()
930 }
931 };
932}
933
934define_float_conversion!(f32, u32, 4, f32_ext);
935define_float_conversion!(f64, u64, 8, f64_ext);
936
937define_type!(
938 An,
939 "A 32-bit floating point number",
940 F32,
941 f32,
942 32,
943 4,
944 f32_ext::from_be_bytes,
945 f32_ext::to_be_bytes,
946 f32_ext::from_le_bytes,
947 f32_ext::to_le_bytes,
948 "floating point number",
949 [f64],
950 [],
951 [F64],
952 []
953);
954define_type!(
955 An,
956 "A 64-bit floating point number",
957 F64,
958 f64,
959 64,
960 8,
961 f64_ext::from_be_bytes,
962 f64_ext::to_be_bytes,
963 f64_ext::from_le_bytes,
964 f64_ext::to_le_bytes,
965 "floating point number",
966 [],
967 [],
968 [],
969 []
970);
971
972macro_rules! module {
973 ($name:ident, $trait:ident, $endianness_str:expr) => {
974 #[doc = $endianness_str]
976 pub mod $name {
978 use super::$trait;
979
980 module!(@ty U16, $trait, "16-bit unsigned integer", $endianness_str);
981 module!(@ty U32, $trait, "32-bit unsigned integer", $endianness_str);
982 module!(@ty U64, $trait, "64-bit unsigned integer", $endianness_str);
983 module!(@ty U128, $trait, "128-bit unsigned integer", $endianness_str);
984 module!(@ty I16, $trait, "16-bit signed integer", $endianness_str);
985 module!(@ty I32, $trait, "32-bit signed integer", $endianness_str);
986 module!(@ty I64, $trait, "64-bit signed integer", $endianness_str);
987 module!(@ty I128, $trait, "128-bit signed integer", $endianness_str);
988 module!(@ty F32, $trait, "32-bit floating point number", $endianness_str);
989 module!(@ty F64, $trait, "64-bit floating point number", $endianness_str);
990 }
991 };
992 (@ty $ty:ident, $trait:ident, $desc_str:expr, $endianness_str:expr) => {
993 #[doc = $desc_str]
995 #[doc = $endianness_str]
997 pub type $ty = crate::byteorder::$ty<$trait>;
999 };
1000}
1001
1002module!(big_endian, BigEndian, "big-endian");
1003module!(little_endian, LittleEndian, "little-endian");
1004module!(network_endian, NetworkEndian, "network-endian");
1005module!(native_endian, NativeEndian, "native-endian");
1006
1007#[cfg(any(test, kani))]
1008mod tests {
1009 use super::*;
1010
1011 #[cfg(not(kani))]
1012 mod compatibility {
1013 pub(super) use rand::{
1014 distributions::{Distribution, Standard},
1015 rngs::SmallRng,
1016 Rng, SeedableRng,
1017 };
1018
1019 pub(crate) trait Arbitrary {}
1020
1021 impl<T> Arbitrary for T {}
1022 }
1023
1024 #[cfg(kani)]
1025 mod compatibility {
1026 pub(crate) use kani::Arbitrary;
1027
1028 pub(crate) struct SmallRng;
1029
1030 impl SmallRng {
1031 pub(crate) fn seed_from_u64(_state: u64) -> Self {
1032 Self
1033 }
1034 }
1035
1036 pub(crate) trait Rng {
1037 fn sample<T, D: Distribution<T>>(&mut self, _distr: D) -> T
1038 where
1039 T: Arbitrary,
1040 {
1041 kani::any()
1042 }
1043 }
1044
1045 impl Rng for SmallRng {}
1046
1047 pub(crate) trait Distribution<T> {}
1048 impl<T, U> Distribution<T> for U {}
1049
1050 pub(crate) struct Standard;
1051 }
1052
1053 use compatibility::*;
1054
1055 trait Native: Arbitrary + FromBytes + IntoBytes + Immutable + Copy + PartialEq + Debug {
1057 const ZERO: Self;
1058 const MAX_VALUE: Self;
1059
1060 type Distribution: Distribution<Self>;
1061 const DIST: Self::Distribution;
1062
1063 fn rand<R: Rng>(rng: &mut R) -> Self {
1064 rng.sample(Self::DIST)
1065 }
1066
1067 #[cfg_attr(kani, allow(unused))]
1068 fn checked_add(self, rhs: Self) -> Option<Self>;
1069
1070 #[cfg_attr(kani, allow(unused))]
1071 fn checked_div(self, rhs: Self) -> Option<Self>;
1072
1073 #[cfg_attr(kani, allow(unused))]
1074 fn checked_mul(self, rhs: Self) -> Option<Self>;
1075
1076 #[cfg_attr(kani, allow(unused))]
1077 fn checked_rem(self, rhs: Self) -> Option<Self>;
1078
1079 #[cfg_attr(kani, allow(unused))]
1080 fn checked_sub(self, rhs: Self) -> Option<Self>;
1081
1082 #[cfg_attr(kani, allow(unused))]
1083 fn checked_shl(self, rhs: Self) -> Option<Self>;
1084
1085 #[cfg_attr(kani, allow(unused))]
1086 fn checked_shr(self, rhs: Self) -> Option<Self>;
1087
1088 fn is_nan(self) -> bool;
1089
1090 fn assert_eq_or_nan(self, other: Self) {
1094 let slf = (!self.is_nan()).then(|| self);
1095 let other = (!other.is_nan()).then(|| other);
1096 assert_eq!(slf, other);
1097 }
1098 }
1099
1100 trait ByteArray:
1101 FromBytes + IntoBytes + Immutable + Copy + AsRef<[u8]> + AsMut<[u8]> + Debug + Default + Eq
1102 {
1103 fn invert(self) -> Self;
1105 }
1106
1107 trait ByteOrderType:
1108 FromBytes + IntoBytes + Unaligned + Copy + Eq + Debug + Hash + From<Self::Native>
1109 {
1110 type Native: Native;
1111 type ByteArray: ByteArray;
1112
1113 const ZERO: Self;
1114
1115 fn new(native: Self::Native) -> Self;
1116 fn get(self) -> Self::Native;
1117 fn set(&mut self, native: Self::Native);
1118 fn from_bytes(bytes: Self::ByteArray) -> Self;
1119 fn into_bytes(self) -> Self::ByteArray;
1120
1121 fn assert_eq_or_nan(self, other: Self) {
1125 let slf = (!self.get().is_nan()).then(|| self);
1126 let other = (!other.get().is_nan()).then(|| other);
1127 assert_eq!(slf, other);
1128 }
1129 }
1130
1131 trait ByteOrderTypeUnsigned: ByteOrderType {
1132 const MAX_VALUE: Self;
1133 }
1134
1135 macro_rules! impl_byte_array {
1136 ($bytes:expr) => {
1137 impl ByteArray for [u8; $bytes] {
1138 fn invert(mut self) -> [u8; $bytes] {
1139 self.reverse();
1140 self
1141 }
1142 }
1143 };
1144 }
1145
1146 impl_byte_array!(2);
1147 impl_byte_array!(4);
1148 impl_byte_array!(8);
1149 impl_byte_array!(16);
1150
1151 macro_rules! impl_byte_order_type_unsigned {
1152 ($name:ident, unsigned) => {
1153 impl<O: ByteOrder> ByteOrderTypeUnsigned for $name<O> {
1154 const MAX_VALUE: $name<O> = $name::MAX_VALUE;
1155 }
1156 };
1157 ($name:ident, signed) => {};
1158 }
1159
1160 macro_rules! impl_traits {
1161 ($name:ident, $native:ident, $sign:ident $(, @$float:ident)?) => {
1162 impl Native for $native {
1163 #[allow(trivial_numeric_casts, clippy::as_conversions)]
1168 const ZERO: $native = 0 as $native;
1169 const MAX_VALUE: $native = $native::MAX;
1170
1171 type Distribution = Standard;
1172 const DIST: Standard = Standard;
1173
1174 impl_traits!(@float_dependent_methods $(@$float)?);
1175 }
1176
1177 impl<O: ByteOrder> ByteOrderType for $name<O> {
1178 type Native = $native;
1179 type ByteArray = [u8; mem::size_of::<$native>()];
1180
1181 const ZERO: $name<O> = $name::ZERO;
1182
1183 fn new(native: $native) -> $name<O> {
1184 $name::new(native)
1185 }
1186
1187 fn get(self) -> $native {
1188 $name::get(self)
1189 }
1190
1191 fn set(&mut self, native: $native) {
1192 $name::set(self, native)
1193 }
1194
1195 fn from_bytes(bytes: [u8; mem::size_of::<$native>()]) -> $name<O> {
1196 $name::from(bytes)
1197 }
1198
1199 fn into_bytes(self) -> [u8; mem::size_of::<$native>()] {
1200 <[u8; mem::size_of::<$native>()]>::from(self)
1201 }
1202 }
1203
1204 impl_byte_order_type_unsigned!($name, $sign);
1205 };
1206 (@float_dependent_methods) => {
1207 fn checked_add(self, rhs: Self) -> Option<Self> { self.checked_add(rhs) }
1208 fn checked_div(self, rhs: Self) -> Option<Self> { self.checked_div(rhs) }
1209 fn checked_mul(self, rhs: Self) -> Option<Self> { self.checked_mul(rhs) }
1210 fn checked_rem(self, rhs: Self) -> Option<Self> { self.checked_rem(rhs) }
1211 fn checked_sub(self, rhs: Self) -> Option<Self> { self.checked_sub(rhs) }
1212 fn checked_shl(self, rhs: Self) -> Option<Self> { self.checked_shl(rhs.try_into().unwrap_or(u32::MAX)) }
1213 fn checked_shr(self, rhs: Self) -> Option<Self> { self.checked_shr(rhs.try_into().unwrap_or(u32::MAX)) }
1214 fn is_nan(self) -> bool { false }
1215 };
1216 (@float_dependent_methods @float) => {
1217 fn checked_add(self, rhs: Self) -> Option<Self> { Some(self + rhs) }
1218 fn checked_div(self, rhs: Self) -> Option<Self> { Some(self / rhs) }
1219 fn checked_mul(self, rhs: Self) -> Option<Self> { Some(self * rhs) }
1220 fn checked_rem(self, rhs: Self) -> Option<Self> { Some(self % rhs) }
1221 fn checked_sub(self, rhs: Self) -> Option<Self> { Some(self - rhs) }
1222 fn checked_shl(self, _rhs: Self) -> Option<Self> { unimplemented!() }
1223 fn checked_shr(self, _rhs: Self) -> Option<Self> { unimplemented!() }
1224 fn is_nan(self) -> bool { self.is_nan() }
1225 };
1226 }
1227
1228 impl_traits!(U16, u16, unsigned);
1229 impl_traits!(U32, u32, unsigned);
1230 impl_traits!(U64, u64, unsigned);
1231 impl_traits!(U128, u128, unsigned);
1232 impl_traits!(Usize, usize, unsigned);
1233 impl_traits!(I16, i16, signed);
1234 impl_traits!(I32, i32, signed);
1235 impl_traits!(I64, i64, signed);
1236 impl_traits!(I128, i128, signed);
1237 impl_traits!(Isize, isize, unsigned);
1238 impl_traits!(F32, f32, signed, @float);
1239 impl_traits!(F64, f64, signed, @float);
1240
1241 macro_rules! call_for_unsigned_types {
1242 ($fn:ident, $byteorder:ident) => {
1243 $fn::<U16<$byteorder>>();
1244 $fn::<U32<$byteorder>>();
1245 $fn::<U64<$byteorder>>();
1246 $fn::<U128<$byteorder>>();
1247 $fn::<Usize<$byteorder>>();
1248 };
1249 }
1250
1251 macro_rules! call_for_signed_types {
1252 ($fn:ident, $byteorder:ident) => {
1253 $fn::<I16<$byteorder>>();
1254 $fn::<I32<$byteorder>>();
1255 $fn::<I64<$byteorder>>();
1256 $fn::<I128<$byteorder>>();
1257 $fn::<Isize<$byteorder>>();
1258 };
1259 }
1260
1261 macro_rules! call_for_float_types {
1262 ($fn:ident, $byteorder:ident) => {
1263 $fn::<F32<$byteorder>>();
1264 $fn::<F64<$byteorder>>();
1265 };
1266 }
1267
1268 macro_rules! call_for_all_types {
1269 ($fn:ident, $byteorder:ident) => {
1270 call_for_unsigned_types!($fn, $byteorder);
1271 call_for_signed_types!($fn, $byteorder);
1272 call_for_float_types!($fn, $byteorder);
1273 };
1274 }
1275
1276 #[cfg(target_endian = "big")]
1277 type NonNativeEndian = LittleEndian;
1278 #[cfg(target_endian = "little")]
1279 type NonNativeEndian = BigEndian;
1280
1281 const RNG_SEED: u64 = 0x7A03CAE2F32B5B8F;
1286
1287 const RAND_ITERS: usize = if cfg!(any(miri, kani)) {
1288 1
1307 } else {
1308 1024
1309 };
1310
1311 #[test]
1312 fn test_const_methods() {
1313 use big_endian::*;
1314
1315 #[rustversion::since(1.61.0)]
1316 const _U: U16 = U16::new(0);
1317 #[rustversion::since(1.61.0)]
1318 const _NATIVE: u16 = _U.get();
1319 const _FROM_BYTES: U16 = U16::from_bytes([0, 1]);
1320 const _BYTES: [u8; 2] = _FROM_BYTES.to_bytes();
1321 }
1322
1323 #[cfg_attr(test, test)]
1324 #[cfg_attr(kani, kani::proof)]
1325 fn test_zero() {
1326 fn test_zero<T: ByteOrderType>() {
1327 assert_eq!(T::ZERO.get(), T::Native::ZERO);
1328 }
1329
1330 call_for_all_types!(test_zero, NativeEndian);
1331 call_for_all_types!(test_zero, NonNativeEndian);
1332 }
1333
1334 #[cfg_attr(test, test)]
1335 #[cfg_attr(kani, kani::proof)]
1336 fn test_max_value() {
1337 fn test_max_value<T: ByteOrderTypeUnsigned>() {
1338 assert_eq!(T::MAX_VALUE.get(), T::Native::MAX_VALUE);
1339 }
1340
1341 call_for_unsigned_types!(test_max_value, NativeEndian);
1342 call_for_unsigned_types!(test_max_value, NonNativeEndian);
1343 }
1344
1345 #[cfg_attr(test, test)]
1346 #[cfg_attr(kani, kani::proof)]
1347 fn test_endian() {
1348 fn test<T: ByteOrderType>(invert: bool) {
1349 let mut r = SmallRng::seed_from_u64(RNG_SEED);
1350 for _ in 0..RAND_ITERS {
1351 let native = T::Native::rand(&mut r);
1352 let mut bytes = T::ByteArray::default();
1353 bytes.as_mut_bytes().copy_from_slice(native.as_bytes());
1354 if invert {
1355 bytes = bytes.invert();
1356 }
1357 let mut from_native = T::new(native);
1358 let from_bytes = T::from_bytes(bytes);
1359
1360 from_native.assert_eq_or_nan(from_bytes);
1361 from_native.get().assert_eq_or_nan(native);
1362 from_bytes.get().assert_eq_or_nan(native);
1363
1364 assert_eq!(from_native.into_bytes(), bytes);
1365 assert_eq!(from_bytes.into_bytes(), bytes);
1366
1367 let updated = T::Native::rand(&mut r);
1368 from_native.set(updated);
1369 from_native.get().assert_eq_or_nan(updated);
1370 }
1371 }
1372
1373 fn test_native<T: ByteOrderType>() {
1374 test::<T>(false);
1375 }
1376
1377 fn test_non_native<T: ByteOrderType>() {
1378 test::<T>(true);
1379 }
1380
1381 call_for_all_types!(test_native, NativeEndian);
1382 call_for_all_types!(test_non_native, NonNativeEndian);
1383 }
1384
1385 #[test]
1386 fn test_ops_impls() {
1387 fn test<T, FTT, FTN, FNT, FNN, FNNChecked, FATT, FATN, FANT>(
1394 op_t_t: FTT,
1395 op_t_n: FTN,
1396 op_n_t: FNT,
1397 op_n_n: FNN,
1398 op_n_n_checked: Option<FNNChecked>,
1399 op_assign: Option<(FATT, FATN, FANT)>,
1400 ) where
1401 T: ByteOrderType,
1402 FTT: Fn(T, T) -> T,
1403 FTN: Fn(T, T::Native) -> T,
1404 FNT: Fn(T::Native, T) -> T,
1405 FNN: Fn(T::Native, T::Native) -> T::Native,
1406 FNNChecked: Fn(T::Native, T::Native) -> Option<T::Native>,
1407 FATT: Fn(&mut T, T),
1408 FATN: Fn(&mut T, T::Native),
1409 FANT: Fn(&mut T::Native, T),
1410 {
1411 let mut r = SmallRng::seed_from_u64(RNG_SEED);
1412 for _ in 0..RAND_ITERS {
1413 let n0 = T::Native::rand(&mut r);
1414 let n1 = T::Native::rand(&mut r);
1415 let t0 = T::new(n0);
1416 let t1 = T::new(n1);
1417
1418 if matches!(&op_n_n_checked, Some(checked) if checked(n0, n1).is_none()) {
1421 continue;
1422 }
1423
1424 let t_t_res = op_t_t(t0, t1);
1425 let t_n_res = op_t_n(t0, n1);
1426 let n_t_res = op_n_t(n0, t1);
1427 let n_n_res = op_n_n(n0, n1);
1428
1429 let val_or_none = |t: T| (!T::Native::is_nan(t.get())).then(|| t.get());
1433 let t_t_res = val_or_none(t_t_res);
1434 let t_n_res = val_or_none(t_n_res);
1435 let n_t_res = val_or_none(n_t_res);
1436 let n_n_res = (!T::Native::is_nan(n_n_res)).then(|| n_n_res);
1437 assert_eq!(t_t_res, n_n_res);
1438 assert_eq!(t_n_res, n_n_res);
1439 assert_eq!(n_t_res, n_n_res);
1440
1441 if let Some((op_assign_t_t, op_assign_t_n, op_assign_n_t)) = &op_assign {
1442 let mut t_t_res = t0;
1443 op_assign_t_t(&mut t_t_res, t1);
1444 let mut t_n_res = t0;
1445 op_assign_t_n(&mut t_n_res, n1);
1446 let mut n_t_res = n0;
1447 op_assign_n_t(&mut n_t_res, t1);
1448
1449 let t_t_res = val_or_none(t_t_res);
1453 let t_n_res = val_or_none(t_n_res);
1454 let n_t_res = (!T::Native::is_nan(n_t_res)).then(|| n_t_res);
1455 assert_eq!(t_t_res, n_n_res);
1456 assert_eq!(t_n_res, n_n_res);
1457 assert_eq!(n_t_res, n_n_res);
1458 }
1459 }
1460 }
1461
1462 macro_rules! test {
1463 (
1464 @binary
1465 $trait:ident,
1466 $method:ident $([$checked_method:ident])?,
1467 $trait_assign:ident,
1468 $method_assign:ident,
1469 $($call_for_macros:ident),*
1470 ) => {{
1471 fn t<T>()
1472 where
1473 T: ByteOrderType,
1474 T: core::ops::$trait<T, Output = T>,
1475 T: core::ops::$trait<T::Native, Output = T>,
1476 T::Native: core::ops::$trait<T, Output = T>,
1477 T::Native: core::ops::$trait<T::Native, Output = T::Native>,
1478
1479 T: core::ops::$trait_assign<T>,
1480 T: core::ops::$trait_assign<T::Native>,
1481 T::Native: core::ops::$trait_assign<T>,
1482 T::Native: core::ops::$trait_assign<T::Native>,
1483 {
1484 test::<T, _, _, _, _, _, _, _, _>(
1485 core::ops::$trait::$method,
1486 core::ops::$trait::$method,
1487 core::ops::$trait::$method,
1488 core::ops::$trait::$method,
1489 {
1490 #[allow(unused_mut, unused_assignments)]
1491 let mut op_native_checked = None::<fn(T::Native, T::Native) -> Option<T::Native>>;
1492 $(
1493 op_native_checked = Some(T::Native::$checked_method);
1494 )?
1495 op_native_checked
1496 },
1497 Some((
1498 <T as core::ops::$trait_assign<T>>::$method_assign,
1499 <T as core::ops::$trait_assign::<T::Native>>::$method_assign,
1500 <T::Native as core::ops::$trait_assign::<T>>::$method_assign
1501 )),
1502 );
1503 }
1504
1505 $(
1506 $call_for_macros!(t, NativeEndian);
1507 $call_for_macros!(t, NonNativeEndian);
1508 )*
1509 }};
1510 (
1511 @unary
1512 $trait:ident,
1513 $method:ident,
1514 $($call_for_macros:ident),*
1515 ) => {{
1516 fn t<T>()
1517 where
1518 T: ByteOrderType,
1519 T: core::ops::$trait<Output = T>,
1520 T::Native: core::ops::$trait<Output = T::Native>,
1521 {
1522 test::<T, _, _, _, _, _, _, _, _>(
1523 |slf, _rhs| core::ops::$trait::$method(slf),
1524 |slf, _rhs| core::ops::$trait::$method(slf),
1525 |slf, _rhs| core::ops::$trait::$method(slf).into(),
1526 |slf, _rhs| core::ops::$trait::$method(slf),
1527 None::<fn(T::Native, T::Native) -> Option<T::Native>>,
1528 None::<(fn(&mut T, T), fn(&mut T, T::Native), fn(&mut T::Native, T))>,
1529 );
1530 }
1531
1532 $(
1533 $call_for_macros!(t, NativeEndian);
1534 $call_for_macros!(t, NonNativeEndian);
1535 )*
1536 }};
1537 }
1538
1539 test!(@binary Add, add[checked_add], AddAssign, add_assign, call_for_all_types);
1540 test!(@binary Div, div[checked_div], DivAssign, div_assign, call_for_all_types);
1541 test!(@binary Mul, mul[checked_mul], MulAssign, mul_assign, call_for_all_types);
1542 test!(@binary Rem, rem[checked_rem], RemAssign, rem_assign, call_for_all_types);
1543 test!(@binary Sub, sub[checked_sub], SubAssign, sub_assign, call_for_all_types);
1544
1545 test!(@binary BitAnd, bitand, BitAndAssign, bitand_assign, call_for_unsigned_types, call_for_signed_types);
1546 test!(@binary BitOr, bitor, BitOrAssign, bitor_assign, call_for_unsigned_types, call_for_signed_types);
1547 test!(@binary BitXor, bitxor, BitXorAssign, bitxor_assign, call_for_unsigned_types, call_for_signed_types);
1548 test!(@binary Shl, shl[checked_shl], ShlAssign, shl_assign, call_for_unsigned_types, call_for_signed_types);
1549 test!(@binary Shr, shr[checked_shr], ShrAssign, shr_assign, call_for_unsigned_types, call_for_signed_types);
1550
1551 test!(@unary Not, not, call_for_signed_types, call_for_unsigned_types);
1552 test!(@unary Neg, neg, call_for_signed_types, call_for_float_types);
1553 }
1554
1555 #[test]
1556 fn test_debug_impl() {
1557 let val = U16::<LE>::new(10);
1559 assert_eq!(format!("{:?}", val), "U16(10)");
1560 assert_eq!(format!("{:03?}", val), "U16(010)");
1561 assert_eq!(format!("{:x?}", val), "U16(a)");
1562 }
1563
1564 #[test]
1565 fn test_byteorder_traits_coverage() {
1566 let val_be = U16::<BigEndian>::from_bytes([0, 1]);
1567 let val_le = U16::<LittleEndian>::from_bytes([1, 0]);
1568
1569 assert_eq!(val_be.get(), 1);
1570 assert_eq!(val_le.get(), 1);
1571
1572 assert_eq!(format!("{:?}", val_be), "U16(1)");
1574 assert_eq!(format!("{:?}", val_le), "U16(1)");
1575
1576 assert!(val_be >= val_be);
1578 assert!(val_be <= val_be);
1579 assert_eq!(val_be.cmp(&val_be), core::cmp::Ordering::Equal);
1580
1581 assert!(val_be == 1u16);
1583 assert!(val_be >= 1u16);
1584
1585 let default_be: U16<BigEndian> = Default::default();
1587 assert_eq!(default_be.get(), 0);
1588
1589 let val_be_i16 = I16::<BigEndian>::from_bytes([0, 1]);
1591 assert_eq!(val_be_i16.get(), 1);
1592 assert_eq!(format!("{:?}", val_be_i16), "I16(1)");
1593 assert_eq!(val_be_i16.cmp(&val_be_i16), core::cmp::Ordering::Equal);
1594 }
1595}