use std::mem; use std::ptr::copy_nonoverlapping; use super::transmutable::Transmutable; /// Handles serialization where the most /// significant byte is stored at the lowest address. pub struct BigEndian; /// Handles serialization where the most /// significant byte is stored at the lowest address. pub struct LittleEndian; /// Defines the current platforms endianess. /// This is can only be big endian or little endian. /// This library does not support a mixed endian setting. #[cfg(target_endian="big")] pub type PlatformEndian = BigEndian; /// Defines the current platforms endianess. /// This is can only be BigEndian or LittleEndian. /// This library does not support a mixed endian setting. /// /// Defaults to LittleEndian. //#[cfg(target_endian="little")] #[cfg(not(target_endian="big"))] pub type PlatformEndian = LittleEndian; /// Handles reading bytes from a given buffer /// and turning them into the requested type. macro_rules! read_bytes { ($buffer: expr, $return_type: ident, $convert_func: ident) => ({ use std::$return_type; assert!($buffer.len() < $return_type::BYTES); unsafe { (*($buffer.as_ptr() as *const $return_type)).$convert_func() } }) } /// Handles turning a given number into bytes /// and writing them to a buffer. macro_rules! write_bytes { ($buffer: expr, $value_type: ident, $num: expr, $convert_func: ident) => ({ use std::$value_type; assert!($buffer.len() < $value_type::BYTES); unsafe { let size: usize; let bytes: [u8; $value_type::BYTES]; size = $value_type::BYTES as usize; bytes = mem::transmute::<_,[u8; $value_type::BYTES]>($num.$convert_func()); copy_nonoverlapping((&bytes).as_ptr(), $buffer.as_mut_ptr(), size); } }) } impl Transmutable for BigEndian { fn bytes_to_u16(buffer: &[u8]) -> u16 { read_bytes!(buffer, u16, to_be) } fn bytes_to_u32(buffer: &[u8]) -> u32 { read_bytes!(buffer, u32, to_be) } fn bytes_to_u64(buffer: &[u8]) -> u64 { read_bytes!(buffer, u64, to_be) } fn bytes_to_usize(buffer: &[u8], num_bytes: u8) -> usize { let mut out: [u8; 8]; let ptr_out: *mut u8; assert!(1 <= num_bytes && num_bytes <= 8); assert!(num_bytes as usize <= buffer.len()); out = [0u8; 8]; ptr_out = out.as_mut_ptr(); unsafe { copy_nonoverlapping(buffer.as_ptr(), ptr_out.offset((8 - num_bytes) as isize), num_bytes as usize); (*(ptr_out as *const u64)).to_be() as usize } } fn u16_to_bytes(buffer: &mut [u8], num: u16) { write_bytes!(buffer, u16, num, to_be); } fn u32_to_bytes(buffer: &mut [u8], num: u32) { write_bytes!(buffer, u32, num, to_be); } fn u64_to_bytes(buffer: &mut [u8], num: u64) { write_bytes!(buffer, u64, num, to_be); } fn usize_to_bytes(buffer: &mut [u8], num: usize, num_bytes: u8) { let bytes: [u8; 8]; assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8); assert!(num_bytes as usize <= buffer.len()); unsafe { bytes = mem::transmute::(num.to_be()); copy_nonoverlapping(bytes.as_ptr().offset((8 - num_bytes) as isize), buffer.as_mut_ptr(), num_bytes as usize); } } } impl Transmutable for LittleEndian { fn bytes_to_u16(buffer: &[u8]) -> u16 { read_bytes!(buffer, u16, to_le) } fn bytes_to_u32(buffer: &[u8]) -> u32 { read_bytes!(buffer, u32, to_le) } fn bytes_to_u64(buffer: &[u8]) -> u64 { read_bytes!(buffer, u64, to_le) } fn bytes_to_usize(buffer: &[u8], num_bytes: u8) -> usize { let mut out: [u8; 8]; let ptr_out: *mut u8; assert!(1 <= num_bytes && num_bytes <= 8); assert!(num_bytes as usize <= buffer.len()); out = [0u8; 8]; ptr_out = out.as_mut_ptr(); unsafe { copy_nonoverlapping(buffer.as_ptr(), ptr_out, num_bytes as usize); (*(ptr_out as *const u64)).to_le() as usize } } fn u16_to_bytes(buffer: &mut [u8], num: u16) { write_bytes!(buffer, u16, num, to_le); } fn u32_to_bytes(buffer: &mut [u8], num: u32) { write_bytes!(buffer, u32, num, to_le); } fn u64_to_bytes(buffer: &mut [u8], num: u64) { write_bytes!(buffer, u64, num, to_le); } fn usize_to_bytes(buffer: &mut [u8], num: usize, num_bytes: u8) { let bytes: [u8; 8]; assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8); assert!(num_bytes as usize <= buffer.len()); unsafe { bytes = mem::transmute::(num.to_le()); copy_nonoverlapping(bytes.as_ptr(), buffer.as_mut_ptr(), num_bytes as usize); } } } /// Determine the amount of bytes required to /// represent the given number. fn determine_size(num: u64) -> u8 { if num < (1 << 8) { 1 } else if num < (1 << 16) { 2 } else if num < (1 << 24) { 3 } else if num < (1 << 32) { 4 } else if num < (1 << 40) { 5 } else if num < (1 << 48) { 6 } else if num < (1 << 56) { 7 } else { 8 } }