use weave::attempt; use spellbook::components::Array; #[cfg(feature="convert_sigils")] use sigils::{Zero, Number, Real, Trig}; #[cfg(feature="convert_sigils")] use sigils::vector::{Vector, Vector2, Vector3, Vector4}; #[cfg(feature="convert_sigils")] use sigils::quaternion::Quaternion; use crate::byte_sized::{ByteSized, get_byte_size_of_string}; use crate::conversion_error::ConversionError; use crate::converter::Converter; use crate::endian::{BigEndian, LittleEndian, PlatformEndian, NetworkEndian}; use crate::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]) -> Result { 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) -> Result; /// Transmute this type to an array of bytes in /// the Platform's endian. fn to_bytes(self) -> Array { 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) -> Array { self.as_endian_bytes(endianess) } /// Transmute this type to an array of bytes in /// the Platform's endian. fn as_bytes(&self) -> Array { 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) -> Array; /// 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) -> Result { // Just return the byte from the buffer. // A single byte has no endian form. check_length!(buffer >= u8::BYTES); Ok(buffer[0]) } #[allow(unused_variables)] fn as_endian_bytes(&self, endianess: Endianess) -> Array { let mut bytes: Array; bytes = Array::with_capacity(1usize); bytes.insert_element(*self); bytes } fn determine_byte_size(&self) -> usize { u8::BYTES } } impl Transmutable for u16 { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Result { // 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) -> Array { // 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) -> Result { // 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) -> Array { // 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) -> Result { // 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) -> Array { // 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) -> Result { // 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) -> Array { // 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) -> Result { check_length!(buffer >= i8::BYTES); Ok(buffer[0] as i8) } #[allow(unused_variables)] fn as_endian_bytes(&self, endianess: Endianess) -> Array { let mut bytes: Array; bytes = Array::with_capacity(1usize); bytes.insert_element(*self as u8); bytes } fn determine_byte_size(&self) -> usize { i8::BYTES } } impl Transmutable for i16 { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Result { // 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) -> Array { // 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) -> Result { // 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) -> Array { // 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) -> Result { // 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) -> Array { // 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) -> Result { // 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) -> Array { // 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) -> Result { // 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) -> Array { // 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) -> Result { // 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) -> Array { // 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) -> Result { // 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) -> Array { // 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 Vector2 where T: Number + ByteSized + Transmutable { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Result { let num_bytes: usize; let mut vec: Vector2; // Determine the number of bytes requires to // represent a Vector2. vec = Vector2::::zero(); num_bytes = vec.determine_byte_size(); // Make sure that there is enough data to read // the bytes for this type. check_length!(buffer >= num_bytes); // Convert the given bytes to this type and return it. vec.x = attempt!(T::from_endian_bytes(&buffer[0..T::BYTES], endianess)); vec.y = attempt!(T::from_endian_bytes(&buffer[T::BYTES..num_bytes], endianess)); Ok(vec) } fn as_endian_bytes(&self, endianess: Endianess) -> Array { let num_bytes: usize; let mut buffer: Array; // Determine the number of bytes requires to // represent a Vector2. num_bytes = T::BYTES * self.get_size() as usize; // Make sure that there is enough space to store // the bytes from this type. buffer = Array::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::BYTES * self.get_size() as usize } } #[cfg(feature="convert_sigils")] impl Transmutable for Vector3 where T: Number + ByteSized + Transmutable { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Result { let num_bytes: usize; let mut vec: Vector3; // Determine the number of bytes requires to // represent a Vector3. vec = Vector3::::zero(); num_bytes = vec.determine_byte_size(); check_length!(buffer >= num_bytes); // Convert the given bytes to this type and return it. vec.x = attempt!(T::from_endian_bytes(&buffer[0..T::BYTES], endianess)); vec.y = attempt!(T::from_endian_bytes(&buffer[T::BYTES..(T::BYTES * 2)], endianess)); vec.z = attempt!(T::from_endian_bytes(&buffer[(T::BYTES * 2)..num_bytes], endianess)); Ok(vec) } fn as_endian_bytes(&self, endianess: Endianess) -> Array { let num_bytes: usize; let mut buffer: Array; // Determine the number of bytes requires to // represent a Vector3. num_bytes = T::BYTES * self.get_size() as usize; // Make sure that there is enough space to store // the bytes from this type. buffer = Array::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::BYTES * self.get_size() as usize } } #[cfg(feature="convert_sigils")] impl Transmutable for Vector4 where T: Number + ByteSized + Transmutable { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Result { let num_bytes: usize; let mut vec: Vector4; // Determine the number of bytes requires to // represent a Vector4. vec = Vector4::::zero(); num_bytes = vec.determine_byte_size(); check_length!(buffer >= num_bytes); // Convert the given bytes to this type and return it. vec.x = attempt!(T::from_endian_bytes(&buffer[0..T::BYTES], endianess)); vec.y = attempt!(T::from_endian_bytes(&buffer[T::BYTES..(T::BYTES * 2)], endianess)); vec.z = attempt!(T::from_endian_bytes(&buffer[(T::BYTES*2)..(T::BYTES*3)], endianess)); vec.w = attempt!(T::from_endian_bytes(&buffer[(T::BYTES * 3)..num_bytes], endianess)); Ok(vec) } fn as_endian_bytes(&self, endianess: Endianess) -> Array { let num_bytes: usize; let mut buffer: Array; // Determine the number of bytes requires to // represent a Vector4. num_bytes = T::BYTES * self.get_size() as usize; // Make sure that there is enough space to store // the bytes from this type. buffer = Array::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::BYTES * self.get_size() as usize } } #[cfg(feature="convert_sigils")] impl Transmutable for Quaternion where T: Real + Trig + ByteSized + Transmutable { fn from_endian_bytes(buffer: &[u8], endianess: Endianess) -> Result { let num_bytes: usize; let mut quat: Quaternion; // Determine the number of bytes requires to // represent a Quaternion. quat = Quaternion::::zero(); num_bytes = quat.determine_byte_size(); // Make sure that there is enough data to read // the bytes for this type. check_length!(buffer >= num_bytes); // Convert the given bytes to this type and return it. quat.scalar = attempt!(T::from_endian_bytes(&buffer[0..T::BYTES], endianess)); quat.vector = attempt!(Vector3::::from_endian_bytes(&buffer[T::BYTES..num_bytes], endianess)); Ok(quat) } fn as_endian_bytes(&self, endianess: Endianess) -> Array { let num_bytes: usize; let mut buffer: Array; // Determine the number of bytes requires to // represent a Quaternion. num_bytes = T::BYTES * 4usize; // Make sure that there is enough space to store // the bytes from this type. buffer = Array::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::BYTES * 4usize } }