#![feature(core_intrinsics)]
use std::mem::transmute;
pub trait Swappable {}
impl Swappable for u128 {}
impl Swappable for u64 {}
impl Swappable for u32 {}
impl Swappable for u16 {}
impl Swappable for i128 {}
impl Swappable for i64 {}
impl Swappable for i32 {}
impl Swappable for i16 {}
impl Swappable for usize {}
impl Swappable for isize {}
impl Swappable for f32 {}
impl Swappable for f64 {}
pub struct LittleEndian<T: Swappable> {
data: T,
}
pub struct BigEndian<T: Swappable> {
data: T,
}
macro_rules! into_from {
($type: ident, $end: ident, $a: tt, $b: tt, $swap: tt) => {
impl Into<$type> for $end<$type> {
fn into(self) -> $type {
#[cfg(target_endian = $a)]
return self.data;
#[cfg(target_endian = $b)]
return unsafe { transmute(self.data.$swap()) };
}
}
impl From<$type> for $end<$type> {
fn from(value: $type) -> Self {
#[cfg(target_endian = $a)]
return Self { data: value };
#[cfg(target_endian = $b)]
return Self {
data: unsafe { transmute(value.$swap()) },
};
}
}
};
}
macro_rules! le_into_from {
($type: ident) => {
into_from! {$type, LittleEndian, "little", "big", to_le_bytes}
};
}
macro_rules! be_into_from {
($type: ident) => {
into_from! {$type, BigEndian, "big", "little", to_be_bytes}
};
}
le_into_from! {u16}
le_into_from! {u32}
le_into_from! {u64}
le_into_from! {u128}
le_into_from! {usize}
le_into_from! {i16}
le_into_from! {i32}
le_into_from! {i64}
le_into_from! {i128}
le_into_from! {isize}
le_into_from! {f32}
le_into_from! {f64}
be_into_from! {u16}
be_into_from! {u32}
be_into_from! {u64}
be_into_from! {u128}
be_into_from! {usize}
be_into_from! {i16}
be_into_from! {i32}
be_into_from! {i64}
be_into_from! {i128}
be_into_from! {isize}
be_into_from! {f32}
be_into_from! {f64}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! test_type {
($fun: ident, $type: ident, $val: expr, $rev: expr) => {
#[test]
fn $fun() {
let l: LittleEndian<$type> = $val.into();
#[cfg(target_endian = "little")]
assert_eq!(l.data, $val);
#[cfg(target_endian = "big")]
assert_eq!(l.data, $rev);
let b: BigEndian<$type> = $val.into();
#[cfg(target_endian = "little")]
assert_eq!(b.data, $rev);
#[cfg(target_endian = "big")]
assert_eq!(b.data, $val);
}
};
}
test_type! {test_u128, u128, 0xaa000000000000000000000000000000, 0x000000000000000000000000000000aa}
test_type! {test_u64, u64, 0xaa00000000000000, 0x00000000000000aa}
test_type! {test_u32, u32, 0xaa000000, 0x000000aa}
test_type! {test_u16, u16, 0xaa00, 0x00aa}
#[cfg(target_pointer_width = "32")]
test_type! {test_usize, usize, 0xaa000000, 0x000000aa}
#[cfg(target_pointer_width = "64")]
test_type! {test_usize, usize, 0xaa00000000000000, 0x00000000000000aa}
#[cfg(target_pointer_width = "32")]
test_type! {test_isize, isize, -2isize, -16777217isize}
#[cfg(target_pointer_width = "64")]
test_type! {test_isize, isize, -2isize, -72057594037927937isize}
test_type! {test_i16, i16, -2i16, -257i16}
test_type! {test_i32, i32, -2i32, -16777217i32}
test_type! {test_i64, i64, -2i64, -72057594037927937i64}
test_type! {test_i128, i128, -2i128, -1329227995784915872903807060280344577i128}
#[test]
fn test_floats() {
const F32_VAL: f32 = 1.3_f32;
const F32_REV: f32 = 272302750000000000000000_f32;
const F64_VAL: f64 = 1.3_f64;
const F64_REV: f64 = -6065988000116450000000000000000000000000000000000000000000000000000_f64;
let l: LittleEndian<f32> = F32_VAL.into();
#[cfg(target_endian = "little")]
assert_eq!(l.data, F32_VAL);
#[cfg(target_endian = "big")]
assert_eq!(l.data, F32_REV);
let b: BigEndian<f32> = F32_VAL.into();
#[cfg(target_endian = "little")]
assert_eq!(b.data, F32_REV);
#[cfg(target_endian = "big")]
assert_eq!(b.data, F32_VAL);
let l: LittleEndian<f64> = F64_VAL.into();
#[cfg(target_endian = "little")]
assert_eq!(l.data, F64_VAL);
#[cfg(target_endian = "big")]
assert_eq!(l.data, F64_REV);
let b: BigEndian<f64> = F64_VAL.into();
#[cfg(target_endian = "little")]
assert_eq!(b.data, F64_REV);
#[cfg(target_endian = "big")]
assert_eq!(b.data, F64_VAL);
}
}