Fixed the conversion code to use macros I wrote.
The previous code was relying on the to_be and to_le functions from the standard library. These now rely on macros that I wrote to handle the bit packing and unpacking. These were macros and not functions because it is really hard to define the types and capabilities needed to turn them into general functions. As such, the macros should never be published publically and the Converters should be used for conversions. The Transmutable property should be used for serialization and internally the primitive types, Elements, all use the Converter functions and any other objects should use the Transmutable primitives to build their binary forms.
This commit is contained in:
parent
8988f9f9ae
commit
03e9484e52
@ -13,10 +13,12 @@ keywords = ["converter", "binary"]
|
||||
default = []
|
||||
convert_sigils = ["sigils"]
|
||||
|
||||
[dependencies]
|
||||
scribe = { git = "https://gitlab.com/CyberMages/scribe.git" }
|
||||
[dependencies.scribe]
|
||||
git = "https://gitlab.com/CyberMages/scribe.git"
|
||||
|
||||
sigils = { optional = true, git = "https://gitlab.com/CyberMages/sigils.git" }
|
||||
[dependencies.sigils]
|
||||
optional = true
|
||||
git = "https://gitlab.com/CyberMages/sigils.git"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { version = "*" }
|
||||
|
@ -1,9 +1,7 @@
|
||||
#![feature(convert)]
|
||||
|
||||
extern crate alchemy;
|
||||
|
||||
|
||||
use alchemy::F32_BYTES;
|
||||
|
||||
use alchemy::{Converter, Endianess, PlatformEndian, Transmutable};
|
||||
|
||||
|
||||
@ -47,12 +45,12 @@ pub fn use_transmutable()
|
||||
println!("Buffer starts as: {}", stringify_array(buffer.as_slice()));
|
||||
|
||||
// Convert the floating point number into an array of bytes.
|
||||
buffer = num.to_bytes(endianess);
|
||||
buffer = num.as_endian_bytes(endianess);
|
||||
|
||||
println!("Buffer contains: {}", stringify_array(buffer.as_slice()));
|
||||
|
||||
// Convert the array of bytes into a floating point number.
|
||||
final_num = f32::from_bytes(buffer.as_slice(), endianess);
|
||||
final_num = f32::from_endian_bytes(buffer.as_slice(), endianess);
|
||||
println!("The buffer converts back to: {}", final_num);
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ pub fn main()
|
||||
// Initialize the variables.
|
||||
quat = Quaternion::<f64>::from_values(6.29f64, 1.9f64, 8.5f64, 7.11f64);
|
||||
buffer = Vec::with_capacity(SIZE_OF_QUATERNION);
|
||||
endianess = Endianess::PLATFORM;
|
||||
endianess = Endianess::Platform;
|
||||
|
||||
println!("Transmuting a Quaternion:");
|
||||
|
||||
@ -74,11 +74,11 @@ pub fn main()
|
||||
println!("Buffer starts as: {}", stringify_array(buffer.as_slice()));
|
||||
|
||||
// Convert the Vector2 into an array of bytes.
|
||||
buffer = quat.to_bytes(endianess);
|
||||
buffer = quat.as_endian_bytes(endianess);
|
||||
|
||||
println!("Buffer contains: {}", stringify_array(buffer.as_slice()));
|
||||
|
||||
// Convert the array of bytes into a Vector2.
|
||||
final_quat = Quaternion::from_bytes(buffer.as_slice(), endianess);
|
||||
final_quat = Quaternion::from_endian_bytes(buffer.as_slice(), endianess);
|
||||
println!("The buffer converts back to: {}", final_quat);
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
#![feature(convert)]
|
||||
|
||||
extern crate alchemy;
|
||||
|
||||
|
||||
use alchemy::U16_BYTES;
|
||||
use alchemy::{Converter, Endianess, PlatformEndian, Transmutable};
|
||||
use alchemy::platform_to_network_order;
|
||||
|
||||
@ -48,12 +45,12 @@ pub fn use_transmutable()
|
||||
println!("Buffer starts as: {}", stringify_array(buffer.as_slice()));
|
||||
|
||||
// Convert the short point number into an array of bytes.
|
||||
buffer = num.to_bytes(endianess);
|
||||
buffer = num.as_endian_bytes(endianess);
|
||||
|
||||
println!("Buffer contains: {}", stringify_array(buffer.as_slice()));
|
||||
|
||||
// Convert the array of bytes into a short number.
|
||||
final_num = u16::from_bytes(buffer.as_slice(), endianess);
|
||||
final_num = u16::from_endian_bytes(buffer.as_slice(), endianess);
|
||||
println!("The buffer converts back to: {}", final_num);
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ pub fn main()
|
||||
// Initialize the variables.
|
||||
vec = Vector2::<u64>::new(629u64, 1985u64);
|
||||
buffer = Vec::with_capacity(SIZE_OF_VECTOR_2);
|
||||
endianess = Endianess::PLATFORM;
|
||||
endianess = Endianess::Platform;
|
||||
|
||||
println!("Transmuting a Vector2:");
|
||||
|
||||
@ -74,11 +74,11 @@ pub fn main()
|
||||
println!("Buffer starts as: {}", stringify_array(buffer.as_slice()));
|
||||
|
||||
// Convert the Vector2 into an array of bytes.
|
||||
buffer = vec.to_bytes(endianess);
|
||||
buffer = vec.as_endian_bytes(endianess);
|
||||
|
||||
println!("Buffer contains: {}", stringify_array(buffer.as_slice()));
|
||||
|
||||
// Convert the array of bytes into a Vector2.
|
||||
final_vec = Vector2::from_bytes(buffer.as_slice(), endianess);
|
||||
final_vec = Vector2::from_endian_bytes(buffer.as_slice(), endianess);
|
||||
println!("The buffer converts back to: {}", final_vec);
|
||||
}
|
||||
|
@ -254,6 +254,7 @@ pub trait Converter
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Switches an unsigned value into its signed equivalent.
|
||||
///
|
||||
/// NOTE: This seems messy for larger unsigned values.
|
||||
|
253
src/endian.rs
253
src/endian.rs
@ -1,8 +1,5 @@
|
||||
use std::mem;
|
||||
use std::ptr::copy_nonoverlapping;
|
||||
|
||||
use ::byte_sized::ByteSized;
|
||||
use ::byte_sized::{U16_BYTES, U32_BYTES, U64_BYTES};
|
||||
use ::byte_sized::U64_BYTES;
|
||||
use ::converter::Converter;
|
||||
use ::transmutable::Transmutable;
|
||||
|
||||
@ -112,108 +109,63 @@ impl Converter for BigEndian
|
||||
{
|
||||
fn bytes_to_u16(buffer: &[u8]) -> u16
|
||||
{
|
||||
read_bytes!(buffer, u16, to_be)
|
||||
// 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
|
||||
{
|
||||
read_bytes!(buffer, u32, to_be)
|
||||
// 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
|
||||
{
|
||||
read_bytes!(buffer, u64, to_be)
|
||||
// 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
|
||||
{
|
||||
let mut out: [u8; 8];
|
||||
let ptr_out: *mut u8;
|
||||
// Make sure that there is enough space to read
|
||||
// a value from the buffer.
|
||||
assert!(buffer.len() == usize::BYTES);
|
||||
|
||||
assert!(buffer.len() >= 1 && buffer.len() <= 8);
|
||||
|
||||
out = [0u8; 8];
|
||||
ptr_out = out.as_mut_ptr();
|
||||
unsafe
|
||||
{
|
||||
copy_nonoverlapping::<u8>(buffer.as_ptr(),
|
||||
ptr_out.offset((8 - buffer.len()) as isize),
|
||||
buffer.len());
|
||||
|
||||
(*(ptr_out as *const u64)).to_be() as usize
|
||||
}
|
||||
pack_big_endian!(buffer, usize, usize::BYTES)
|
||||
}
|
||||
|
||||
|
||||
fn u16_to_bytes(num: u16) -> Vec<u8>
|
||||
{
|
||||
let mut buffer: Vec<u8>;
|
||||
|
||||
// Create the Vector to hold the bytes
|
||||
// from this type.
|
||||
buffer = Vec::with_capacity(u16::BYTES);
|
||||
|
||||
// Write the bytes to the Vector.
|
||||
write_bytes!(buffer, u16, U16_BYTES, num, to_be);
|
||||
|
||||
// Return the byte buffer.
|
||||
buffer
|
||||
// Unpack the value into it's byte form.
|
||||
unpack_big_endian!(num, u16::BYTES)
|
||||
}
|
||||
|
||||
fn u32_to_bytes(num: u32) -> Vec<u8>
|
||||
{
|
||||
let mut buffer: Vec<u8>;
|
||||
|
||||
// Create the Vector to hold the bytes
|
||||
// from this type.
|
||||
buffer = Vec::with_capacity(u32::BYTES);
|
||||
|
||||
// Write the bytes to the Vector.
|
||||
write_bytes!(buffer, u32, U32_BYTES, num, to_be);
|
||||
|
||||
// Return the byte buffer.
|
||||
buffer
|
||||
// Unpack the value into it's byte form.
|
||||
unpack_big_endian!(num, u32::BYTES)
|
||||
}
|
||||
|
||||
fn u64_to_bytes(num: u64) -> Vec<u8>
|
||||
{
|
||||
let mut buffer: Vec<u8>;
|
||||
|
||||
// Create the Vector to hold the bytes
|
||||
// from this type.
|
||||
buffer = Vec::with_capacity(u64::BYTES);
|
||||
|
||||
// Write the bytes to the Vector.
|
||||
write_bytes!(buffer, u64, U64_BYTES, num, to_be);
|
||||
|
||||
// Return the byte buffer.
|
||||
buffer
|
||||
// Unpack the value into it's byte form.
|
||||
unpack_big_endian!(num, u64::BYTES)
|
||||
}
|
||||
|
||||
fn usize_to_bytes(num: usize) -> Vec<u8>
|
||||
{
|
||||
let bytes: [u8; 8];
|
||||
let num_bytes: u8;
|
||||
let mut buffer: Vec<u8>;
|
||||
|
||||
num_bytes = usize::BYTES as u8;
|
||||
|
||||
// Create a buffer with enough space for this type.
|
||||
buffer = Vec::with_capacity(usize::BYTES);
|
||||
|
||||
assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8);
|
||||
|
||||
unsafe
|
||||
{
|
||||
bytes = mem::transmute::<usize, [u8; 8]>(num.to_be());
|
||||
buffer.extend_from_slice(&bytes);
|
||||
//copy_nonoverlapping::<u8>(
|
||||
// bytes.as_ptr().offset((8 - num_bytes) as isize),
|
||||
// buffer.as_mut_ptr(), num_bytes as usize);
|
||||
}
|
||||
|
||||
// Return the byte buffer.
|
||||
buffer
|
||||
// Unpack the value into it's byte form.
|
||||
unpack_big_endian!(num, usize::BYTES)
|
||||
}
|
||||
|
||||
fn bytes_to_string(buffer: &[u8]) -> String
|
||||
@ -285,104 +237,63 @@ impl Converter for LittleEndian
|
||||
{
|
||||
fn bytes_to_u16(buffer: &[u8]) -> u16
|
||||
{
|
||||
read_bytes!(buffer, u16, to_le)
|
||||
// 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
|
||||
{
|
||||
read_bytes!(buffer, u32, to_le)
|
||||
// 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
|
||||
{
|
||||
read_bytes!(buffer, u64, to_le)
|
||||
// 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
|
||||
{
|
||||
let mut out: [u8; 8];
|
||||
let ptr_out: *mut u8;
|
||||
// Make sure that there is enough space to read
|
||||
// a value from the buffer.
|
||||
assert!(buffer.len() == usize::BYTES);
|
||||
|
||||
assert!(buffer.len() >= 1 && buffer.len() <= 8);
|
||||
|
||||
out = [0u8; 8];
|
||||
ptr_out = out.as_mut_ptr();
|
||||
unsafe
|
||||
{
|
||||
copy_nonoverlapping::<u8>(buffer.as_ptr(), ptr_out, buffer.len());
|
||||
(*(ptr_out as *const u64)).to_le() as usize
|
||||
}
|
||||
pack_little_endian!(buffer, usize, usize::BYTES)
|
||||
}
|
||||
|
||||
|
||||
fn u16_to_bytes(num: u16) -> Vec<u8>
|
||||
{
|
||||
let mut buffer: Vec<u8>;
|
||||
|
||||
// Create the Vector to hold the bytes
|
||||
// from this type.
|
||||
buffer = Vec::with_capacity(u16::BYTES);
|
||||
|
||||
// Write the bytes to the Vector.
|
||||
write_bytes!(buffer, u16, U16_BYTES, num, to_le);
|
||||
|
||||
// Return the byte buffer.
|
||||
buffer
|
||||
// Unpack the value into it's byte form.
|
||||
unpack_little_endian!(num, u16::BYTES)
|
||||
}
|
||||
|
||||
fn u32_to_bytes(num: u32) -> Vec<u8>
|
||||
{
|
||||
let mut buffer: Vec<u8>;
|
||||
|
||||
// Create the Vector to hold the bytes
|
||||
// from this type.
|
||||
buffer = Vec::with_capacity(u32::BYTES);
|
||||
|
||||
// Write the bytes to the Vector.
|
||||
write_bytes!(buffer, u32, U32_BYTES, num, to_le);
|
||||
|
||||
// Return the byte buffer.
|
||||
buffer
|
||||
// Unpack the value into it's byte form.
|
||||
unpack_little_endian!(num, u32::BYTES)
|
||||
}
|
||||
|
||||
fn u64_to_bytes(num: u64) -> Vec<u8>
|
||||
{
|
||||
let mut buffer: Vec<u8>;
|
||||
|
||||
// Create the Vector to hold the bytes
|
||||
// from this type.
|
||||
buffer = Vec::with_capacity(u64::BYTES);
|
||||
|
||||
// Write the bytes to the Vector.
|
||||
write_bytes!(buffer, u64, U64_BYTES, num, to_le);
|
||||
|
||||
// Return the byte buffer.
|
||||
buffer
|
||||
// Unpack the value into it's byte form.
|
||||
unpack_little_endian!(num, u64::BYTES)
|
||||
}
|
||||
|
||||
fn usize_to_bytes(num: usize) -> Vec<u8>
|
||||
{
|
||||
let bytes: [u8; 8];
|
||||
let num_bytes: u8;
|
||||
let mut buffer: Vec<u8>;
|
||||
|
||||
num_bytes = usize::BYTES as u8;
|
||||
|
||||
// Create a buffer with enough space for this type.
|
||||
buffer = Vec::with_capacity(usize::BYTES);
|
||||
|
||||
assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8);
|
||||
|
||||
unsafe
|
||||
{
|
||||
bytes = mem::transmute::<usize, [u8; 8]>(num.to_le());
|
||||
buffer.extend_from_slice(&bytes);
|
||||
//copy_nonoverlapping::<u8>(bytes.as_ptr(), buffer.as_mut_ptr(),
|
||||
// num_bytes as usize);
|
||||
}
|
||||
|
||||
// Return the byte buffer.
|
||||
buffer
|
||||
// Unpack the value into it's byte form.
|
||||
unpack_little_endian!(num, usize::BYTES)
|
||||
}
|
||||
|
||||
fn bytes_to_string(buffer: &[u8]) -> String
|
||||
@ -396,7 +307,7 @@ impl Converter for LittleEndian
|
||||
// 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]);
|
||||
byte_count = LittleEndian::bytes_to_u64(&buffer[0..U64_BYTES]);
|
||||
|
||||
if byte_count > 0
|
||||
{
|
||||
@ -493,8 +404,6 @@ impl ::std::fmt::Display for Endianess
|
||||
pub fn network_to_platform_order<T>(val: T) -> T
|
||||
where T: Transmutable
|
||||
{
|
||||
let buffer: Vec<u8>;
|
||||
|
||||
// Determine what endianess the Platform is using.
|
||||
if cfg!(target_endian="big")
|
||||
{
|
||||
@ -504,9 +413,7 @@ pub fn network_to_platform_order<T>(val: T) -> T
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert the value from Big endian to Little endian.
|
||||
buffer = val.as_endian_bytes(Endianess::Network);
|
||||
T::from_endian_bytes(buffer.as_slice(), Endianess::Platform)
|
||||
T::from_endian_bytes(val.as_bytes().as_slice(), Endianess::Platform)
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,8 +421,6 @@ pub fn network_to_platform_order<T>(val: T) -> T
|
||||
pub fn platform_to_network_order<T>(val: T) -> T
|
||||
where T: Transmutable
|
||||
{
|
||||
let buffer: Vec<u8>;
|
||||
|
||||
// Determine what endianess the Platform is using.
|
||||
if cfg!(target_endian="big")
|
||||
{
|
||||
@ -525,9 +430,7 @@ pub fn platform_to_network_order<T>(val: T) -> T
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert the value from Little endian to Big endian.
|
||||
buffer = val.as_endian_bytes(Endianess::Platform);
|
||||
T::from_endian_bytes(buffer.as_slice(), Endianess::Network)
|
||||
T::from_endian_bytes(val.as_bytes().as_slice(), Endianess::Platform)
|
||||
}
|
||||
}
|
||||
|
||||
@ -549,43 +452,3 @@ pub fn get_platform_endianess() -> Endianess
|
||||
Endianess::Little
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,9 @@ extern crate sigils;
|
||||
|
||||
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod byte_sized;
|
||||
mod converter;
|
||||
mod endian;
|
||||
|
136
src/macros.rs
Normal file
136
src/macros.rs
Normal file
@ -0,0 +1,136 @@
|
||||
//! Macros were created because functions started to get really complicated.
|
||||
//! These macros should not be exported out of the library as they are
|
||||
//! not safe to use since they do no type checking.
|
||||
|
||||
|
||||
|
||||
/// Handles the repetative bit packing for big endian.
|
||||
macro_rules! pack_big_endian
|
||||
{
|
||||
($buffer: ident, $target_type: ty, $bytes: expr) =>
|
||||
{
|
||||
{
|
||||
let mut value: $target_type;
|
||||
|
||||
// Make sure that there is enough data to read
|
||||
// the bytes for this type.
|
||||
assert!($buffer.len() >= $bytes);
|
||||
|
||||
// Start with a value of zero and or it with
|
||||
// the bits shifted values from the buffer.
|
||||
value = 0;
|
||||
for i in 0..$bytes
|
||||
{
|
||||
value |= ($buffer[i] as $target_type) << ((($bytes - i) - 1) * 8);
|
||||
}
|
||||
|
||||
// Return the determined value.
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles the repetative bit packing for little endian.
|
||||
macro_rules! pack_little_endian
|
||||
{
|
||||
($buffer: ident, $target_type: ty, $bytes: expr) =>
|
||||
{
|
||||
{
|
||||
let mut value: $target_type;
|
||||
|
||||
// Make sure that there is enough data to read
|
||||
// the bytes for this type.
|
||||
assert!($buffer.len() >= $bytes);
|
||||
|
||||
// Start with a value of zero and or it with
|
||||
// the bits shifted values from the buffer.
|
||||
value = 0;
|
||||
for i in 0..$bytes
|
||||
{
|
||||
value |= ($buffer[($bytes - 1) - i] as $target_type) <<
|
||||
((($bytes - i) - 1) * 8);
|
||||
}
|
||||
|
||||
// Return the determined value.
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles the repetative big endian unpacking.
|
||||
macro_rules! unpack_big_endian
|
||||
{
|
||||
($value: expr, $bytes: expr) =>
|
||||
{
|
||||
{
|
||||
let mut buffer: Vec<u8>;
|
||||
|
||||
// Create an array with enough space for this value
|
||||
// and then bit shift the value into a buffer of bytes.
|
||||
buffer = Vec::with_capacity($bytes);
|
||||
for i in 0..$bytes
|
||||
{
|
||||
buffer.push(($value >> (($bytes - i) - 1) * 8) as u8);
|
||||
}
|
||||
|
||||
// Return the buffer of bytes that represent this value.
|
||||
buffer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles the repetative little endian unpacking.
|
||||
macro_rules! unpack_little_endian
|
||||
{
|
||||
($value: expr, $bytes: expr) =>
|
||||
{
|
||||
{
|
||||
let mut buffer: Vec<u8>;
|
||||
|
||||
// Create an array with enough space for this value
|
||||
// and then bit shift the value into a buffer of bytes.
|
||||
buffer = Vec::with_capacity($bytes);
|
||||
for i in 0..$bytes
|
||||
{
|
||||
buffer.push(($value >> (i * 8)) as u8);
|
||||
}
|
||||
|
||||
// Return the buffer of bytes that represent this value.
|
||||
buffer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles swapping from big endian to little endian.
|
||||
macro_rules! swap_big_to_little_endian
|
||||
{
|
||||
($value: expr, $target_type: ty, $bytes: expr) =>
|
||||
{
|
||||
{
|
||||
let buffer: Vec<u8>;
|
||||
|
||||
// Convert the big endian value to bytes.
|
||||
buffer = unpack_big_endian!($value, $bytes);
|
||||
|
||||
// Convert the buffer of bytes to a little endian value.
|
||||
pack_little_endian!(buffer, $target_type, $bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles swapping from little endian to big endian.
|
||||
macro_rules! swap_little_to_big_endian
|
||||
{
|
||||
($value: expr, $target_type: ty, $bytes: expr) =>
|
||||
{
|
||||
{
|
||||
let buffer: Vec<u8>;
|
||||
|
||||
// Convert the little endian value to bytes.
|
||||
buffer = unpack_little_endian!($value, $bytes);
|
||||
|
||||
// Convert the buffer of bytes to a big endian value.
|
||||
pack_big_endian!(buffer, $target_type, $bytes)
|
||||
}
|
||||
}
|
||||
}
|
1175
src/transmutable.rs
1175
src/transmutable.rs
File diff suppressed because it is too large
Load Diff
@ -1,249 +0,0 @@
|
||||
extern crate rand;
|
||||
|
||||
extern crate alchemy;
|
||||
extern crate sigils;
|
||||
|
||||
|
||||
|
||||
use std::thread::{Builder, JoinHandle};
|
||||
|
||||
use alchemy::{U16_BYTES, U32_BYTES, U64_BYTES};
|
||||
use alchemy::{I16_BYTES, I32_BYTES, I64_BYTES};
|
||||
use alchemy::{USIZE_BYTES, ISIZE_BYTES};
|
||||
use alchemy::{F32_BYTES, F64_BYTES};
|
||||
|
||||
|
||||
const EXHAUSTIVE_RUNS: u64 = 10000u64;
|
||||
|
||||
|
||||
|
||||
macro_rules! create_thread
|
||||
{
|
||||
($thread_name: expr, $func_name: ident) =>
|
||||
{
|
||||
{
|
||||
let builder: Builder;
|
||||
|
||||
builder = Builder::new().name($thread_name.to_string());
|
||||
match builder.spawn($func_name)
|
||||
{
|
||||
Ok(handle) =>
|
||||
{
|
||||
handle
|
||||
}
|
||||
|
||||
Err(_) =>
|
||||
{
|
||||
panic!("Error spawning thread: {}.", $thread_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
macro_rules! full_check_impl
|
||||
{
|
||||
($varType: ident, $read_func: ident, $write_func: ident, $numBytes: expr) =>
|
||||
{
|
||||
{
|
||||
use std::$varType;
|
||||
use rand::ThreadRng;
|
||||
use rand::distributions::{IndependentSample, Range};
|
||||
use alchemy::{Converter, BigEndian, LittleEndian};
|
||||
|
||||
let range: Range<$varType>;
|
||||
let mut rng: ThreadRng;
|
||||
|
||||
rng = rand::thread_rng();
|
||||
range = Range::new($varType::MIN, $varType::MAX);
|
||||
for _ in 0..EXHAUSTIVE_RUNS
|
||||
{
|
||||
let val: $varType;
|
||||
let final_big_val: $varType;
|
||||
let final_little_val: $varType;
|
||||
let mut buffer: [u8; $numBytes];
|
||||
|
||||
buffer = [0u8; $numBytes];
|
||||
val = range.ind_sample(&mut rng);
|
||||
|
||||
BigEndian::$write_func(&mut buffer, val);
|
||||
final_big_val = BigEndian::$read_func(&buffer);
|
||||
if final_big_val != val
|
||||
{
|
||||
panic!(false);
|
||||
}
|
||||
|
||||
LittleEndian::$write_func(&mut buffer, val);
|
||||
final_little_val = LittleEndian::$read_func(&buffer);
|
||||
if final_little_val != val
|
||||
{
|
||||
panic!(false);
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
macro_rules! full_check
|
||||
{
|
||||
($func_name: ident, $varType: ident, $read_func: ident,
|
||||
$write_func: ident) =>
|
||||
{
|
||||
fn $func_name() -> bool
|
||||
{
|
||||
full_check_impl!($varType, $read_func, $write_func, $varType::BYTES)
|
||||
}
|
||||
};
|
||||
|
||||
($func_name: ident, $varType: ident,
|
||||
$read_func: ident, $write_func: ident, $numBytes: expr) =>
|
||||
{
|
||||
fn $func_name() -> bool
|
||||
{
|
||||
full_check_impl!($varType, $read_func, $write_func, $numBytes)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// This should only be called by the macro below.
|
||||
macro_rules! overflow_impl
|
||||
{
|
||||
($numBytes: expr, $varType: ident,
|
||||
$read_func: ident, $write_func: ident) =>
|
||||
{
|
||||
use alchemy::{Converter, BigEndian, LittleEndian};
|
||||
use sigils::Zero;
|
||||
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn read_big_endian()
|
||||
{
|
||||
let buffer: [u8; $numBytes - 1];
|
||||
|
||||
buffer = [0u8; $numBytes - 1];
|
||||
BigEndian::$read_func(&buffer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn read_little_endian()
|
||||
{
|
||||
let buffer: [u8; $numBytes - 1];
|
||||
|
||||
buffer = [0u8; $numBytes - 1];
|
||||
LittleEndian::$read_func(&buffer);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn write_big_endian()
|
||||
{
|
||||
let mut buffer: [u8; $numBytes - 1];
|
||||
|
||||
buffer = [0u8; $numBytes - 1];
|
||||
BigEndian::$write_func(&mut buffer, $varType::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn write_little_endian()
|
||||
{
|
||||
let mut buffer: [u8; $numBytes - 1];
|
||||
|
||||
buffer = [0u8; $numBytes - 1];
|
||||
LittleEndian::$write_func(&mut buffer, $varType::zero());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// This macro tries to test for buffer overflow happening.
|
||||
macro_rules! test_buffer_overflow
|
||||
{
|
||||
($mod_name: ident, $varType: ident,
|
||||
$read_func: ident, $write_func: ident, $numBytes: ident) =>
|
||||
{
|
||||
mod $mod_name
|
||||
{
|
||||
use alchemy::$numBytes;
|
||||
|
||||
overflow_impl!($numBytes, $varType, $read_func, $write_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Test the different data types for buffer overflow.
|
||||
test_buffer_overflow!(overflow_u16, u16, bytes_to_u16, u16_to_bytes, U16_BYTES);
|
||||
test_buffer_overflow!(overflow_u32, u32, bytes_to_u32, u32_to_bytes, U32_BYTES);
|
||||
test_buffer_overflow!(overflow_u64, u64, bytes_to_u64, u64_to_bytes, U64_BYTES);
|
||||
test_buffer_overflow!(overflow_usize, usize,
|
||||
bytes_to_usize, usize_to_bytes, U8_BYTES);
|
||||
|
||||
test_buffer_overflow!(overflow_i16, i16, bytes_to_i16, i16_to_bytes, I16_BYTES);
|
||||
test_buffer_overflow!(overflow_i32, i32, bytes_to_i32, i32_to_bytes, I32_BYTES);
|
||||
test_buffer_overflow!(overflow_i64, i64, bytes_to_i64, i64_to_bytes, I64_BYTES);
|
||||
test_buffer_overflow!(overflow_isize, isize,
|
||||
bytes_to_isize, isize_to_bytes, U8_BYTES);
|
||||
|
||||
test_buffer_overflow!(overflow_f32, f32, bytes_to_f32, f32_to_bytes, F32_BYTES);
|
||||
test_buffer_overflow!(overflow_f64, f64, bytes_to_f64, f64_to_bytes, F64_BYTES);
|
||||
|
||||
// Create the exhaustive check functions for the integer types.
|
||||
full_check!(check_u16, u16, bytes_to_u16, u16_to_bytes, U16_BYTES);
|
||||
full_check!(check_u32, u32, bytes_to_u32, u32_to_bytes, U32_BYTES);
|
||||
full_check!(check_u64, u64, bytes_to_u64, u64_to_bytes, U64_BYTES);
|
||||
full_check!(check_usize, usize, bytes_to_usize, usize_to_bytes, USIZE_BYTES);
|
||||
|
||||
full_check!(check_i16, i16, bytes_to_i16, i16_to_bytes, I16_BYTES);
|
||||
full_check!(check_i32, i32, bytes_to_i32, i32_to_bytes, I32_BYTES);
|
||||
full_check!(check_i64, i64, bytes_to_i64, i64_to_bytes, I64_BYTES);
|
||||
full_check!(check_isize, isize, bytes_to_isize, isize_to_bytes, ISIZE_BYTES);
|
||||
|
||||
full_check!(check_f32, f32, bytes_to_f32, f32_to_bytes, F32_BYTES);
|
||||
full_check!(check_f64, f64, bytes_to_f64, f64_to_bytes, F64_BYTES);
|
||||
|
||||
|
||||
#[test]
|
||||
fn exhaustive_check()
|
||||
{
|
||||
let mut threads: Vec<JoinHandle<bool>>;
|
||||
|
||||
threads = Vec::new();
|
||||
threads.push(create_thread!("u16", check_u16));
|
||||
threads.push(create_thread!("u32", check_u32));
|
||||
threads.push(create_thread!("u64", check_u64));
|
||||
threads.push(create_thread!("usize", check_usize));
|
||||
threads.push(create_thread!("i16", check_i16));
|
||||
threads.push(create_thread!("i32", check_i32));
|
||||
threads.push(create_thread!("i64", check_i64));
|
||||
threads.push(create_thread!("isize", check_isize));
|
||||
threads.push(create_thread!("f32", check_f32));
|
||||
threads.push(create_thread!("f64", check_f64));
|
||||
|
||||
for handle in threads
|
||||
{
|
||||
let mut name: String;
|
||||
|
||||
name = String::new();
|
||||
name.push_str(handle.thread().name().unwrap());
|
||||
match handle.join()
|
||||
{
|
||||
Ok(result) =>
|
||||
{
|
||||
println!("{}: {}", name, result);
|
||||
}
|
||||
|
||||
Err(_) =>
|
||||
{
|
||||
panic!("{}", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
extern crate rand;
|
||||
|
||||
extern crate alchemy;
|
||||
extern crate sigils;
|
||||
|
||||
|
||||
|
||||
macro_rules! transmutation_vector_test
|
||||
{
|
||||
($modName: ident, $varType: ident, $dataType:ty,
|
||||
$numBytes: expr, [$($var: ident)*]) =>
|
||||
{
|
||||
mod $modName
|
||||
{
|
||||
use rand::{thread_rng, Rng, ThreadRng};
|
||||
|
||||
use alchemy::{Endianess, Transmutable};
|
||||
use sigils::Zero;
|
||||
use sigils::vector::$varType;
|
||||
|
||||
|
||||
|
||||
#[test]
|
||||
pub fn transmutation()
|
||||
{
|
||||
let mut vec: $varType<$dataType>;
|
||||
let final_vec: $varType<$dataType>;
|
||||
let endianess: Endianess;
|
||||
let mut rng: ThreadRng;
|
||||
let mut buffer: [u8; $numBytes];
|
||||
|
||||
// Initialize the variables.
|
||||
rng = thread_rng();
|
||||
vec = $varType::<$dataType>::zero();
|
||||
$(vec.$var = rng.gen();)*
|
||||
buffer = [0u8; $numBytes];
|
||||
endianess = Endianess::PLATFORM;
|
||||
|
||||
vec.to_bytes(&mut buffer, endianess);
|
||||
final_vec = $varType::from_bytes(&buffer, endianess);
|
||||
|
||||
$(assert_eq!(vec.$var, final_vec.$var);)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
transmutation_vector_test!(vec2, Vector2, u64, 16, [x y]);
|
||||
transmutation_vector_test!(vec3, Vector3, u32, 12, [x y z]);
|
||||
transmutation_vector_test!(vec4, Vector4, u16, 8, [x y z w]);
|
||||
|
||||
|
||||
|
||||
mod quat
|
||||
{
|
||||
use rand::{thread_rng, Rng, ThreadRng};
|
||||
|
||||
use alchemy::{Endianess, Transmutable};
|
||||
use sigils::Zero;
|
||||
use sigils::quaternion::Quaternion;
|
||||
|
||||
|
||||
|
||||
#[test]
|
||||
pub fn transmutation()
|
||||
{
|
||||
let mut quat: Quaternion<f64>;
|
||||
let final_quat: Quaternion<f64>;
|
||||
let endianess: Endianess;
|
||||
let mut rng: ThreadRng;
|
||||
let mut buffer: [u8; 32];
|
||||
|
||||
// Initialize the variables.
|
||||
rng = thread_rng();
|
||||
quat = Quaternion::<f64>::zero();
|
||||
quat.scalar = rng.gen();
|
||||
quat.vector.x = rng.gen();
|
||||
quat.vector.y = rng.gen();
|
||||
quat.vector.z = rng.gen();
|
||||
buffer = [0u8; 32];
|
||||
endianess = Endianess::PLATFORM;
|
||||
|
||||
quat.to_bytes(&mut buffer, endianess);
|
||||
final_quat = Quaternion::from_bytes(&buffer, endianess);
|
||||
|
||||
assert_eq!(quat.scalar, final_quat.scalar);
|
||||
assert_eq!(quat.vector.x, final_quat.vector.x);
|
||||
assert_eq!(quat.vector.y, final_quat.vector.y);
|
||||
assert_eq!(quat.vector.z, final_quat.vector.z);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user