byteorder_pod/
lib.rs

1#![deny(missing_docs)]
2
3//! Provides types that assist with byte order conversions of primitive data
4//! types.
5//!
6//! # Example
7//!
8//! ```
9//! # extern crate pod;
10//! # extern crate byteorder_pod;
11//! use pod::Pod;
12//! use byteorder_pod::unaligned::{Le, Be};
13//!
14//! unsafe impl Pod for Data { }
15//!
16//! #[repr(C)]
17//! struct Data(u8, Le<u16>, Be<u32>);
18//!
19//! # fn main() {
20//! let data = Data(1, From::from(0x2055), From::from(0xdeadbeef));
21//!
22//! let cmp = &[
23//!     0x01,
24//!     0x55, 0x20,
25//!     0xde, 0xad, 0xbe, 0xef,
26//! ];
27//!
28//! assert_eq!(cmp, data.as_bytes());
29//! # }
30//!
31//! ```
32
33extern 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
51/// Aligned type aliases
52pub mod aligned {
53    use byteorder;
54    use super::EndianPrimitive;
55
56    /// A type alias for little endian primitives
57    pub type Le<T> = EndianPrimitive<byteorder::LittleEndian, T, T>;
58
59    /// A type alias for big endian primitives
60    pub type Be<T> = EndianPrimitive<byteorder::BigEndian, T, T>;
61
62    /// A type alias for native endian primitives
63    pub type Native<T> = EndianPrimitive<byteorder::NativeEndian, T, T>;
64}
65
66/// Unaligned type aliases
67pub mod unaligned {
68    use byteorder;
69    use super::EndianPrimitive;
70
71    /// A type alias for unaligned little endian primitives
72    pub type Le<T> = EndianPrimitive<byteorder::LittleEndian, T, ()>;
73
74    /// A type alias for unaligned big endian primitives
75    pub type Be<T> = EndianPrimitive<byteorder::BigEndian, T, ()>;
76
77    /// A type alias for unaligned native endian primitives
78    pub type Native<T> = EndianPrimitive<byteorder::NativeEndian, T, ()>;
79}
80
81/// A POD container for a primitive that stores a value in the specified endianness
82/// in memory, and transforms on `get`/`set`
83#[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    /// Creates a new value
92    #[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    /// Transforms to the native value
102    #[inline]
103    pub fn get(&self) -> T {
104        EndianConvert::from::<B>(&self.value)
105    }
106
107    /// Transforms from a native value
108    #[inline]
109    pub fn set(&mut self, v: T) {
110        self.value = EndianConvert::to::<B>(v)
111    }
112
113    /// Gets the inner untransformed value
114    #[inline]
115    pub fn raw(&self) -> &T::Unaligned {
116        &self.value
117    }
118
119    /// A mutable reference to the inner untransformed value
120    #[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
193/// Describes a value that can be converted to and from a specified byte order.
194pub trait EndianConvert: Aligned {
195    /// Converts a value from `B`
196    fn from<B: ByteOrder>(&Self::Unaligned) -> Self;
197
198    /// Converts a value to `B`
199    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}