endian_type/
lib.rs

1#![no_std]
2
3use core::ops::{BitAnd, BitOr, BitXor};
4use core::{mem, slice};
5
6///Type with a specified byte order.
7pub trait Endian<T> {}
8
9macro_rules! impl_Endian{
10    ( for $e:ident) => {
11        impl<T> BitAnd for $e<T>
12        where
13            T: BitAnd,
14        {
15            type Output = $e<<T as BitAnd>::Output>;
16
17            #[inline]
18            fn bitand(self, other: Self) -> Self::Output {
19                $e(self.0 & other.0)
20            }
21        }
22
23        impl<T> BitOr for $e<T>
24        where
25            T: BitOr,
26        {
27            type Output = $e<<T as BitOr>::Output>;
28
29            #[inline]
30            fn bitor(self, other: Self) -> Self::Output {
31                $e(self.0 | other.0)
32            }
33        }
34
35        impl<T> BitXor for $e<T>
36        where
37            T: BitXor,
38        {
39            type Output = $e<<T as BitXor>::Output>;
40
41            #[inline]
42            fn bitxor(self, other: Self) -> Self::Output {
43                $e(self.0 ^ other.0)
44            }
45        }
46
47        impl<T> $e<T>
48        where
49            T: Sized + Copy,
50        {
51            #[inline]
52            pub const unsafe fn from_byte_slice(bytes: &[u8]) -> $e<T> {
53                debug_assert!(bytes.len() >= mem::size_of::<T>());
54                $e({ *(bytes.as_ptr() as *const T) })
55            }
56
57            #[inline]
58            pub fn as_byte_slice(&self) -> &[u8] {
59                unsafe { slice::from_raw_parts(&self.0 as *const T as *const u8, mem::size_of::<T>()) }
60            }
61
62            #[inline]
63            pub fn as_byte_slice_mut(&mut self) -> &mut [u8] {
64                unsafe { slice::from_raw_parts_mut(&mut self.0 as *mut T as *mut u8, mem::size_of::<T>()) }
65            }
66        }
67    }
68}
69
70///Big endian byte order.
71///
72///Most significant byte first.
73#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
74#[repr(transparent)]
75pub struct BigEndian<T>(T);
76
77impl<T> Endian<T> for BigEndian<T> {}
78
79macro_rules! impl_for_BigEndian {
80    ( $t:ident ) => {
81        impl From<BigEndian<$t>> for $t {
82            #[inline]
83            fn from(data: BigEndian<$t>) -> $t {
84                $t::from_be(data.0)
85            }
86        }
87
88        impl From<$t> for BigEndian<$t> {
89            #[inline]
90            fn from(data: $t) -> Self {
91                BigEndian(data.to_be())
92            }
93        }
94
95        impl From<LittleEndian<$t>> for BigEndian<$t> {
96            #[inline]
97            fn from(data: LittleEndian<$t>) -> Self {
98                BigEndian(data.0.swap_bytes())
99            }
100        }
101
102        //TODO: Move these to Endian when https://github.com/rust-lang/rust/issues/67792 stabilized in a few years
103        impl BigEndian<$t>{
104            ///Return the memory representation of this type as a byte array in its endian byte order.
105            ///Note: This is just a transmute.
106            #[inline]
107            pub const fn to_bytes(self) -> [u8; mem::size_of::<BigEndian<$t>>()] {
108                unsafe { mem::transmute(self) }
109            }
110
111            ///Construct a value from its memory representation as a byte array.
112            ///Note: This is just a transmute.
113            #[inline]
114            pub const fn from_bytes(bytes: [u8; mem::size_of::<BigEndian<$t>>()]) -> BigEndian<$t> {
115                unsafe { mem::transmute(bytes) }
116            }
117        }
118    };
119}
120
121impl_Endian!(for BigEndian);
122impl_for_BigEndian!(u16);
123impl_for_BigEndian!(u32);
124impl_for_BigEndian!(u64);
125impl_for_BigEndian!(u128);
126impl_for_BigEndian!(usize);
127impl_for_BigEndian!(i16);
128impl_for_BigEndian!(i32);
129impl_for_BigEndian!(i64);
130impl_for_BigEndian!(i128);
131impl_for_BigEndian!(isize);
132
133///Little endian byte order.
134///
135///Least significant byte first.
136#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
137#[repr(transparent)]
138pub struct LittleEndian<T>(T);
139
140impl<T> Endian<T> for LittleEndian<T> {}
141
142macro_rules! impl_for_LittleEndian {
143    ( $t:ident ) => {
144        impl From<LittleEndian<$t>> for $t {
145            #[inline]
146            fn from(data: LittleEndian<$t>) -> $t {
147                $t::from_le(data.0)
148            }
149        }
150
151        impl From<$t> for LittleEndian<$t> {
152            #[inline]
153            fn from(data: $t) -> Self {
154                LittleEndian(data.to_le())
155            }
156        }
157
158        impl From<BigEndian<$t>> for LittleEndian<$t> {
159            #[inline]
160            fn from(data: BigEndian<$t>) -> Self {
161                LittleEndian(data.0.swap_bytes())
162            }
163        }
164
165        impl LittleEndian<$t>{
166            ///Return the memory representation of this type as a byte array in its endian byte order.
167            ///Note: This is just a transmute.
168            #[inline]
169            pub const fn to_bytes(self) -> [u8; mem::size_of::<LittleEndian<$t>>()] {
170                unsafe { mem::transmute(self) }
171            }
172
173            ///Construct a value from its memory representation as a byte array.
174            ///Note: This is just a transmute.
175            #[inline]
176            pub const fn from_bytes(bytes: [u8; mem::size_of::<LittleEndian<$t>>()]) -> LittleEndian<$t> {
177                unsafe { mem::transmute(bytes) }
178            }
179        }
180    };
181}
182
183impl_Endian!(for LittleEndian);
184impl_for_LittleEndian!(u16);
185impl_for_LittleEndian!(u32);
186impl_for_LittleEndian!(u64);
187impl_for_LittleEndian!(u128);
188impl_for_LittleEndian!(usize);
189impl_for_LittleEndian!(i16);
190impl_for_LittleEndian!(i32);
191impl_for_LittleEndian!(i64);
192impl_for_LittleEndian!(i128);
193impl_for_LittleEndian!(isize);
194
195///Network byte order as defined by IETF RFC1700 <http://tools.ietf.org/html/rfc1700>.
196pub type NetworkOrder<T> = BigEndian<T>;
197
198///Type aliases for primitive types.
199pub mod types {
200    #![allow(non_camel_case_types)]
201
202    use super::*;
203
204    pub type i16_be = BigEndian<i16>;
205    pub type i32_be = BigEndian<i32>;
206    pub type i64_be = BigEndian<i64>;
207    pub type i128_be = BigEndian<i128>;
208    pub type isize_be = BigEndian<isize>;
209
210    pub type u16_be = BigEndian<u16>;
211    pub type u32_be = BigEndian<u32>;
212    pub type u64_be = BigEndian<u64>;
213    pub type u128_be = BigEndian<u128>;
214    pub type usize_be = BigEndian<usize>;
215
216    pub type i16_le = LittleEndian<i16>;
217    pub type i32_le = LittleEndian<i32>;
218    pub type i64_le = LittleEndian<i64>;
219    pub type i128_le = LittleEndian<i128>;
220    pub type isize_le = LittleEndian<isize>;
221
222    pub type u16_le = LittleEndian<u16>;
223    pub type u32_le = LittleEndian<u32>;
224    pub type u64_le = LittleEndian<u64>;
225    pub type u128_le = LittleEndian<u128>;
226    pub type usize_le = LittleEndian<usize>;
227
228    pub type i16_net = NetworkOrder<i16>;
229    pub type i32_net = NetworkOrder<i32>;
230    pub type i128_net = NetworkOrder<i128>;
231    pub type isize_net = NetworkOrder<isize>;
232
233    pub type u16_net = NetworkOrder<u16>;
234    pub type u32_net = NetworkOrder<u32>;
235    pub type u64_net = NetworkOrder<u64>;
236    pub type u128_net = NetworkOrder<u128>;
237    pub type usize_net = NetworkOrder<usize>;
238}
239
240#[cfg(test)]
241mod tests{
242    use super::*;
243    use super::types::*;
244
245    #[test]
246    fn from_to_bytes(){
247        macro_rules! test{
248            ($e:ident for $t:ident in $r:expr) => {
249                for i in $r{
250                    let j = $e::<$t>::from(i);
251                    assert_eq!($e::<$t>::from_bytes(j.to_bytes()) , j);
252                }
253            }
254        }
255
256        test!(BigEndian for i16  in -10000..10000);
257        test!(BigEndian for i32  in -10000..10000);
258        test!(BigEndian for i64  in -10000..10000);
259        test!(BigEndian for i128 in -10000..10000);
260
261        test!(LittleEndian for i16  in -10000..10000);
262        test!(LittleEndian for i32  in -10000..10000);
263        test!(LittleEndian for i64  in -10000..10000);
264        test!(LittleEndian for i128 in -10000..10000);
265
266        test!(BigEndian for u16  in 0..20000);
267        test!(BigEndian for u32  in 0..20000);
268        test!(BigEndian for u64  in 0..20000);
269        test!(BigEndian for u128 in 0..20000);
270
271        test!(LittleEndian for u16  in 0..20000);
272        test!(LittleEndian for u32  in 0..20000);
273        test!(LittleEndian for u64  in 0..20000);
274        test!(LittleEndian for u128 in 0..20000);
275    }
276
277    #[test]
278    fn to_bytes_std(){
279        macro_rules! test{
280            ( for $t:ident in $r:expr) => {
281                for i in $r{
282                    assert_eq!(   BigEndian::<$t>::from(i).to_bytes() , i.to_be_bytes());
283                    assert_eq!(LittleEndian::<$t>::from(i).to_bytes() , i.to_le_bytes());
284                }
285            }
286        }
287
288        test!(for i16  in -10000..10000);
289        test!(for i32  in -10000..10000);
290        test!(for i64  in -10000..10000);
291        test!(for i128 in -10000..10000);
292
293        test!(for i16  in 0..20000);
294        test!(for i32  in 0..20000);
295        test!(for i64  in 0..20000);
296        test!(for i128 in 0..20000);
297    }
298
299    #[test]
300    fn as_to_byte_slice(){
301        macro_rules! test{
302            ($e:ident for $t:ident in $r:expr) => {
303                for i in $r{
304                    let mut j = $e::<$t>::from(i);
305                    assert_eq!(unsafe{$e::<$t>::from_byte_slice(j.as_byte_slice())} , j);
306                    assert_eq!(unsafe{$e::<$t>::from_byte_slice(j.as_byte_slice_mut())} , j);
307                }
308            }
309        }
310
311        test!(BigEndian for i16  in -10000..10000);
312        test!(BigEndian for i32  in -10000..10000);
313        test!(BigEndian for i64  in -10000..10000);
314        test!(BigEndian for i128 in -10000..10000);
315
316        test!(LittleEndian for i16  in -10000..10000);
317        test!(LittleEndian for i32  in -10000..10000);
318        test!(LittleEndian for i64  in -10000..10000);
319        test!(LittleEndian for i128 in -10000..10000);
320
321        test!(BigEndian for u16  in 0..20000);
322        test!(BigEndian for u32  in 0..20000);
323        test!(BigEndian for u64  in 0..20000);
324        test!(BigEndian for u128 in 0..20000);
325
326        test!(LittleEndian for u16  in 0..20000);
327        test!(LittleEndian for u32  in 0..20000);
328        test!(LittleEndian for u64  in 0..20000);
329        test!(LittleEndian for u128 in 0..20000);
330    }
331
332}
333
334#[cfg(doctest)]
335mod test_readme {
336    macro_rules! external_doc_test {
337        ($x:expr) => {
338            #[doc = $x]
339            extern {}
340        };
341    }
342    external_doc_test!(include_str!("../README.md"));
343}