diff --git a/src/endian.rs b/src/endian.rs new file mode 100644 index 0000000..fbeae5d --- /dev/null +++ b/src/endian.rs @@ -0,0 +1,245 @@ +use std::mem; +use std::ptr::copy_nonoverlapping; + +use super::transmutable::Transmutable; + + +/// Handles serialization where the most +/// significant byte is stored at the lowest address. +pub struct BigEndian; + +/// Handles serialization where the most +/// significant byte is stored at the lowest address. +pub struct LittleEndian; + +/// 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 reading bytes from a given buffer +/// and turning them into the requested type. +macro_rules! read_bytes +{ + ($buffer: expr, $return_type: ident, $convert_func: ident) => + ({ + use std::$return_type; + + assert!($return_type::BYTES <= $buffer.len()); + unsafe + { + (*($buffer.as_ptr() as *const $return_type)).$convert_func() + } + }) +} + +/// Handles turning a given number into bytes +/// and writing them to a buffer. +macro_rules! write_bytes +{ + ($buffer: expr, $value_type: ident, $num: expr, $convert_func: ident) => + ({ + use std::$value_type; + + assert!($value_type::BYTES <= $buffer.len()); + unsafe + { + let size: usize; + let bytes: [u8; $value_type::BYTES]; + + size = $value_type::BYTES as usize; + + bytes = + mem::transmute::<_,[u8; $value_type::BYTES]>($num.$convert_func()); + copy_nonoverlapping((&bytes).as_ptr(), $buffer.as_mut_ptr(), size); + } + }) +} + + + +impl Transmutable 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], num_bytes: u8) -> usize + { + let mut out: [u8; 8]; + let ptr_out: *mut u8; + + assert!(1 <= num_bytes && num_bytes <= 8); + assert!(num_bytes as usize <= buffer.len()); + + out = [0u8; 8]; + ptr_out = out.as_mut_ptr(); + unsafe + { + copy_nonoverlapping(buffer.as_ptr(), + ptr_out.offset((8 - num_bytes) as isize), + num_bytes as usize); + + (*(ptr_out as *const u64)).to_be() as usize + } + } + + + fn u16_to_bytes(buffer: &mut [u8], num: u16) + { + write_bytes!(buffer, u16, num, to_be); + } + + fn u32_to_bytes(buffer: &mut [u8], num: u32) + { + write_bytes!(buffer, u32, num, to_be); + } + + fn u64_to_bytes(buffer: &mut [u8], num: u64) + { + write_bytes!(buffer, u64, num, to_be); + } + + fn usize_to_bytes(buffer: &mut [u8], num: usize, num_bytes: u8) + { + let bytes: [u8; 8]; + + assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8); + assert!(num_bytes as usize <= buffer.len()); + 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); + } + } +} + +impl Transmutable 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], num_bytes: u8) -> usize + { + let mut out: [u8; 8]; + let ptr_out: *mut u8; + + assert!(1 <= num_bytes && num_bytes <= 8); + assert!(num_bytes as usize <= buffer.len()); + + out = [0u8; 8]; + ptr_out = out.as_mut_ptr(); + unsafe + { + copy_nonoverlapping(buffer.as_ptr(), ptr_out, num_bytes as usize); + (*(ptr_out as *const u64)).to_le() as usize + } + } + + + fn u16_to_bytes(buffer: &mut [u8], num: u16) + { + write_bytes!(buffer, u16, num, to_le); + } + + fn u32_to_bytes(buffer: &mut [u8], num: u32) + { + write_bytes!(buffer, u32, num, to_le); + } + + fn u64_to_bytes(buffer: &mut [u8], num: u64) + { + write_bytes!(buffer, u64, num, to_le); + } + + fn usize_to_bytes(buffer: &mut [u8], num: usize, num_bytes: u8) + { + let bytes: [u8; 8]; + + assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8); + assert!(num_bytes as usize <= buffer.len()); + unsafe + { + + bytes = mem::transmute::(num.to_le()); + copy_nonoverlapping(bytes.as_ptr(), buffer.as_mut_ptr(), + num_bytes as usize); + } + } +} + + + +/// 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 + } +} diff --git a/src/lib.rs b/src/lib.rs index a93251b..f2ef538 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,12 @@ -#[test] -fn it_works() { -} +#![feature(num_bits_bytes)] + +extern crate sigils; + + + +mod transmutable; +mod endian; + + +pub use ::transmutable::Transmutable; +pub use ::endian::{BigEndian, LittleEndian, PlatformEndian}; diff --git a/src/transmutable.rs b/src/transmutable.rs new file mode 100644 index 0000000..e3ac467 --- /dev/null +++ b/src/transmutable.rs @@ -0,0 +1,260 @@ +use std::mem; + + +/// Describes types that can transmute Numbers into bytes, +/// or bytes into Numbers. This means that they can also +/// transmute higher order mathematic types like Vectors, +/// Quaternions, Matrices, and such. +pub trait Transmutable +{ + /// Converts an array of bytes to a signed 16-bit integer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough information to convert. + fn bytes_to_i16(buffer: &[u8]) -> i16 + { + Self::bytes_to_u16(buffer) as i16 + } + + /// Converts an array of bytes to a signed 32-bit integer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough information to convert. + fn bytes_to_i32(buffer: &[u8]) -> i32 + { + Self::bytes_to_u32(buffer) as i32 + } + + /// Converts an array of bytes to a signed 64-bit integer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough information to convert. + fn bytes_to_i64(buffer: &[u8]) -> i64 + { + Self::bytes_to_u64(buffer) as i64 + } + + /// Converts an array of bytes to a signed integer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough information to convert. + /// + /// This will panic if the number of bytes + /// passed in is less than one or more than eight. + fn bytes_to_isize(buffer: &[u8], num_bytes: u8) -> isize + { + let temp_num: u64; + + assert!(num_bytes > 1 && num_bytes < 8); + assert!(buffer.len() < (num_bytes as usize)); + + temp_num = Self::bytes_to_usize(buffer, num_bytes) as u64; + add_sign(temp_num, num_bytes) as isize + } + + /// Converts an array of bytes to a 32-bit floating point number. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough information to convert. + fn bytes_to_f32(buffer: &[u8]) -> f32 + { + unsafe + { + mem::transmute::(Self::bytes_to_u32(buffer)) + } + } + + /// Converts an array of bytes to a 64-bit floating point number. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough information to convert. + fn bytes_to_f64(buffer: &[u8]) -> f64 + { + unsafe + { + mem::transmute::(Self::bytes_to_u64(buffer)) + } + } + + + /// Converts a signed 16-bit integer to bytes + /// and places them into the given buffer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough space to store the converted value. + fn i16_to_bytes(buffer: &mut [u8], num: i16) + { + Self::u16_to_bytes(buffer, num as u16) + } + + /// Converts a signed 32-bit integer to bytes + /// and places them into the given buffer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough space to store the converted value. + fn i32_to_bytes(buffer: &mut [u8], num: i32) + { + Self::u32_to_bytes(buffer, num as u32) + } + + /// Converts a signed 64-bit integer to bytes + /// and places them into the given buffer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough space to store the converted value. + fn i64_to_bytes(buffer: &mut [u8], num: i64) + { + Self::u64_to_bytes(buffer, num as u64) + } + + /// Converts a signed integer to bytes + /// and places them into the given buffer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough space to store the converted value. + /// + /// This will panic if the number of bytes + /// passed in is less than the byte size of the given number + /// or more than eight. + fn isize_to_bytes(buffer: &mut [u8], num: isize, num_bytes: u8) + { + let temp_num: usize; + + assert!(num_bytes > 1 && num_bytes < 8); + assert!(buffer.len() < (num_bytes as usize)); + + temp_num = remove_sign(num as i64, num_bytes) as usize; + Self::usize_to_bytes(buffer, temp_num, num_bytes) + } + + /// Converts a 32-bit floating point number to bytes + /// and places them into the given buffer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough space to store the converted value. + fn f32_to_bytes(buffer: &mut [u8], num: f32) + { + unsafe + { + Self::u32_to_bytes(buffer, mem::transmute::(num)); + } + } + + /// Converts a 64-bit floating point number to bytes + /// and places them into the given buffer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough space to store the converted value. + fn f64_to_bytes(buffer: &mut [u8], num: f64) + { + unsafe + { + Self::u64_to_bytes(buffer, mem::transmute::(num)); + } + } + + + + /// Converts an array of bytes to an unsigned 16-bit integer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough information to convert. + fn bytes_to_u16(buffer: &[u8]) -> u16; + + /// Converts an array of bytes to an unsigned 32-bit integer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough information to convert. + fn bytes_to_u32(buffer: &[u8]) -> u32; + + /// Converts an array of bytes to an unsigned 64-bit integer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough information to convert. + fn bytes_to_u64(buffer: &[u8]) -> u64; + + /// Converts an array of bytes to an unsigned integer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough information to convert. + /// + /// This will panic if the number of bytes + /// passed in is less than one or more than eight. + fn bytes_to_usize(buffer: &[u8], num_bytes: u8) -> usize; + + + /// Converts an unsigned 16-bit integer to bytes + /// and places them into the given buffer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough space to store the converted value. + fn u16_to_bytes(buffer: &mut [u8], num: u16); + + /// Converts an unsigned 32-bit integer to bytes + /// and places them into the given buffer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough space to store the converted value. + fn u32_to_bytes(buffer: &mut [u8], num: u32); + + /// Converts an unsigned 64-bit integer to bytes + /// and places them into the given buffer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough space to store the converted value. + fn u64_to_bytes(buffer: &mut [u8], num: u64); + + /// Converts an unsigned integer to bytes + /// and places them into the given buffer. + /// + /// # Panics + /// This will panic if the buffer does not have + /// enough space to store the converted value. + /// + /// This will panic if the number of bytes + /// passed in is less than the byte size of the given number + /// or more than eight. + fn usize_to_bytes(buffer: &mut [u8], num: usize, num_bytes: u8); +} + + +/// Switches an unsigned value into its signed equivalent. +/// +/// NOTE: This seems messy for larger unsigned values. +fn add_sign(val: u64, num_bytes: u8) -> i64 +{ + let shift: u8; + + shift = (8 - num_bytes) * 8; + (val << shift) as i64 >> shift +} + +/// Switches a signed value into its unsigned equivalent. +/// +/// NOTE: This seems messy for values under zero. +fn remove_sign(val: i64, num_bytes: u8) -> u64 +{ + let shift: u8; + + shift = (8 - num_bytes) * 8; + (val << shift) as u64 >> shift +}