use cbor::CborTagEncode;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::cmp::*;
use std::mem;
use std::fmt;
use rand;
pub const NAME_TYPE_LEN : usize = 64;
pub fn slice_equal<T: PartialEq>(lhs: &[T], rhs: &[T]) -> bool {
lhs.len() == rhs.len() && lhs.iter().zip(rhs.iter()).all(|(a, b)| a == b)
}
macro_rules! convert_to_array {
($container:ident, $size:expr) => {{
if $container.len() != $size {
None
} else {
use std::mem;
let mut arr : [_; $size] = unsafe { mem::uninitialized() };
for element in $container.into_iter().enumerate() {
let old_val = mem::replace(&mut arr[element.0], element.1);
unsafe { mem::forget(old_val) };
}
Some(arr)
}
}};
}
pub struct NameType(pub [u8; NAME_TYPE_LEN]);
impl NameType {
#[allow(dead_code)]
fn closer_to_target(lhs: &NameType, rhs: &NameType, target: &NameType) -> bool {
for i in 0..lhs.0.len() {
let res_0 = lhs.0[i] ^ target.0[i];
let res_1 = rhs.0[i] ^ target.0[i];
if res_0 != res_1 {
return res_0 < res_1
}
}
false
}
pub fn new(id: [u8; NAME_TYPE_LEN]) -> NameType {
NameType(id)
}
pub fn get_id(&self) -> [u8; NAME_TYPE_LEN] {
self.0
}
pub fn is_valid(&self) -> bool {
for it in self.0.iter() {
if *it != 0 {
return true;
}
}
false
}
pub fn generate_random() -> NameType {
let mut arr: [u8; NAME_TYPE_LEN] = unsafe { mem::uninitialized() };
for i in 0..NAME_TYPE_LEN {
arr[i] = rand::random::<u8>();
}
NameType(arr)
}
}
impl fmt::Debug for NameType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.0.to_vec())
}
}
impl PartialEq for NameType {
fn eq(&self, other: &NameType) -> bool {
slice_equal(&self.0, &other.0)
}
}
impl Clone for NameType {
fn clone(&self) -> Self {
let mut arr_cloned = [0u8; NAME_TYPE_LEN];
let &NameType(arr_self) = self;
for i in 0..arr_self.len() {
arr_cloned[i] = arr_self[i];
}
NameType(arr_cloned)
}
}
impl Encodable for NameType {
fn encode<E: Encoder>(&self, e: &mut E)->Result<(), E::Error> {
CborTagEncode::new(5483_000, &(self.0.as_ref())).encode(e)
}
}
impl Decodable for NameType {
fn decode<D: Decoder>(d: &mut D)->Result<NameType, D::Error> {
try!(d.read_u64());
let id : Vec<u8> = try!(Decodable::decode(d));
match convert_to_array!(id, NAME_TYPE_LEN) {
Some(id_arr) => Ok(NameType(id_arr)),
None => Err(d.error("Bad NameType size"))
}
}
}
#[cfg(test)]
mod test {
extern crate cbor;
use super::*;
#[test]
fn serialisation_name_type() {
let obj_before = NameType::generate_random();
let mut e = cbor::Encoder::from_memory();
e.encode(&[&obj_before]).unwrap();
let mut d = cbor::Decoder::from_bytes(e.as_bytes());
let obj_after: NameType = d.decode().next().unwrap().unwrap();
assert_eq!(obj_before, obj_after);
}
#[test]
fn name_type_equal_assertion() {
let type1 = NameType::generate_random();
let type1_clone = type1.clone();
let type2 = NameType::generate_random();
assert_eq!(type1, type1_clone);
assert!(type1 == type1_clone);
assert!(!(type1 != type1_clone));
assert!(type1 != type2);
}
#[test]
fn name_type_validity_assertion() {
assert!(NameType([1u8; NAME_TYPE_LEN]).is_valid());
assert!(!NameType([0u8; NAME_TYPE_LEN]).is_valid());
}
#[test]
fn closer_to_target() {
let obj0 = NameType::generate_random();
let obj0_clone = obj0.clone();
let obj1 = NameType::generate_random();
assert!(NameType::closer_to_target(&obj0_clone, &obj1, &obj0));
assert!(!NameType::closer_to_target(&obj1, &obj0_clone, &obj0));
}
#[test]
fn copy_strings_to_bad_array() {
let one = "some string".to_string();
let two = "some two".to_string();
let mut data = Vec::<String>::with_capacity(2);
data.push(one);
data.push(two);
let data2 = data.clone();
assert!(convert_to_array!(data2, 1).is_none());
assert!(convert_to_array!(data, 3).is_none());
}
}