use ::byte_sized::ByteSized; use ::byte_sized::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(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)] 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 { // Make sure that there is enough space to read // a value from the buffer. assert!(buffer.len() == u16::BYTES); pack_big_endian!(buffer, u16, u16::BYTES) } fn bytes_to_u32(buffer: &[u8]) -> u32 { // Make sure that there is enough space to read // a value from the buffer. assert!(buffer.len() == u32::BYTES); pack_big_endian!(buffer, u32, u32::BYTES) } fn bytes_to_u64(buffer: &[u8]) -> u64 { // Make sure that there is enough space to read // a value from the buffer. assert!(buffer.len() == u64::BYTES); pack_big_endian!(buffer, u64, u64::BYTES) } fn bytes_to_usize(buffer: &[u8]) -> usize { // Make sure that there is enough space to read // a value from the buffer. assert!(buffer.len() == usize::BYTES); pack_big_endian!(buffer, usize, usize::BYTES) } fn u16_to_bytes(num: u16) -> Vec { // Unpack the value into it's byte form. unpack_big_endian!(num, u16::BYTES) } fn u32_to_bytes(num: u32) -> Vec { // Unpack the value into it's byte form. unpack_big_endian!(num, u32::BYTES) } fn u64_to_bytes(num: u64) -> Vec { // Unpack the value into it's byte form. unpack_big_endian!(num, u64::BYTES) } fn usize_to_bytes(num: usize) -> Vec { // Unpack the value into it's byte form. unpack_big_endian!(num, usize::BYTES) } 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]); 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 { // Make sure that there is enough space to read // a value from the buffer. assert!(buffer.len() == u16::BYTES); pack_little_endian!(buffer, u16, u16::BYTES) } fn bytes_to_u32(buffer: &[u8]) -> u32 { // Make sure that there is enough space to read // a value from the buffer. assert!(buffer.len() == u32::BYTES); pack_little_endian!(buffer, u32, u32::BYTES) } fn bytes_to_u64(buffer: &[u8]) -> u64 { // Make sure that there is enough space to read // a value from the buffer. assert!(buffer.len() == u64::BYTES); pack_little_endian!(buffer, u64, u64::BYTES) } fn bytes_to_usize(buffer: &[u8]) -> usize { // Make sure that there is enough space to read // a value from the buffer. assert!(buffer.len() == usize::BYTES); pack_little_endian!(buffer, usize, usize::BYTES) } fn u16_to_bytes(num: u16) -> Vec { // Unpack the value into it's byte form. unpack_little_endian!(num, u16::BYTES) } fn u32_to_bytes(num: u32) -> Vec { // Unpack the value into it's byte form. unpack_little_endian!(num, u32::BYTES) } fn u64_to_bytes(num: u64) -> Vec { // Unpack the value into it's byte form. unpack_little_endian!(num, u64::BYTES) } fn usize_to_bytes(num: usize) -> Vec { // Unpack the value into it's byte form. unpack_little_endian!(num, usize::BYTES) } 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 = LittleEndian::bytes_to_u64(&buffer[0..U64_BYTES]); 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 { // 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 { T::from_endian_bytes(val.as_bytes().as_slice(), Endianess::Network) } } /// Turns a Platform order value to a Network order value. pub fn platform_to_network_order(val: T) -> T where T: Transmutable { // 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 { T::from_endian_bytes(val.as_bytes().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 } }