1use std::mem::{align_of, size_of};
37
38use crate::bytes::ByteValued;
39
40macro_rules! const_assert {
41 ($condition:expr) => {
42 let _ = [(); 0 - !$condition as usize];
43 };
44}
45
46macro_rules! endian_type {
47 ($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) => {
48 #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
52 pub struct $new_type($old_type);
53
54 impl $new_type {
55 fn _assert() {
56 const_assert!(align_of::<$new_type>() == align_of::<$old_type>());
57 const_assert!(size_of::<$new_type>() == size_of::<$old_type>());
58 }
59
60 pub fn to_native(self) -> $old_type {
62 $old_type::$from_new(self.0)
63 }
64 }
65
66 unsafe impl ByteValued for $new_type {}
69
70 impl PartialEq<$old_type> for $new_type {
71 fn eq(&self, other: &$old_type) -> bool {
72 self.0 == $old_type::$to_new(*other)
73 }
74 }
75
76 impl PartialEq<$new_type> for $old_type {
77 fn eq(&self, other: &$new_type) -> bool {
78 $old_type::$to_new(other.0) == *self
79 }
80 }
81
82 impl From<$new_type> for $old_type {
83 fn from(v: $new_type) -> $old_type {
84 v.to_native()
85 }
86 }
87
88 impl From<$old_type> for $new_type {
89 fn from(v: $old_type) -> $new_type {
90 $new_type($old_type::$to_new(v))
91 }
92 }
93 };
94}
95
96endian_type!(u16, Le16, to_le, from_le);
97endian_type!(u32, Le32, to_le, from_le);
98endian_type!(u64, Le64, to_le, from_le);
99endian_type!(usize, LeSize, to_le, from_le);
100endian_type!(u16, Be16, to_be, from_be);
101endian_type!(u32, Be32, to_be, from_be);
102endian_type!(u64, Be64, to_be, from_be);
103endian_type!(usize, BeSize, to_be, from_be);
104
105#[cfg(test)]
106mod tests {
107 #![allow(clippy::undocumented_unsafe_blocks)]
108 use super::*;
109
110 use std::convert::From;
111 use std::mem::transmute;
112
113 #[cfg(target_endian = "little")]
114 const NATIVE_LITTLE: bool = true;
115 #[cfg(target_endian = "big")]
116 const NATIVE_LITTLE: bool = false;
117 const NATIVE_BIG: bool = !NATIVE_LITTLE;
118
119 macro_rules! endian_test {
120 ($old_type:ty, $new_type:ty, $test_name:ident, $native:expr) => {
121 mod $test_name {
122 use super::*;
123
124 #[allow(overflowing_literals)]
125 #[test]
126 fn test_endian_type() {
127 <$new_type>::_assert();
128
129 let v = 0x0123_4567_89AB_CDEF as $old_type;
130 let endian_v: $new_type = From::from(v);
131 let endian_into: $old_type = endian_v.into();
132 let endian_transmute: $old_type = unsafe { transmute(endian_v) };
133
134 if $native {
135 assert_eq!(endian_v, endian_transmute);
136 } else {
137 assert_eq!(endian_v, endian_transmute.swap_bytes());
138 }
139
140 assert_eq!(endian_into, v);
141 assert_eq!(endian_v.to_native(), v);
142
143 assert!(v == endian_v);
144 assert!(endian_v == v);
145 }
146 }
147 };
148 }
149
150 endian_test!(u16, Le16, test_le16, NATIVE_LITTLE);
151 endian_test!(u32, Le32, test_le32, NATIVE_LITTLE);
152 endian_test!(u64, Le64, test_le64, NATIVE_LITTLE);
153 endian_test!(usize, LeSize, test_le_size, NATIVE_LITTLE);
154 endian_test!(u16, Be16, test_be16, NATIVE_BIG);
155 endian_test!(u32, Be32, test_be32, NATIVE_BIG);
156 endian_test!(u64, Be64, test_be64, NATIVE_BIG);
157 endian_test!(usize, BeSize, test_be_size, NATIVE_BIG);
158}