use crate::feature_from::FeatureFrom;
use crate::gap_gram::GapPair;
use fxhash::FxHasher64;
use nohash_hasher::IsEnabled;
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
use std::cmp::Reverse;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
#[derive(Hash, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Debug)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct HashedAs<T>(pub(crate) T);
type TheHasher = FxHasher64;
macro_rules! impl_hashed {
($u_type:ty) => {
impl<A: Hash> FromIterator<A> for HashedAs<$u_type> {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = A>,
{
let mut h = TheHasher::default();
for t in iter.into_iter() {
t.hash(&mut h);
}
HashedAs(h.finish() as $u_type)
}
}
impl<T: Hash> FeatureFrom<T> for HashedAs<$u_type> {
fn from(token_group: T) -> Self {
let mut h = TheHasher::default();
token_group.hash(&mut h);
HashedAs(h.finish() as $u_type)
}
}
impl<T: Hash, V: Hash> From<GapPair<T, V>> for HashedAs<$u_type> {
fn from(x: GapPair<T, V>) -> Self {
let mut h = TheHasher::default();
x.0.hash(&mut h);
[x.2, 4567].hash(&mut h);
x.1.hash(&mut h);
HashedAs(h.finish() as $u_type)
}
}
impl From<HashedAs<$u_type>> for $u_type {
fn from(x: HashedAs<$u_type>) -> $u_type {
x.0
}
}
impl IsEnabled for HashedAs<$u_type> {}
};
}
impl<A, B> FeatureFrom<A> for Reverse<HashedAs<B>>
where
HashedAs<B>: FeatureFrom<A>,
{
fn from(token_group: A) -> Self {
Reverse(FeatureFrom::from(token_group))
}
}
impl_hashed!(u8);
impl_hashed!(u16);
impl_hashed!(u32);
impl_hashed!(u64);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gap_pair_hash_uses_both_components() {
let a: HashedAs<u64> = From::from(GapPair("ab", "cd", 1));
let b: HashedAs<u64> = From::from(GapPair("ab", "zz", 1));
assert_ne!(a, b);
let a2: HashedAs<u64> = From::from(GapPair("ab", "cd", 1));
assert_eq!(a, a2);
}
}