use std::mem; use std::ptr::copy_nonoverlapping; use ::byte_sized::ByteSized; use ::byte_sized::{U16_BYTES, U32_BYTES, U64_BYTES}; use ::converter::Converter; /// 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 serialization where the most /// significant byte is stored at the lowest address. pub enum BigEndian { } /// Handles serialization where the most /// significant byte is stored at the lowest address. pub enum LittleEndian { } /// Create an enumeration of the different /// available endianesses. #[derive(Clone, Copy)] pub enum Endianess { /// Referes to BigEndian. BIG, /// Referes to LittleEndian. LITTLE, /// Referes to PlatformEndian. This can be anyone /// of the other available endians depending on /// the platform you are on. PLATFORM } /// Handles reading bytes from a given buffer /// and turning them into the requested type. macro_rules! read_bytes { ($buffer: expr, $returnType: ident, $convertFunc: ident) => ({ // Make sure that there is enough space to read // a value from the buffer. assert!($buffer.len() == $returnType::BYTES); unsafe { (*($buffer.as_ptr() as *const $returnType)).$convertFunc() } }) } /// Handles turning a given number into bytes /// and writing them to a buffer. macro_rules! write_bytes { ($buffer: expr, $valueType: ident, $numBytes: expr, $num: expr, $convertFunc: ident) => ({ assert!($buffer.len() >= $valueType::BYTES, "Not enough room in the buffer to write to."); unsafe { let size: usize; let bytes: [u8; $numBytes]; size = $valueType::BYTES; bytes = mem::transmute::<_, [u8; $numBytes]>($num.$convertFunc()); copy_nonoverlapping::((&bytes).as_ptr(), $buffer.as_mut_ptr(), size); } }) } impl Converter 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]) -> usize { let mut out: [u8; 8]; let ptr_out: *mut u8; assert!(buffer.len() >= 1 && buffer.len() <= 8); out = [0u8; 8]; ptr_out = out.as_mut_ptr(); unsafe { copy_nonoverlapping::(buffer.as_ptr(), ptr_out.offset((8 - buffer.len()) as isize), buffer.len()); (*(ptr_out as *const u64)).to_be() as usize } } fn u16_to_bytes(buffer: &mut [u8], num: u16) { write_bytes!(buffer, u16, U16_BYTES, num, to_be); } fn u32_to_bytes(buffer: &mut [u8], num: u32) { write_bytes!(buffer, u32, U32_BYTES, num, to_be); } fn u64_to_bytes(buffer: &mut [u8], num: u64) { write_bytes!(buffer, u64, U64_BYTES, num, to_be); } fn usize_to_bytes(buffer: &mut [u8], num: usize) { let bytes: [u8; 8]; let num_bytes: u8; num_bytes = buffer.len() as u8; assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8); assert!(buffer.len() >= 1 && buffer.len() <= 8); 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); } } fn bytes_to_string(buffer: &[u8]) -> String { let byte_count: u64; let new_string: String; // A string array should have atleast a u64 size byte count. assert!(buffer.len() >= U64_BYTES); // Strings start with the size of bytes to read as // a u64. So read that in and then we know how many // bytes make up the string. byte_count = BigEndian::bytes_to_u64(buffer); if byte_count > 0 { match String::from_utf8(buffer[U64_BYTES..(buffer.len()-1)].to_vec()) { Ok(string) => { new_string = string; } Err(error) => { error!("{}", error); } } } else { new_string = String::new(); } new_string } fn string_to_bytes(buffer: &mut [u8], string: String) { let bytes: &[u8]; let byte_count: u64; // Turn the string into a byte array. bytes = string.as_bytes(); // Determine how many bytes will be written // for this string. byte_count = bytes.len() as u64; // Make sure the buffer has enough space for this string. assert!(buffer.len() as u64 >= byte_count + U64_BYTES as u64); // Add the count to the buffer. BigEndian::u64_to_bytes(&mut buffer[0..U64_BYTES], byte_count); // Add each byte of the string to the buffer. for (i, byte) in bytes.iter().enumerate() { buffer[U64_BYTES + i] = byte.clone(); } } } impl Converter 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]) -> usize { let mut out: [u8; 8]; let ptr_out: *mut u8; assert!(buffer.len() >= 1 && buffer.len() <= 8); out = [0u8; 8]; ptr_out = out.as_mut_ptr(); unsafe { copy_nonoverlapping::(buffer.as_ptr(), ptr_out, buffer.len()); (*(ptr_out as *const u64)).to_le() as usize } } fn u16_to_bytes(buffer: &mut [u8], num: u16) { write_bytes!(buffer, u16, U16_BYTES, num, to_le); } fn u32_to_bytes(buffer: &mut [u8], num: u32) { write_bytes!(buffer, u32, U32_BYTES, num, to_le); } fn u64_to_bytes(buffer: &mut [u8], num: u64) { write_bytes!(buffer, u64, U64_BYTES, num, to_le); } fn usize_to_bytes(buffer: &mut [u8], num: usize) { let bytes: [u8; 8]; let num_bytes: u8; num_bytes = buffer.len() as u8; assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8); assert!(buffer.len() >= 1 && buffer.len() <= 8); unsafe { bytes = mem::transmute::(num.to_le()); copy_nonoverlapping::(bytes.as_ptr(), buffer.as_mut_ptr(), num_bytes as usize); } } fn bytes_to_string(buffer: &[u8]) -> String { let byte_count: u64; let new_string: String; // A string array should have atleast a u64 size byte count. assert!(buffer.len() >= U64_BYTES); // Strings start with the size of bytes to read as // a u64. So read that in and then we know how many // bytes make up the string. byte_count = BigEndian::bytes_to_u64(buffer); if byte_count > 0 { match String::from_utf8(buffer[U64_BYTES..(buffer.len()-1)].to_vec()) { Ok(string) => { new_string = string; } Err(error) => { error!("{}", error); } } } else { new_string = String::new(); } new_string } fn string_to_bytes(buffer: &mut [u8], string: String) { let bytes: &[u8]; let byte_count: u64; // Turn the string into a byte array. bytes = string.as_bytes(); // Determine how many bytes will be written // for this string. byte_count = bytes.len() as u64 + U64_BYTES as u64; // Make sure the buffer has enough space for this string. assert!(buffer.len() as u64 >= byte_count); // Add the count to the buffer. LittleEndian::u64_to_bytes(&mut buffer[0..U64_BYTES], byte_count); // Add each byte of the string to the buffer. for (i, byte) in bytes.iter().enumerate() { buffer[U64_BYTES + i] = byte.clone(); } } } /// 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 } }