1use std::mem::{align_of, size_of};
36
37#[macro_export]
40macro_rules! const_assert {
41 ($x:expr $(,)?) => {
42 #[allow(unknown_lints, clippy::eq_op)]
43 const _: [(); 0 - !{
44 const ASSERT: bool = $x;
45 ASSERT
46 } as usize] = [];
47 };
48}
49
50use crate::ByteValued;
51
52macro_rules! endian_type {
53 ($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) => {
54 #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
58 pub struct $new_type($old_type);
59
60 impl $new_type {
61 fn _assert() {
62 const_assert!(align_of::<$new_type>() == align_of::<$old_type>());
63 const_assert!(size_of::<$new_type>() == size_of::<$old_type>());
64 }
65
66 pub fn to_native(self) -> $old_type {
68 $old_type::$from_new(self.0)
69 }
70 }
71
72 unsafe impl ByteValued for $new_type {}
73
74 impl PartialEq<$old_type> for $new_type {
75 fn eq(&self, other: &$old_type) -> bool {
76 self.0 == $old_type::$to_new(*other)
77 }
78 }
79
80 impl PartialEq<$new_type> for $old_type {
81 fn eq(&self, other: &$new_type) -> bool {
82 $old_type::$to_new(other.0) == *self
83 }
84 }
85
86 impl From<$new_type> for $old_type {
87 fn from(v: $new_type) -> $old_type {
88 $old_type::$from_new(v.0)
89 }
90 }
91
92 impl From<$old_type> for $new_type {
93 fn from(v: $old_type) -> $new_type {
94 $new_type($old_type::$to_new(v))
95 }
96 }
97 };
98}
99
100endian_type!(u16, Le16, to_le, from_le);
101endian_type!(i16, SLe16, to_le, from_le);
102endian_type!(u32, Le32, to_le, from_le);
103endian_type!(i32, SLe32, to_le, from_le);
104endian_type!(u64, Le64, to_le, from_le);
105endian_type!(i64, SLe64, to_le, from_le);
106endian_type!(usize, LeSize, to_le, from_le);
107endian_type!(isize, SLeSize, to_le, from_le);
108endian_type!(u16, Be16, to_be, from_be);
109endian_type!(i16, SBe16, to_be, from_be);
110endian_type!(u32, Be32, to_be, from_be);
111endian_type!(i32, SBe32, to_be, from_be);
112endian_type!(u64, Be64, to_be, from_be);
113endian_type!(i64, SBe64, to_be, from_be);
114endian_type!(usize, BeSize, to_be, from_be);
115endian_type!(isize, SBeSize, to_be, from_be);
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 use std::convert::From;
122 use std::mem::transmute;
123
124 #[cfg(target_endian = "little")]
125 const NATIVE_LITTLE: bool = true;
126 #[cfg(target_endian = "big")]
127 const NATIVE_LITTLE: bool = false;
128 const NATIVE_BIG: bool = !NATIVE_LITTLE;
129
130 macro_rules! endian_test {
131 ($old_type:ty, $new_type:ty, $test_name:ident, $native:expr) => {
132 mod $test_name {
133 use super::*;
134
135 #[allow(overflowing_literals)]
136 #[test]
137 fn equality() {
138 let v = 0x0123456789ABCDEF as $old_type;
139 let endian_v: $new_type = From::from(v);
140 let endian_into: $old_type = endian_v.into();
141 let endian_transmute: $old_type = unsafe { transmute(endian_v) };
142
143 if $native {
144 assert_eq!(endian_v, endian_transmute);
145 } else {
146 assert_eq!(endian_v, endian_transmute.swap_bytes());
147 }
148
149 assert_eq!(v, endian_into);
150 assert!(v == endian_v);
151 assert!(endian_v == v);
152 }
153 }
154 };
155 }
156
157 endian_test!(u16, Le16, test_le16, NATIVE_LITTLE);
158 endian_test!(i16, SLe16, test_sle16, NATIVE_LITTLE);
159 endian_test!(u32, Le32, test_le32, NATIVE_LITTLE);
160 endian_test!(i32, SLe32, test_sle32, NATIVE_LITTLE);
161 endian_test!(u64, Le64, test_le64, NATIVE_LITTLE);
162 endian_test!(i64, SLe64, test_sle64, NATIVE_LITTLE);
163 endian_test!(usize, LeSize, test_le_size, NATIVE_LITTLE);
164 endian_test!(isize, SLeSize, test_sle_size, NATIVE_LITTLE);
165 endian_test!(u16, Be16, test_be16, NATIVE_BIG);
166 endian_test!(i16, SBe16, test_sbe16, NATIVE_BIG);
167 endian_test!(u32, Be32, test_be32, NATIVE_BIG);
168 endian_test!(i32, SBe32, test_sbe32, NATIVE_BIG);
169 endian_test!(u64, Be64, test_be64, NATIVE_BIG);
170 endian_test!(i64, SBe64, test_sbe64, NATIVE_BIG);
171 endian_test!(usize, BeSize, test_be_size, NATIVE_BIG);
172 endian_test!(isize, SBeSize, test_sbe_size, NATIVE_BIG);
173}