#![deny(missing_docs)]
extern crate byteorder;
extern crate pod;
#[cfg(feature = "uninitialized")]
extern crate uninitialized;
use std::marker::PhantomData;
use std::fmt;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use byteorder::ByteOrder;
use pod::packed::{Unaligned, Aligned, Packed};
use pod::Pod;
#[cfg(feature = "uninitialized")]
use uninitialized::uninitialized;
#[cfg(not(feature = "uninitialized"))]
use std::mem::zeroed as uninitialized;
pub mod aligned {
use byteorder;
use super::EndianPrimitive;
pub type Le<T> = EndianPrimitive<byteorder::LittleEndian, T, T>;
pub type Be<T> = EndianPrimitive<byteorder::BigEndian, T, T>;
pub type Native<T> = EndianPrimitive<byteorder::NativeEndian, T, T>;
}
pub mod unaligned {
use byteorder;
use super::EndianPrimitive;
pub type Le<T> = EndianPrimitive<byteorder::LittleEndian, T, ()>;
pub type Be<T> = EndianPrimitive<byteorder::BigEndian, T, ()>;
pub type Native<T> = EndianPrimitive<byteorder::NativeEndian, T, ()>;
}
#[repr(C)]
pub struct EndianPrimitive<B, T: EndianConvert, Alignment = ()> {
_alignment: [Alignment; 0],
value: T::Unaligned,
_phantom: PhantomData<*const B>,
}
impl<B: ByteOrder, T: EndianConvert, A> EndianPrimitive<B, T, A> {
#[inline]
pub fn new(v: T) -> Self {
EndianPrimitive {
_alignment: [],
value: EndianConvert::to::<B>(v),
_phantom: PhantomData,
}
}
#[inline]
pub fn get(&self) -> T {
EndianConvert::from::<B>(&self.value)
}
#[inline]
pub fn set(&mut self, v: T) {
self.value = EndianConvert::to::<B>(v)
}
#[inline]
pub fn raw(&self) -> &T::Unaligned {
&self.value
}
#[inline]
pub fn raw_mut(&mut self) -> &mut T::Unaligned {
&mut self.value
}
}
unsafe impl<B: Pod, T: EndianConvert, A> Pod for EndianPrimitive<B, T, A> { }
unsafe impl<B, T: EndianConvert, A: Unaligned> Unaligned for EndianPrimitive<B, T, A> { }
unsafe impl<B, T: EndianConvert, A: Unaligned> Packed for EndianPrimitive<B, T, A> { }
impl<B: ByteOrder, T: Default + EndianConvert, A> Default for EndianPrimitive<B, T, A> {
#[inline]
fn default() -> Self {
Self::new(Default::default())
}
}
impl<B: ByteOrder, T: EndianConvert, A> From<T> for EndianPrimitive<B, T, A> {
#[inline]
fn from(v: T) -> Self {
Self::new(v)
}
}
impl<B: ByteOrder, T: fmt::Debug + EndianConvert, A> fmt::Debug for EndianPrimitive<B, T, A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<T as fmt::Debug>::fmt(&self.get(), f)
}
}
impl<ARHS, A, BRHS: ByteOrder, RHS: EndianConvert, B: ByteOrder, T: EndianConvert + PartialEq<RHS>> PartialEq<EndianPrimitive<BRHS, RHS, ARHS>> for EndianPrimitive<B, T, A> {
#[inline]
fn eq(&self, other: &EndianPrimitive<BRHS, RHS, ARHS>) -> bool {
self.get().eq(&other.get())
}
}
impl<A, B: ByteOrder, T: EndianConvert + Eq> Eq for EndianPrimitive<B, T, A> { }
impl<ARHS, A, BRHS: ByteOrder, RHS: EndianConvert, B: ByteOrder, T: EndianConvert + PartialOrd<RHS>> PartialOrd<EndianPrimitive<BRHS, RHS, ARHS>> for EndianPrimitive<B, T, A> {
#[inline]
fn partial_cmp(&self, other: &EndianPrimitive<BRHS, RHS, ARHS>) -> Option<Ordering> {
self.get().partial_cmp(&other.get())
}
}
impl<B: ByteOrder, T: EndianConvert + Ord, A> Ord for EndianPrimitive<B, T, A> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.get().cmp(&other.get())
}
}
impl<B, T: EndianConvert + Hash, A> Hash for EndianPrimitive<B, T, A> where T::Unaligned: Hash {
#[inline]
fn hash<H: Hasher>(&self, h: &mut H) {
self.value.hash(h)
}
}
impl<B, T: EndianConvert, A> Clone for EndianPrimitive<B, T, A> {
#[inline]
fn clone(&self) -> Self {
EndianPrimitive {
_alignment: [],
value: self.value.clone(),
_phantom: PhantomData,
}
}
}
impl<B, T: EndianConvert, A: Copy> Copy for EndianPrimitive<B, T, A> { }
pub trait EndianConvert: Aligned {
fn from<B: ByteOrder>(&Self::Unaligned) -> Self;
fn to<B: ByteOrder>(self) -> Self::Unaligned;
}
macro_rules! endian_impl {
($(($($tt:tt)*)),*) => {
$(
endian_impl! { $($tt)* }
)*
};
($t:ty: $s:expr => $r:ident, $w:ident) => {
impl EndianConvert for $t {
#[inline]
fn from<B: ByteOrder>(s: &Self::Unaligned) -> Self {
B::$r(s) as _
}
#[inline]
fn to<B: ByteOrder>(self) -> Self::Unaligned {
let mut s: Self::Unaligned = unsafe { uninitialized() };
B::$w(&mut s, self as _);
s
}
}
impl<B: ByteOrder, A> Into<$t> for EndianPrimitive<B, $t, A> {
#[inline]
fn into(self) -> $t {
self.get()
}
}
};
}
endian_impl! {
(u16: 2 => read_u16, write_u16),
(i16: 2 => read_i16, write_i16),
(i32: 4 => read_i32, write_i32),
(u32: 4 => read_u32, write_u32),
(i64: 8 => read_i64, write_i64),
(u64: 8 => read_u64, write_u64),
(f32: 4 => read_f32, write_f32),
(f64: 8 => read_f64, write_f64)
}
#[cfg(target_pointer_width = "32")]
endian_impl! {
(usize: 4 => read_u32, write_u32),
(isize: 4 => read_i32, write_i32)
}
#[cfg(target_pointer_width = "64")]
endian_impl! {
(usize: 8 => read_u64, write_u64),
(isize: 8 => read_i64, write_i64)
}
impl<T> EndianConvert for *const T {
#[inline]
fn from<B: ByteOrder>(s: &Self::Unaligned) -> Self {
<usize as EndianConvert>::from::<B>(s) as _
}
#[inline]
fn to<B: ByteOrder>(self) -> Self::Unaligned {
<usize as EndianConvert>::to::<B>(self as _)
}
}
impl<T> EndianConvert for *mut T {
#[inline]
fn from<B: ByteOrder>(s: &Self::Unaligned) -> Self {
<usize as EndianConvert>::from::<B>(s) as _
}
#[inline]
fn to<B: ByteOrder>(self) -> Self::Unaligned {
<usize as EndianConvert>::to::<B>(self as _)
}
}
impl<T, B: ByteOrder, A> Into<*const T> for EndianPrimitive<B, *const T, A> {
#[inline]
fn into(self) -> *const T {
self.get()
}
}
impl<T, B: ByteOrder, A> Into<*mut T> for EndianPrimitive<B, *mut T, A> {
#[inline]
fn into(self) -> *mut T {
self.get()
}
}
impl EndianConvert for bool {
#[inline]
fn from<B: ByteOrder>(s: &Self::Unaligned) -> Self {
*s as u8 != 0
}
#[inline]
fn to<B: ByteOrder>(self) -> Self::Unaligned {
if self as u8 != 0 { true } else { false }
}
}
impl<B: ByteOrder, A> Into<bool> for EndianPrimitive<B, bool, A> {
#[inline]
fn into(self) -> bool {
self.get()
}
}
#[cfg(test)]
mod tests {
use byteorder;
use super::*;
fn align_size<B: byteorder::ByteOrder>() {
fn f<B: byteorder::ByteOrder, T: EndianConvert>() {
use std::mem::{size_of, align_of};
assert_eq!(size_of::<EndianPrimitive<B, T, T>>(), size_of::<T>());
assert_eq!(size_of::<EndianPrimitive<B, T, ()>>(), size_of::<T>());
assert_eq!(align_of::<EndianPrimitive<B, T, T>>(), align_of::<T>());
assert_eq!(align_of::<EndianPrimitive<B, T, ()>>(), 1);
}
f::<B, *const u32>();
f::<B, *mut u32>();
f::<B, isize>();
f::<B, usize>();
f::<B, i16>();
f::<B, i32>();
f::<B, i64>();
f::<B, u16>();
f::<B, u32>();
f::<B, u64>();
f::<B, f32>();
f::<B, f64>();
f::<B, bool>();
}
#[test]
fn align_size_ne() {
align_size::<byteorder::NativeEndian>();
align_size::<byteorder::LittleEndian>();
align_size::<byteorder::BigEndian>();
}
}