Transmutable was changed to Converter. This needed to be reflected in the example and tests. Also, fixed some comments in the new transmutable module.
258 lines
6.3 KiB
Rust
258 lines
6.3 KiB
Rust
#![feature(zero_one)]
|
|
#![feature(num_bits_bytes)]
|
|
|
|
extern crate rand;
|
|
|
|
extern crate alchemy;
|
|
extern crate sigils;
|
|
|
|
|
|
|
|
use std::thread::{Builder, JoinHandle};
|
|
|
|
|
|
|
|
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
|
|
{
|
|
($T: ident, $read_func: ident, $write_func: ident, $numBytes: expr) =>
|
|
{
|
|
{
|
|
use rand::ThreadRng;
|
|
use rand::distributions::{IndependentSample, Range};
|
|
use alchemy::{Converter, BigEndian, LittleEndian};
|
|
|
|
let range: Range<$T>;
|
|
let mut rng: ThreadRng;
|
|
|
|
rng = rand::thread_rng();
|
|
range = Range::new(std::$T::MIN, std::$T::MAX);
|
|
for _ in 0..EXHAUSTIVE_RUNS
|
|
{
|
|
let val: $T;
|
|
let final_big_val: $T;
|
|
let final_little_val: $T;
|
|
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, $T: ident, $read_func: ident, $write_func: ident) =>
|
|
{
|
|
fn $func_name() -> bool
|
|
{
|
|
use std::$T;
|
|
full_check_impl!($T, $read_func, $write_func, $T::BYTES)
|
|
}
|
|
};
|
|
|
|
($func_name: ident, $T: ident,
|
|
$read_func: ident, $write_func: ident, $numBytes: expr) =>
|
|
{
|
|
fn $func_name() -> bool
|
|
{
|
|
full_check_impl!($T, $read_func, $write_func, $numBytes)
|
|
}
|
|
};
|
|
}
|
|
|
|
/// This should only be called by the macro below.
|
|
macro_rules! overflow_impl
|
|
{
|
|
($numBytes: expr, $T: ident,
|
|
$read_func: ident, $write_func: ident) =>
|
|
{
|
|
use std::num::Zero;
|
|
|
|
use alchemy::{Converter, BigEndian, LittleEndian};
|
|
|
|
|
|
|
|
#[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, $T::zero());
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn write_little_endian()
|
|
{
|
|
let mut buffer: [u8; $numBytes - 1];
|
|
|
|
buffer = [0u8; $numBytes - 1];
|
|
LittleEndian::$write_func(&mut buffer, $T::zero());
|
|
}
|
|
};
|
|
}
|
|
|
|
/// This macro tries to test for buffer overflow happening.
|
|
macro_rules! test_buffer_overflow
|
|
{
|
|
($mod_name: ident, $T: ident,
|
|
$read_func: ident, $write_func: ident) =>
|
|
{
|
|
mod $mod_name
|
|
{
|
|
use std::$T;
|
|
overflow_impl!($T::BYTES, $T, $read_func, $write_func);
|
|
}
|
|
};
|
|
|
|
($mod_name: ident, $T: ident,
|
|
$read_func: ident, $write_func: ident, $numBytes: expr) =>
|
|
{
|
|
mod $mod_name
|
|
{
|
|
overflow_impl!($numBytes, $T, $read_func, $write_func);
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
|
|
// Test the different data types for buffer overflow.
|
|
test_buffer_overflow!(overflow_u16, u16, bytes_to_u16, u16_to_bytes);
|
|
test_buffer_overflow!(overflow_u32, u32, bytes_to_u32, u32_to_bytes);
|
|
test_buffer_overflow!(overflow_u64, u64, bytes_to_u64, u64_to_bytes);
|
|
test_buffer_overflow!(overflow_usize, usize,
|
|
bytes_to_usize, usize_to_bytes, 1);
|
|
|
|
test_buffer_overflow!(overflow_i16, i16, bytes_to_i16, i16_to_bytes);
|
|
test_buffer_overflow!(overflow_i32, i32, bytes_to_i32, i32_to_bytes);
|
|
test_buffer_overflow!(overflow_i64, i64, bytes_to_i64, i64_to_bytes);
|
|
test_buffer_overflow!(overflow_isize, isize,
|
|
bytes_to_isize, isize_to_bytes, 1);
|
|
|
|
test_buffer_overflow!(overflow_f32, f32, bytes_to_f32, f32_to_bytes, 4);
|
|
test_buffer_overflow!(overflow_f64, f64, bytes_to_f64, f64_to_bytes, 8);
|
|
|
|
// Create the exhaustive check functions for the integer types.
|
|
full_check!(check_u16, u16, bytes_to_u16, u16_to_bytes);
|
|
full_check!(check_u32, u32, bytes_to_u32, u32_to_bytes);
|
|
full_check!(check_u64, u64, bytes_to_u64, u64_to_bytes);
|
|
full_check!(check_usize, usize, bytes_to_usize, usize_to_bytes);
|
|
|
|
full_check!(check_i16, i16, bytes_to_i16, i16_to_bytes);
|
|
full_check!(check_i32, i32, bytes_to_i32, i32_to_bytes);
|
|
full_check!(check_i64, i64, bytes_to_i64, i64_to_bytes);
|
|
full_check!(check_isize, isize, bytes_to_isize, isize_to_bytes);
|
|
|
|
full_check!(check_f32, f32, bytes_to_f32, f32_to_bytes, 4);
|
|
full_check!(check_f64, f64, bytes_to_f64, f64_to_bytes, 8);
|
|
|
|
|
|
#[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);
|
|
}
|
|
}
|
|
}
|
|
}
|