use spellbook::components::DynamicArray; #[cfg(feature="convert_sigils")] use sigils::{Zero, Number, Real}; #[cfg(feature="convert_sigils")] use sigils::vector::{DynamicArraytor, DynamicArraytor2, DynamicArraytor3, DynamicArraytor4}; #[cfg(feature="convert_sigils")] use sigils::quaternion::Quaternion; use ::byte_sized::{ByteSized, get_byte_size_of_string}; use ::converter::Converter; use ::endian::{BigEndian, LittleEndian, PlatformEndian, NetworkEndian}; use ::endian::Endianess; // From and Into are not used because we need to also // know the endianess to use for converting. /// A type that can be converted to and from bytes. pub trait Transmutable: Sized { /// Transmute an array of bytes in the /// platform's endian to this type. fn from_bytes(buffer: &[u8]) -> Self { Self::from_endian_bytes(buffer, Endianess::Platform) } /// Transmute an array of bytes in the /// given endian to this type. fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self; /// Transmute this type to an array of bytes in /// the Platform's endian. fn to_bytes(self) -> DynamicArray { self.as_endian_bytes(Endianess::Platform) } /// Transmute this type to an array of bytes in /// the desired endian. fn to_endian_bytes(self, endianess: Endianess) -> DynamicArray { self.as_endian_bytes(endianess) } /// Transmute this type to an array of bytes in /// the Platform's endian. fn as_bytes(&self) -> DynamicArray { self.as_endian_bytes(Endianess::Platform) } /// Transmute this type to an array of bytes in /// the desired endian. fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray; /// Get the current size of this Transmutable in bytes. fn determine_byte_size(&self) -> usize; } /// Handles the repetative endianess matching /// for the primitive number types when converting /// a number to bytes. macro_rules! handle_endianess_to_bytes { ($val: ident, $endianess: ident, $func: ident) => { { match $endianess { Endianess::Big => { BigEndian::$func(*$val) } Endianess::Little => { LittleEndian::$func(*$val) } Endianess::Platform => { PlatformEndian::$func(*$val) } Endianess::Network => { NetworkEndian::$func(*$val) } } } } } /// Handles the repetative endianess matching /// for the primitive number types when converting /// a number from bytes. macro_rules! handle_endianess_from_bytes { ($buffer: ident, $endianess: ident, $func: ident) => { match $endianess { Endianess::Big => { BigEndian::$func(&$buffer) } Endianess::Little => { LittleEndian::$func(&$buffer) } Endianess::Platform => { PlatformEndian::$func(&$buffer) } Endianess::Network => { NetworkEndian::$func(&$buffer) } } } } impl Transmutable for u8 { #[allow(unused_variables)] fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= u8::BYTES); // Just return the byte from the buffer. // A single byte has no endian form. buffer[0] } #[allow(unused_variables)] fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // A single byte has no endian form. vec![*self] } fn determine_byte_size(&self) -> usize { u8::BYTES } } impl Transmutable for u16 { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= u16::BYTES); // Convert the given bytes to this type and return it. handle_endianess_from_bytes!(buffer, endianess, bytes_to_u16) } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // Return the Endianess conversion. handle_endianess_to_bytes!(self, endianess, u16_to_bytes) } fn determine_byte_size(&self) -> usize { u16::BYTES } } impl Transmutable for u32 { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= u32::BYTES); // Convert the given bytes to this type and return it. handle_endianess_from_bytes!(buffer, endianess, bytes_to_u32) } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // Convert this to bytes and add it to the buffer. handle_endianess_to_bytes!(self, endianess, u32_to_bytes) } fn determine_byte_size(&self) -> usize { u32::BYTES } } impl Transmutable for u64 { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= u64::BYTES); // Convert the given bytes to this type and return it. handle_endianess_from_bytes!(buffer, endianess, bytes_to_u64) } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // Convert this to bytes and add it to the buffer. handle_endianess_to_bytes!(self, endianess, u64_to_bytes) } fn determine_byte_size(&self) -> usize { u64::BYTES } } impl Transmutable for usize { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= usize::BYTES); // Convert the given bytes to this type and return it. handle_endianess_from_bytes!(buffer, endianess, bytes_to_usize) } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // Convert this to bytes and add it to the buffer. handle_endianess_to_bytes!(self, endianess, usize_to_bytes) } fn determine_byte_size(&self) -> usize { usize::BYTES } } impl Transmutable for i8 { #[allow(unused_variables)] fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= i8::BYTES); buffer[0] as i8 } #[allow(unused_variables)] fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { vec![*self as u8] } fn determine_byte_size(&self) -> usize { i8::BYTES } } impl Transmutable for i16 { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= i16::BYTES); // Convert the given bytes to this type and return it. handle_endianess_from_bytes!(buffer, endianess, bytes_to_i16) } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // Convert this to bytes and add it to the buffer. handle_endianess_to_bytes!(self, endianess, i16_to_bytes) } fn determine_byte_size(&self) -> usize { i16::BYTES } } impl Transmutable for i32 { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= i32::BYTES); // Convert the given bytes to this type and return it. handle_endianess_from_bytes!(buffer, endianess, bytes_to_i32) } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // Convert this to bytes and add it to the buffer. handle_endianess_to_bytes!(self, endianess, i32_to_bytes) } fn determine_byte_size(&self) -> usize { i32::BYTES } } impl Transmutable for i64 { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= i64::BYTES); // Convert the given bytes to this type and return it. handle_endianess_from_bytes!(buffer, endianess, bytes_to_i64) } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // Convert this to bytes and add it to the buffer. handle_endianess_to_bytes!(self, endianess, i64_to_bytes) } fn determine_byte_size(&self) -> usize { i64::BYTES } } impl Transmutable for isize { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= isize::BYTES); // Convert the given bytes to this type and return it. handle_endianess_from_bytes!(buffer, endianess, bytes_to_isize) } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // Convert this to bytes and add it to the buffer. handle_endianess_to_bytes!(self, endianess, isize_to_bytes) } fn determine_byte_size(&self) -> usize { isize::BYTES } } impl Transmutable for f32 { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= f32::BYTES); // Convert the given bytes to this type and return it. handle_endianess_from_bytes!(buffer, endianess, bytes_to_f32) } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // Convert this to bytes and add it to the buffer. handle_endianess_to_bytes!(self, endianess, f32_to_bytes) } fn determine_byte_size(&self) -> usize { f32::BYTES } } impl Transmutable for f64 { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= f64::BYTES); // Convert the given bytes to this type and return it. handle_endianess_from_bytes!(buffer, endianess, bytes_to_f64) } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // Convert this to bytes and add it to the buffer. handle_endianess_to_bytes!(self, endianess, f64_to_bytes) } fn determine_byte_size(&self) -> usize { f64::BYTES } } impl Transmutable for String { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { // Convert the given bytes to this type and return it. handle_endianess_from_bytes!(buffer, endianess, bytes_to_string) } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { // Convert this to bytes and add it to the buffer. // We are not using the macro because *String is a str. match endianess { Endianess::Big => { BigEndian::string_to_bytes(self.clone()) } Endianess::Little => { LittleEndian::string_to_bytes(self.clone()) } Endianess::Platform => { PlatformEndian::string_to_bytes(self.clone()) } Endianess::Network => { NetworkEndian::string_to_bytes(self.clone()) } } } fn determine_byte_size(&self) -> usize { get_byte_size_of_string(self) } } #[cfg(feature="convert_sigils")] impl Transmutable for DynamicArraytor2 where T: Number + ByteSized + Transmutable { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { let byte_size: usize; let num_bytes: usize; let mut vec: DynamicArraytor2; // Determine the number of bytes requires to // represent a DynamicArraytor2. vec = DynamicArraytor2::::zero(); byte_size = T::get_byte_size(); num_bytes = byte_size * vec.get_size() as usize; // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= num_bytes); // Convert the given bytes to this type and return it. vec.x = T::from_endian_bytes(&buffer[0..byte_size], endianess); vec.y = T::from_endian_bytes(&buffer[byte_size..num_bytes], endianess); vec } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { let byte_size: usize; let num_bytes: usize; let mut buffer: DynamicArray; // Determine the number of bytes requires to // represent a DynamicArraytor2. byte_size = T::get_byte_size(); num_bytes = byte_size * self.get_size() as usize; // Make sure that there is enough space to store // the bytes from this type. buffer = DynamicArray::with_capacity(num_bytes); // Convert this to bytes and add it to the buffer. buffer.append(&mut self.x.as_endian_bytes(endianess)); buffer.append(&mut self.y.as_endian_bytes(endianess)); // Return the byte buffer. buffer } fn determine_byte_size(&self) -> usize { T::get_byte_size() * self.get_size() as usize } } #[cfg(feature="convert_sigils")] impl Transmutable for DynamicArraytor3 where T: Number + ByteSized + Transmutable { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { let byte_size: usize; let num_bytes: usize; let mut vec: DynamicArraytor3; // Determine the number of bytes requires to // represent a DynamicArraytor3. vec = DynamicArraytor3::::zero(); byte_size = T::get_byte_size(); num_bytes = byte_size * vec.get_size() as usize; // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= num_bytes); // Convert the given bytes to this type and return it. vec.x = T::from_endian_bytes(&buffer[0..byte_size], endianess); vec.y = T::from_endian_bytes(&buffer[byte_size..(byte_size*2)], endianess); vec.z = T::from_endian_bytes(&buffer[(byte_size*2)..num_bytes], endianess); vec } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { let byte_size: usize; let num_bytes: usize; let mut buffer: DynamicArray; // Determine the number of bytes requires to // represent a DynamicArraytor3. byte_size = T::get_byte_size(); num_bytes = byte_size * self.get_size() as usize; // Make sure that there is enough space to store // the bytes from this type. buffer = DynamicArray::with_capacity(num_bytes); // Convert this to bytes and add it to the buffer. buffer.append(&mut self.x.as_endian_bytes(endianess)); buffer.append(&mut self.y.as_endian_bytes(endianess)); buffer.append(&mut self.z.as_endian_bytes(endianess)); // Return the byte buffer. buffer } fn determine_byte_size(&self) -> usize { T::get_byte_size() * self.get_size() as usize } } #[cfg(feature="convert_sigils")] impl Transmutable for DynamicArraytor4 where T: Number + ByteSized + Transmutable { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { let byte_size: usize; let num_bytes: usize; let mut vec: DynamicArraytor4; // Determine the number of bytes requires to // represent a DynamicArraytor4. vec = DynamicArraytor4::::zero(); byte_size = T::get_byte_size(); num_bytes = byte_size * vec.get_size() as usize; // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= num_bytes); // Convert the given bytes to this type and return it. vec.x = T::from_endian_bytes(&buffer[0..byte_size], endianess); vec.y = T::from_endian_bytes(&buffer[byte_size..(byte_size*2)], endianess); vec.z = T::from_endian_bytes(&buffer[(byte_size*2)..(byte_size*3)], endianess); vec.w = T::from_endian_bytes(&buffer[(byte_size*3)..num_bytes], endianess); vec } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { let byte_size: usize; let num_bytes: usize; let mut buffer: DynamicArray; // Determine the number of bytes requires to // represent a DynamicArraytor4. byte_size = T::get_byte_size(); num_bytes = byte_size * self.get_size() as usize; // Make sure that there is enough space to store // the bytes from this type. buffer = DynamicArray::with_capacity(num_bytes); // Convert this to bytes and add it to the buffer. buffer.append(&mut self.x.as_endian_bytes(endianess)); buffer.append(&mut self.y.as_endian_bytes(endianess)); buffer.append(&mut self.z.as_endian_bytes(endianess)); buffer.append(&mut self.w.as_endian_bytes(endianess)); // Return the byte buffer. buffer } fn determine_byte_size(&self) -> usize { T::get_byte_size() * self.get_size() as usize } } #[cfg(feature="convert_sigils")] impl Transmutable for Quaternion where T: Real + ByteSized + Transmutable { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Self { let byte_size: usize; let num_bytes: usize; let mut quat: Quaternion; // Determine the number of bytes requires to // represent a Quaternion. quat = Quaternion::::zero(); byte_size = T::get_byte_size(); num_bytes = byte_size * 4usize; // Make sure that there is enough data to read // the bytes for this type. assert!(buffer.len() >= num_bytes); // Convert the given bytes to this type and return it. quat.scalar = T::from_endian_bytes(&buffer[0..byte_size], endianess); quat.vector = DynamicArraytor3::::from_endian_bytes(&buffer[byte_size..num_bytes], endianess); quat } fn as_endian_bytes(&self, endianess: Endianess) -> DynamicArray { let byte_size: usize; let num_bytes: usize; let mut buffer: DynamicArray; // Determine the number of bytes requires to // represent a Quaternion. byte_size = T::get_byte_size(); num_bytes = byte_size * 4usize; // Make sure that there is enough space to store // the bytes from this type. buffer = DynamicArray::with_capacity(num_bytes); // Convert this to bytes and add it to the buffer. buffer.append(&mut self.scalar.as_endian_bytes(endianess)); buffer.append(&mut self.vector.as_endian_bytes(endianess)); // Return the byte buffer. buffer } fn determine_byte_size(&self) -> usize { T::get_byte_size() * 4usize } }