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