1 //! Types for compile-time and run-time endianity.
2 
3 use byteorder;
4 use byteorder::ByteOrder;
5 use core::fmt::Debug;
6 
7 /// A trait describing the endianity of some buffer.
8 pub trait Endianity: Debug + Default + Clone + Copy + PartialEq + Eq {
9     /// Return true for big endian byte order.
is_big_endian(self) -> bool10     fn is_big_endian(self) -> bool;
11 
12     /// Return true for little endian byte order.
13     #[inline]
is_little_endian(self) -> bool14     fn is_little_endian(self) -> bool {
15         !self.is_big_endian()
16     }
17 
18     /// Reads an unsigned 16 bit integer from `buf`.
19     ///
20     /// # Panics
21     ///
22     /// Panics when `buf.len() < 2`.
23     #[inline]
read_u16(self, buf: &[u8]) -> u1624     fn read_u16(self, buf: &[u8]) -> u16 {
25         if self.is_big_endian() {
26             byteorder::BigEndian::read_u16(buf)
27         } else {
28             byteorder::LittleEndian::read_u16(buf)
29         }
30     }
31 
32     /// Reads an unsigned 32 bit integer from `buf`.
33     ///
34     /// # Panics
35     ///
36     /// Panics when `buf.len() < 4`.
37     #[inline]
read_u32(self, buf: &[u8]) -> u3238     fn read_u32(self, buf: &[u8]) -> u32 {
39         if self.is_big_endian() {
40             byteorder::BigEndian::read_u32(buf)
41         } else {
42             byteorder::LittleEndian::read_u32(buf)
43         }
44     }
45 
46     /// Reads an unsigned 64 bit integer from `buf`.
47     ///
48     /// # Panics
49     ///
50     /// Panics when `buf.len() < 8`.
51     #[inline]
read_u64(self, buf: &[u8]) -> u6452     fn read_u64(self, buf: &[u8]) -> u64 {
53         if self.is_big_endian() {
54             byteorder::BigEndian::read_u64(buf)
55         } else {
56             byteorder::LittleEndian::read_u64(buf)
57         }
58     }
59 
60     /// Read an unsigned n-bytes integer u64.
61     ///
62     /// # Panics
63     ///
64     /// Panics when `buf.len() < 1` or `buf.len() > 8`.
65     #[inline]
read_uint(&mut self, buf: &[u8]) -> u6466     fn read_uint(&mut self, buf: &[u8]) -> u64 {
67         if self.is_big_endian() {
68             byteorder::BigEndian::read_uint(buf, buf.len())
69         } else {
70             byteorder::LittleEndian::read_uint(buf, buf.len())
71         }
72     }
73 
74     /// Reads a signed 16 bit integer from `buf`.
75     ///
76     /// # Panics
77     ///
78     /// Panics when `buf.len() < 2`.
79     #[inline]
read_i16(self, buf: &[u8]) -> i1680     fn read_i16(self, buf: &[u8]) -> i16 {
81         self.read_u16(buf) as i16
82     }
83 
84     /// Reads a signed 32 bit integer from `buf`.
85     ///
86     /// # Panics
87     ///
88     /// Panics when `buf.len() < 4`.
89     #[inline]
read_i32(self, buf: &[u8]) -> i3290     fn read_i32(self, buf: &[u8]) -> i32 {
91         self.read_u32(buf) as i32
92     }
93 
94     /// Reads a signed 64 bit integer from `buf`.
95     ///
96     /// # Panics
97     ///
98     /// Panics when `buf.len() < 8`.
99     #[inline]
read_i64(self, buf: &[u8]) -> i64100     fn read_i64(self, buf: &[u8]) -> i64 {
101         self.read_u64(buf) as i64
102     }
103 
104     /// Reads a 32 bit floating point number from `buf`.
105     ///
106     /// # Panics
107     ///
108     /// Panics when `buf.len() < 8`.
109     #[inline]
read_f32(self, buf: &[u8]) -> f32110     fn read_f32(self, buf: &[u8]) -> f32 {
111         f32::from_bits(self.read_u32(buf))
112     }
113 
114     /// Reads a 32 bit floating point number from `buf`.
115     ///
116     /// # Panics
117     ///
118     /// Panics when `buf.len() < 8`.
119     #[inline]
read_f64(self, buf: &[u8]) -> f64120     fn read_f64(self, buf: &[u8]) -> f64 {
121         f64::from_bits(self.read_u64(buf))
122     }
123 
124     /// Writes an unsigned 16 bit integer `n` to `buf`.
125     ///
126     /// # Panics
127     ///
128     /// Panics when `buf.len() < 2`.
129     #[inline]
write_u16(self, buf: &mut [u8], n: u16)130     fn write_u16(self, buf: &mut [u8], n: u16) {
131         if self.is_big_endian() {
132             byteorder::BigEndian::write_u16(buf, n)
133         } else {
134             byteorder::LittleEndian::write_u16(buf, n)
135         }
136     }
137 
138     /// Writes an unsigned 32 bit integer `n` to `buf`.
139     ///
140     /// # Panics
141     ///
142     /// Panics when `buf.len() < 4`.
143     #[inline]
write_u32(self, buf: &mut [u8], n: u32)144     fn write_u32(self, buf: &mut [u8], n: u32) {
145         if self.is_big_endian() {
146             byteorder::BigEndian::write_u32(buf, n)
147         } else {
148             byteorder::LittleEndian::write_u32(buf, n)
149         }
150     }
151 
152     /// Writes an unsigned 64 bit integer `n` to `buf`.
153     ///
154     /// # Panics
155     ///
156     /// Panics when `buf.len() < 8`.
157     #[inline]
write_u64(self, buf: &mut [u8], n: u64)158     fn write_u64(self, buf: &mut [u8], n: u64) {
159         if self.is_big_endian() {
160             byteorder::BigEndian::write_u64(buf, n)
161         } else {
162             byteorder::LittleEndian::write_u64(buf, n)
163         }
164     }
165 }
166 
167 /// Byte order that is selectable at runtime.
168 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
169 pub enum RunTimeEndian {
170     /// Little endian byte order.
171     Little,
172     /// Big endian byte order.
173     Big,
174 }
175 
176 impl Default for RunTimeEndian {
177     #[cfg(target_endian = "little")]
178     #[inline]
default() -> RunTimeEndian179     fn default() -> RunTimeEndian {
180         RunTimeEndian::Little
181     }
182 
183     #[cfg(target_endian = "big")]
184     #[inline]
default() -> RunTimeEndian185     fn default() -> RunTimeEndian {
186         RunTimeEndian::Big
187     }
188 }
189 
190 impl Endianity for RunTimeEndian {
191     #[inline]
is_big_endian(self) -> bool192     fn is_big_endian(self) -> bool {
193         self != RunTimeEndian::Little
194     }
195 }
196 
197 /// Little endian byte order.
198 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
199 pub struct LittleEndian;
200 
201 impl Default for LittleEndian {
202     #[inline]
default() -> LittleEndian203     fn default() -> LittleEndian {
204         LittleEndian
205     }
206 }
207 
208 impl Endianity for LittleEndian {
209     #[inline]
is_big_endian(self) -> bool210     fn is_big_endian(self) -> bool {
211         false
212     }
213 }
214 
215 /// Big endian byte order.
216 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
217 pub struct BigEndian;
218 
219 impl Default for BigEndian {
220     #[inline]
default() -> BigEndian221     fn default() -> BigEndian {
222         BigEndian
223     }
224 }
225 
226 impl Endianity for BigEndian {
227     #[inline]
is_big_endian(self) -> bool228     fn is_big_endian(self) -> bool {
229         true
230     }
231 }
232 
233 /// The native endianity for the target platform.
234 #[cfg(target_endian = "little")]
235 pub type NativeEndian = LittleEndian;
236 
237 #[cfg(target_endian = "little")]
238 #[allow(non_upper_case_globals)]
239 #[doc(hidden)]
240 pub const NativeEndian: LittleEndian = LittleEndian;
241 
242 /// The native endianity for the target platform.
243 #[cfg(target_endian = "big")]
244 pub type NativeEndian = BigEndian;
245 
246 #[cfg(target_endian = "big")]
247 #[allow(non_upper_case_globals)]
248 #[doc(hidden)]
249 pub const NativeEndian: BigEndian = BigEndian;
250