1#![deny(missing_docs)]
2
3extern crate byteorder;
34extern crate pod;
35#[cfg(feature = "uninitialized")]
36extern crate uninitialized;
37
38use std::marker::PhantomData;
39use std::fmt;
40use std::cmp::Ordering;
41use std::hash::{Hash, Hasher};
42use byteorder::ByteOrder;
43use pod::packed::{Unaligned, Aligned, Packed};
44use pod::Pod;
45
46#[cfg(feature = "uninitialized")]
47use uninitialized::uninitialized;
48#[cfg(not(feature = "uninitialized"))]
49use std::mem::zeroed as uninitialized;
50
51pub mod aligned {
53 use byteorder;
54 use super::EndianPrimitive;
55
56 pub type Le<T> = EndianPrimitive<byteorder::LittleEndian, T, T>;
58
59 pub type Be<T> = EndianPrimitive<byteorder::BigEndian, T, T>;
61
62 pub type Native<T> = EndianPrimitive<byteorder::NativeEndian, T, T>;
64}
65
66pub mod unaligned {
68 use byteorder;
69 use super::EndianPrimitive;
70
71 pub type Le<T> = EndianPrimitive<byteorder::LittleEndian, T, ()>;
73
74 pub type Be<T> = EndianPrimitive<byteorder::BigEndian, T, ()>;
76
77 pub type Native<T> = EndianPrimitive<byteorder::NativeEndian, T, ()>;
79}
80
81#[repr(C)]
84pub struct EndianPrimitive<B, T: EndianConvert, Alignment = ()> {
85 _alignment: [Alignment; 0],
86 value: T::Unaligned,
87 _phantom: PhantomData<*const B>,
88}
89
90impl<B: ByteOrder, T: EndianConvert, A> EndianPrimitive<B, T, A> {
91 #[inline]
93 pub fn new(v: T) -> Self {
94 EndianPrimitive {
95 _alignment: [],
96 value: EndianConvert::to::<B>(v),
97 _phantom: PhantomData,
98 }
99 }
100
101 #[inline]
103 pub fn get(&self) -> T {
104 EndianConvert::from::<B>(&self.value)
105 }
106
107 #[inline]
109 pub fn set(&mut self, v: T) {
110 self.value = EndianConvert::to::<B>(v)
111 }
112
113 #[inline]
115 pub fn raw(&self) -> &T::Unaligned {
116 &self.value
117 }
118
119 #[inline]
121 pub fn raw_mut(&mut self) -> &mut T::Unaligned {
122 &mut self.value
123 }
124}
125
126unsafe impl<B: Pod, T: EndianConvert, A> Pod for EndianPrimitive<B, T, A> { }
127unsafe impl<B, T: EndianConvert, A: Unaligned> Unaligned for EndianPrimitive<B, T, A> { }
128unsafe impl<B, T: EndianConvert, A: Unaligned> Packed for EndianPrimitive<B, T, A> { }
129
130impl<B: ByteOrder, T: Default + EndianConvert, A> Default for EndianPrimitive<B, T, A> {
131 #[inline]
132 fn default() -> Self {
133 Self::new(Default::default())
134 }
135}
136
137impl<B: ByteOrder, T: EndianConvert, A> From<T> for EndianPrimitive<B, T, A> {
138 #[inline]
139 fn from(v: T) -> Self {
140 Self::new(v)
141 }
142}
143
144impl<B: ByteOrder, T: fmt::Debug + EndianConvert, A> fmt::Debug for EndianPrimitive<B, T, A> {
145 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146 <T as fmt::Debug>::fmt(&self.get(), f)
147 }
148}
149
150impl<ARHS, A, BRHS: ByteOrder, RHS: EndianConvert, B: ByteOrder, T: EndianConvert + PartialEq<RHS>> PartialEq<EndianPrimitive<BRHS, RHS, ARHS>> for EndianPrimitive<B, T, A> {
151 #[inline]
152 fn eq(&self, other: &EndianPrimitive<BRHS, RHS, ARHS>) -> bool {
153 self.get().eq(&other.get())
154 }
155}
156
157impl<A, B: ByteOrder, T: EndianConvert + Eq> Eq for EndianPrimitive<B, T, A> { }
158
159impl<ARHS, A, BRHS: ByteOrder, RHS: EndianConvert, B: ByteOrder, T: EndianConvert + PartialOrd<RHS>> PartialOrd<EndianPrimitive<BRHS, RHS, ARHS>> for EndianPrimitive<B, T, A> {
160 #[inline]
161 fn partial_cmp(&self, other: &EndianPrimitive<BRHS, RHS, ARHS>) -> Option<Ordering> {
162 self.get().partial_cmp(&other.get())
163 }
164}
165
166impl<B: ByteOrder, T: EndianConvert + Ord, A> Ord for EndianPrimitive<B, T, A> {
167 #[inline]
168 fn cmp(&self, other: &Self) -> Ordering {
169 self.get().cmp(&other.get())
170 }
171}
172
173impl<B, T: EndianConvert + Hash, A> Hash for EndianPrimitive<B, T, A> where T::Unaligned: Hash {
174 #[inline]
175 fn hash<H: Hasher>(&self, h: &mut H) {
176 self.value.hash(h)
177 }
178}
179
180impl<B, T: EndianConvert, A> Clone for EndianPrimitive<B, T, A> {
181 #[inline]
182 fn clone(&self) -> Self {
183 EndianPrimitive {
184 _alignment: [],
185 value: self.value.clone(),
186 _phantom: PhantomData,
187 }
188 }
189}
190
191impl<B, T: EndianConvert, A: Copy> Copy for EndianPrimitive<B, T, A> { }
192
193pub trait EndianConvert: Aligned {
195 fn from<B: ByteOrder>(&Self::Unaligned) -> Self;
197
198 fn to<B: ByteOrder>(self) -> Self::Unaligned;
200}
201
202macro_rules! endian_impl {
203 ($(($($tt:tt)*)),*) => {
204 $(
205 endian_impl! { $($tt)* }
206 )*
207 };
208 ($t:ty: $s:expr => $r:ident, $w:ident) => {
209 impl EndianConvert for $t {
210 #[inline]
211 fn from<B: ByteOrder>(s: &Self::Unaligned) -> Self {
212 B::$r(s) as _
213 }
214
215 #[inline]
216 fn to<B: ByteOrder>(self) -> Self::Unaligned {
217 let mut s: Self::Unaligned = unsafe { uninitialized() };
218 B::$w(&mut s, self as _);
219 s
220 }
221 }
222
223 impl<B: ByteOrder, A> Into<$t> for EndianPrimitive<B, $t, A> {
224 #[inline]
225 fn into(self) -> $t {
226 self.get()
227 }
228 }
229 };
230}
231
232endian_impl! {
233 (u16: 2 => read_u16, write_u16),
234 (i16: 2 => read_i16, write_i16),
235 (i32: 4 => read_i32, write_i32),
236 (u32: 4 => read_u32, write_u32),
237 (i64: 8 => read_i64, write_i64),
238 (u64: 8 => read_u64, write_u64),
239 (f32: 4 => read_f32, write_f32),
240 (f64: 8 => read_f64, write_f64)
241}
242
243#[cfg(target_pointer_width = "32")]
244endian_impl! {
245 (usize: 4 => read_u32, write_u32),
246 (isize: 4 => read_i32, write_i32)
247}
248
249#[cfg(target_pointer_width = "64")]
250endian_impl! {
251 (usize: 8 => read_u64, write_u64),
252 (isize: 8 => read_i64, write_i64)
253}
254
255impl<T> EndianConvert for *const T {
256 #[inline]
257 fn from<B: ByteOrder>(s: &Self::Unaligned) -> Self {
258 <usize as EndianConvert>::from::<B>(s) as _
259 }
260
261 #[inline]
262 fn to<B: ByteOrder>(self) -> Self::Unaligned {
263 <usize as EndianConvert>::to::<B>(self as _)
264 }
265}
266
267impl<T> EndianConvert for *mut T {
268 #[inline]
269 fn from<B: ByteOrder>(s: &Self::Unaligned) -> Self {
270 <usize as EndianConvert>::from::<B>(s) as _
271 }
272
273 #[inline]
274 fn to<B: ByteOrder>(self) -> Self::Unaligned {
275 <usize as EndianConvert>::to::<B>(self as _)
276 }
277}
278
279impl<T, B: ByteOrder, A> Into<*const T> for EndianPrimitive<B, *const T, A> {
280 #[inline]
281 fn into(self) -> *const T {
282 self.get()
283 }
284}
285
286impl<T, B: ByteOrder, A> Into<*mut T> for EndianPrimitive<B, *mut T, A> {
287 #[inline]
288 fn into(self) -> *mut T {
289 self.get()
290 }
291}
292
293impl EndianConvert for bool {
294 #[inline]
295 fn from<B: ByteOrder>(s: &Self::Unaligned) -> Self {
296 *s as u8 != 0
297 }
298
299 #[inline]
300 fn to<B: ByteOrder>(self) -> Self::Unaligned {
301 if self as u8 != 0 { true } else { false }
302 }
303}
304
305impl<B: ByteOrder, A> Into<bool> for EndianPrimitive<B, bool, A> {
306 #[inline]
307 fn into(self) -> bool {
308 self.get()
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use byteorder;
315 use super::*;
316
317 fn align_size<B: byteorder::ByteOrder>() {
318 fn f<B: byteorder::ByteOrder, T: EndianConvert>() {
319 use std::mem::{size_of, align_of};
320
321 assert_eq!(size_of::<EndianPrimitive<B, T, T>>(), size_of::<T>());
322 assert_eq!(size_of::<EndianPrimitive<B, T, ()>>(), size_of::<T>());
323
324 assert_eq!(align_of::<EndianPrimitive<B, T, T>>(), align_of::<T>());
325 assert_eq!(align_of::<EndianPrimitive<B, T, ()>>(), 1);
326 }
327
328 f::<B, *const u32>();
329 f::<B, *mut u32>();
330
331 f::<B, isize>();
332 f::<B, usize>();
333
334 f::<B, i16>();
335 f::<B, i32>();
336 f::<B, i64>();
337
338 f::<B, u16>();
339 f::<B, u32>();
340 f::<B, u64>();
341
342 f::<B, f32>();
343 f::<B, f64>();
344
345 f::<B, bool>();
346 }
347
348 #[test]
349 fn align_size_ne() {
350 align_size::<byteorder::NativeEndian>();
351 align_size::<byteorder::LittleEndian>();
352 align_size::<byteorder::BigEndian>();
353 }
354}