#![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::{BigEndian, LittleEndian, Transmutable}; 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::{BigEndian, LittleEndian, Transmutable}; #[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>; 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); } } } }