use std::mem; use std::ptr::copy_nonoverlapping; use ::byte_sized::ByteSized; use ::byte_sized::{U16_BYTES, U32_BYTES, U64_BYTES}; use ::converter::Converter; use ::transmutable::Transmutable; /// 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; /// Defines the endianess to use when communicating /// over a network. This could be either /// of the available endians as long as it is consistent /// across the network. However, RFC1700 decided network /// byte order would be BigEndian. As such, it is now the /// common endian style for networking. pub type NetworkEndian = BigEndian; /// 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, /// Referes to NetworkEndian. This could be either /// of the available endians as long as it is consistent /// across the network. However, RFC1700 decided network /// byte order would be BigEndian. As such, it is now the /// common endian style for networking. Network } /// 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) => ({ unsafe { let bytes: [u8; $numBytes]; bytes = mem::transmute::<_, [u8; $numBytes]>($num.$convertFunc()); $buffer.extend_from_slice(&bytes); } }) } 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(num: u16) -> Vec { let mut buffer: Vec; // Create the Vector to hold the bytes // from this type. buffer = Vec::with_capacity(u16::BYTES); // Write the bytes to the Vector. write_bytes!(buffer, u16, U16_BYTES, num, to_be); // Return the byte buffer. buffer } fn u32_to_bytes(num: u32) -> Vec { let mut buffer: Vec; // Create the Vector to hold the bytes // from this type. buffer = Vec::with_capacity(u32::BYTES); // Write the bytes to the Vector. write_bytes!(buffer, u32, U32_BYTES, num, to_be); // Return the byte buffer. buffer } fn u64_to_bytes(num: u64) -> Vec { let mut buffer: Vec; // Create the Vector to hold the bytes // from this type. buffer = Vec::with_capacity(u64::BYTES); // Write the bytes to the Vector. write_bytes!(buffer, u64, U64_BYTES, num, to_be); // Return the byte buffer. buffer } fn usize_to_bytes(num: usize) -> Vec { let bytes: [u8; 8]; let num_bytes: u8; let mut buffer: Vec; num_bytes = usize::BYTES as u8; // Create a buffer with enough space for this type. buffer = Vec::with_capacity(usize::BYTES); assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8); unsafe { bytes = mem::transmute::(num.to_be()); buffer.extend_from_slice(&bytes); //copy_nonoverlapping::( // bytes.as_ptr().offset((8 - num_bytes) as isize), // buffer.as_mut_ptr(), num_bytes as usize); } // Return the byte buffer. buffer } 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[0..U64_BYTES-1]); 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(string: String) -> Vec { let bytes: &[u8]; let byte_count: u64; let mut buffer: Vec; // 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. buffer = Vec::with_capacity(bytes.len() + U64_BYTES); // Add the count to the buffer. buffer.append(&mut BigEndian::u64_to_bytes(byte_count)); // Add each byte of the string to the buffer. buffer.extend_from_slice(bytes); // Return the byte buffer. buffer } } 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(num: u16) -> Vec { let mut buffer: Vec; // Create the Vector to hold the bytes // from this type. buffer = Vec::with_capacity(u16::BYTES); // Write the bytes to the Vector. write_bytes!(buffer, u16, U16_BYTES, num, to_le); // Return the byte buffer. buffer } fn u32_to_bytes(num: u32) -> Vec { let mut buffer: Vec; // Create the Vector to hold the bytes // from this type. buffer = Vec::with_capacity(u32::BYTES); // Write the bytes to the Vector. write_bytes!(buffer, u32, U32_BYTES, num, to_le); // Return the byte buffer. buffer } fn u64_to_bytes(num: u64) -> Vec { let mut buffer: Vec; // Create the Vector to hold the bytes // from this type. buffer = Vec::with_capacity(u64::BYTES); // Write the bytes to the Vector. write_bytes!(buffer, u64, U64_BYTES, num, to_le); // Return the byte buffer. buffer } fn usize_to_bytes(num: usize) -> Vec { let bytes: [u8; 8]; let num_bytes: u8; let mut buffer: Vec; num_bytes = usize::BYTES as u8; // Create a buffer with enough space for this type. buffer = Vec::with_capacity(usize::BYTES); assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8); unsafe { bytes = mem::transmute::(num.to_le()); buffer.extend_from_slice(&bytes); //copy_nonoverlapping::(bytes.as_ptr(), buffer.as_mut_ptr(), // num_bytes as usize); } // Return the byte buffer. buffer } 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(string: String) -> Vec { let bytes: &[u8]; let byte_count: u64; let mut buffer: Vec; // 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. buffer = Vec::with_capacity(bytes.len() + U64_BYTES); // Add the count to the buffer. buffer.append(&mut LittleEndian::u64_to_bytes(byte_count)); // Add each byte of the string to the buffer. buffer.extend_from_slice(bytes); // Return the byte buffer. buffer } } impl ::std::fmt::Debug for Endianess { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { ::std::fmt::Display::fmt(self, f) } } impl ::std::fmt::Display for Endianess { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { match *self { Endianess::Big => { write!(f, "Big Endian") } Endianess::Little => { write!(f, "Little Endian") } Endianess::Network => { write!(f, "Network Endian") } Endianess::Platform => { write!(f, "Big Endian") } } } } /// Turns a Network order value to a Platform order value. pub fn network_to_platform_order(val: T) -> T where T: Transmutable { let buffer: Vec; // Determine what endianess the Platform is using. if cfg!(target_endian="big") { // Network endianess is Big endian, so they are the same. // Just return the value. val } else { // Convert the value from Big endian to Little endian. buffer = val.to_bytes(Endianess::Network); T::from_bytes(buffer.as_slice(), Endianess::Platform) } } /// Turns a Platform order value to a Network order value. pub fn platform_to_network_order(val: T) -> T where T: Transmutable { let buffer: Vec; // Determine what endianess the Platform is using. if cfg!(target_endian="big") { // Network endianess is Big endian, so they are the same. // Just return the value. val } else { // Convert the value from Little endian to Big endian. buffer = val.to_bytes(Endianess::Platform); T::from_bytes(buffer.as_slice(), Endianess::Network) } } /// Returns the Endianess used for network transmission. pub fn get_network_endianess() -> Endianess { Endianess::Big } /// Returns the Endianess of the current platform. pub fn get_platform_endianess() -> Endianess { if cfg!(target_endian="big") { Endianess::Big } else { Endianess::Little } } /// 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 } }