The library can now convert numbers to and from bytes.

Numbers can be converted to and from bytes in both
BigEndian and LittleEndian styles. This does not yet take care of
the other mathematical structures provided by Sigil.

Also, no tests of these capabilities have been written yet.
This commit is contained in:
Jason Travis Smith 2015-12-30 17:06:48 -05:00
parent fee27b18a3
commit 039c093b92
3 changed files with 517 additions and 3 deletions

245
src/endian.rs Normal file
View File

@ -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::<usize, [u8; 8]>(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::<usize, [u8; 8]>(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
}
}

View File

@ -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};

260
src/transmutable.rs Normal file
View File

@ -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::<u32, f32>(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::<u64, f64>(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::<f32, u32>(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::<f64, u64>(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
}