use std::hash;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::hex::ToHex;
use std::cmp::*;
use std::fmt;
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)
}
#[derive(Eq, Copy)]
pub struct NameType(pub [u8; NAME_TYPE_LEN]);
#[allow(unused)]
impl NameType {
pub fn new(id: [u8; NAME_TYPE_LEN]) -> NameType {
NameType(id)
}
pub fn get_id(&self) -> [u8; NAME_TYPE_LEN] {
self.0
}
fn get_debug_id(&self) -> String {
format!("{:02x}{:02x}{:02x}..{:02x}{:02x}{:02x}",
self.0[0],
self.0[1],
self.0[2],
self.0[NAME_TYPE_LEN-3],
self.0[NAME_TYPE_LEN-2],
self.0[NAME_TYPE_LEN-1])
}
fn get_full_id(&self) -> String {
self.0.to_hex()
}
}
impl fmt::Debug for NameType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.get_debug_id())
}
}
impl fmt::Display for NameType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.get_debug_id())
}
}
impl PartialEq for NameType {
fn eq(&self, other: &NameType) -> bool {
slice_equal(&self.0, &other.0)
}
}
pub 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 closer_to_target_or_equal(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
}
}
true
}
impl Ord for NameType {
#[inline]
fn cmp(&self, other: &NameType) -> Ordering {
Ord::cmp(&&self.0[..], &&other.0[..])
}
}
impl PartialOrd for NameType {
#[inline]
fn partial_cmp(&self, other: &NameType) -> Option<Ordering> {
PartialOrd::partial_cmp(&&self.0[..], &&other.0[..])
}
#[inline]
fn lt(&self, other: &NameType) -> bool {
PartialOrd::lt(&&self.0[..], &&other.0[..])
}
#[inline]
fn le(&self, other: &NameType) -> bool {
PartialOrd::le(&&self.0[..], &&other.0[..])
}
#[inline]
fn gt(&self, other: &NameType) -> bool {
PartialOrd::gt(&&self.0[..], &&other.0[..])
}
#[inline]
fn ge(&self, other: &NameType) -> bool {
PartialOrd::ge(&&self.0[..], &&other.0[..])
}
}
impl hash::Hash for NameType {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
state.write(&self.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 ::std::ops::Index<::std::ops::Range<usize>> for NameType {
type Output = [u8];
fn index(&self, _index: ::std::ops::Range<usize>) -> &[u8] {
let &NameType(ref b) = self;
b.index(_index)
}
}
impl ::std::ops::Index<::std::ops::RangeTo<usize>> for NameType {
type Output = [u8];
fn index(&self, _index: ::std::ops::RangeTo<usize>) -> &[u8] {
let &NameType(ref b) = self;
b.index(_index)
}
}
impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for NameType {
type Output = [u8];
fn index(&self, _index: ::std::ops::RangeFrom<usize>) -> &[u8] {
let &NameType(ref b) = self;
b.index(_index)
}
}
impl ::std::ops::Index<::std::ops::RangeFull> for NameType {
type Output = [u8];
fn index(&self, _index: ::std::ops::RangeFull) -> &[u8] {
let &NameType(ref b) = self;
b.index(_index)
}
}
impl Encodable for NameType {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), E::Error> {
encoder.emit_seq(NAME_TYPE_LEN, |encoder| {
for (i, e) in self[..].iter().enumerate() {
try!(encoder.emit_seq_elt(i, |encoder| e.encode(encoder)))
}
Ok(())
})
}
}
impl Decodable for NameType {
fn decode<D: Decoder>(decoder: &mut D) -> Result<NameType, D::Error> {
decoder.read_seq(|decoder, len| {
if len != NAME_TYPE_LEN {
return Err(decoder.error(
&format!("Expecting array of length: {}, but found {}",
NAME_TYPE_LEN, len)));
}
let mut res = NameType([0; NAME_TYPE_LEN]);
{
let NameType(ref mut arr) = res;
for (i, val) in arr.iter_mut().enumerate() {
*val = try!(decoder.read_seq_elt(i,
|decoder| Decodable::decode(decoder)));
}
}
Ok(res)
})
}
}
#[cfg(test)]
mod test {
use cbor;
use super::*;
use id::Id;
use test_utils::Random;
#[test]
fn serialisation_name_type() {
let obj_before: NameType = Random::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 = Random::generate_random();
let type1_clone = type1.clone();
let type2: NameType = Random::generate_random();
assert_eq!(type1, type1_clone);
assert!(type1 == type1_clone);
assert!(!(type1 != type1_clone));
assert!(type1 != type2);
}
#[test]
fn closeness() {
let obj0: NameType = Random::generate_random();
let obj0_clone = obj0.clone();
let obj1: NameType = Random::generate_random();
assert!(closer_to_target(&obj0_clone, &obj1, &obj0));
assert!(!closer_to_target(&obj1, &obj0_clone, &obj0));
}
#[test]
fn format_id_nametype() {
for _ in 0..5 {
let my_id = Id::new();
let my_name = my_id.name();
let debug_id = my_name.get_debug_id();
let full_id = my_name.get_full_id();
assert_eq!(debug_id.len(), 14);
assert_eq!(full_id.len(), 2 * NAME_TYPE_LEN);
assert_eq!(&debug_id[0..6], &full_id[0..6]);
assert_eq!(&debug_id[8..14], &full_id[2*NAME_TYPE_LEN-6..2*NAME_TYPE_LEN]);
assert_eq!(&debug_id[6..8], "..");
}
}
#[test]
fn format_random_nametype() {
for _ in 0..5 {
let my_name : NameType = Random::generate_random();
let debug_id = my_name.get_debug_id();
let full_id = my_name.get_full_id();
assert_eq!(debug_id.len(), 14);
assert_eq!(full_id.len(), 2 * NAME_TYPE_LEN);
assert_eq!(&debug_id[0..6], &full_id[0..6]);
assert_eq!(&debug_id[8..14], &full_id[2*NAME_TYPE_LEN-6..2*NAME_TYPE_LEN]);
assert_eq!(&debug_id[6..8], "..");
}
}
#[test]
fn format_fixed_low_char_nametype() {
let low_char_id = [1u8; NAME_TYPE_LEN];
let my_low_char_name = NameType::new(low_char_id);
let debug_id = my_low_char_name.get_debug_id();
let full_id = my_low_char_name.get_full_id();
assert_eq!(debug_id.len(), 14);
assert_eq!(full_id.len(), 2 * NAME_TYPE_LEN);
assert_eq!(&debug_id[0..6], &full_id[0..6]);
assert_eq!(&debug_id[8..14], &full_id[2*NAME_TYPE_LEN-6..2*NAME_TYPE_LEN]);
assert_eq!(&debug_id[6..8], "..");
}
}