use crate::core::hash::{DefaultHashable, Hash, Hashed};
use crate::ser::{self, Readable, Reader, Writeable, Writer};
use byteorder::{ByteOrder, LittleEndian};
use siphasher::sip::SipHasher24;
use std::cmp::{min, Ordering};
use util::ToHex;
pub const SHORT_ID_SIZE: usize = 6;
pub trait ShortIdentifiable {
fn short_id(&self, hash: &Hash, nonce: u64) -> ShortId;
}
impl<H: Hashed> ShortIdentifiable for H {
fn short_id(&self, hash: &Hash, nonce: u64) -> ShortId {
let hash_with_nonce = (hash, nonce).hash();
use std::hash::Hasher;
let k0 = LittleEndian::read_u64(&hash_with_nonce.as_bytes()[0..8]);
let k1 = LittleEndian::read_u64(&hash_with_nonce.as_bytes()[8..16]);
let mut sip_hasher = SipHasher24::new_with_keys(k0, k1);
sip_hasher.write(&self.hash().to_vec()[..]);
let res = sip_hasher.finish();
let mut buf = [0; 8];
LittleEndian::write_u64(&mut buf, res);
ShortId::from_bytes(&buf[0..6])
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct ShortId([u8; 6]);
impl DefaultHashable for ShortId {}
hashable_ord!(ShortId);
impl ::std::fmt::Debug for ShortId {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "{}(", stringify!(ShortId))?;
write!(f, "{}", self.to_hex())?;
write!(f, ")")
}
}
impl AsRef<[u8]> for ShortId {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl Readable for ShortId {
fn read<R: Reader>(reader: &mut R) -> Result<ShortId, ser::Error> {
let v = reader.read_fixed_bytes(SHORT_ID_SIZE)?;
let mut a = [0; SHORT_ID_SIZE];
a.copy_from_slice(&v[..]);
Ok(ShortId(a))
}
}
impl Writeable for ShortId {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
writer.write_fixed_bytes(&self.0)
}
}
impl ShortId {
pub fn from_bytes(bytes: &[u8]) -> ShortId {
let mut hash = [0; SHORT_ID_SIZE];
let copy_size = min(SHORT_ID_SIZE, bytes.len());
hash[..copy_size].copy_from_slice(&bytes[..copy_size]);
ShortId(hash)
}
pub fn from_hex(hex: &str) -> Result<ShortId, ser::Error> {
let bytes = util::from_hex(hex)
.map_err(|_| ser::Error::HexError("short_id from_hex error".to_string()))?;
Ok(ShortId::from_bytes(&bytes))
}
pub fn zero() -> ShortId {
ShortId::from_bytes(&[0])
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::ser::{Writeable, Writer};
#[test]
fn short_id_ord() {
let id_1 = ShortId::from_bytes(&[1, 1, 1, 1]);
let id_2 = ShortId::from_bytes(&[2, 2, 2, 2]);
let id_3 = ShortId::from_bytes(&[3, 3, 3, 3]);
let mut ids = vec![id_1.clone(), id_2.clone(), id_3.clone()];
println!("{:?}", ids);
let mut hashes = ids.iter().map(|x| x.hash()).collect::<Vec<_>>();
println!("{:?}", hashes);
hashes.sort();
println!("{:?}", hashes);
assert_eq!(hashes, [id_1.hash(), id_3.hash(), id_2.hash()]);
ids.sort();
println!("{:?}", ids);
assert_eq!(ids, [id_1, id_3, id_2]);
}
#[test]
fn test_short_id() {
struct Foo(u64);
impl Writeable for Foo {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
writer.write_u64(self.0)?;
Ok(())
}
}
impl DefaultHashable for Foo {}
let foo = Foo(0);
let expected_hash =
Hash::from_hex("81e47a19e6b29b0a65b9591762ce5143ed30d0261e5d24a3201752506b20f15c")
.unwrap();
assert_eq!(foo.hash(), expected_hash);
let other_hash = Hash::default();
assert_eq!(
foo.short_id(&other_hash, foo.0),
ShortId::from_hex("4cc808b62476").unwrap()
);
let foo = Foo(5);
let expected_hash =
Hash::from_hex("3a42e66e46dd7633b57d1f921780a1ac715e6b93c19ee52ab714178eb3a9f673")
.unwrap();
assert_eq!(foo.hash(), expected_hash);
let other_hash = Hash::default();
assert_eq!(
foo.short_id(&other_hash, foo.0),
ShortId::from_hex("02955a094534").unwrap()
);
let foo = Foo(5);
let expected_hash =
Hash::from_hex("3a42e66e46dd7633b57d1f921780a1ac715e6b93c19ee52ab714178eb3a9f673")
.unwrap();
assert_eq!(foo.hash(), expected_hash);
let other_hash =
Hash::from_hex("81e47a19e6b29b0a65b9591762ce5143ed30d0261e5d24a3201752506b20f15c")
.unwrap();
assert_eq!(
foo.short_id(&other_hash, foo.0),
ShortId::from_hex("3e9cde72a687").unwrap()
);
}
}