#![doc(html_root_url = "https://docs.rs/phf_shared/0.9")]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
extern crate std as core;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::num::Wrapping;
use siphasher::sip128::{Hash128, Hasher128, SipHasher13};
#[non_exhaustive]
pub struct Hashes {
pub g: u32,
pub f1: u32,
pub f2: u32,
}
pub type HashKey = u64;
#[inline]
pub fn displace(f1: u32, f2: u32, d1: u32, d2: u32) -> u32 {
(Wrapping(d2) + Wrapping(f1) * Wrapping(d1) + Wrapping(f2)).0
}
#[inline]
pub fn hash<T: ?Sized + PhfHash>(x: &T, key: &HashKey) -> Hashes {
let mut hasher = SipHasher13::new_with_keys(0, *key);
x.phf_hash(&mut hasher);
let Hash128 {
h1: lower,
h2: upper,
} = hasher.finish128();
Hashes {
g: (lower >> 32) as u32,
f1: lower as u32,
f2: upper as u32,
}
}
#[inline]
pub fn get_index(hashes: &Hashes, disps: &[(u32, u32)], len: usize) -> u32 {
let (d1, d2) = disps[(hashes.g % (disps.len() as u32)) as usize];
displace(hashes.f1, hashes.f2, d1, d2) % (len as u32)
}
pub trait PhfHash {
fn phf_hash<H: Hasher>(&self, state: &mut H);
fn phf_hash_slice<H: Hasher>(data: &[Self], state: &mut H)
where
Self: Sized,
{
for piece in data {
piece.phf_hash(state);
}
}
}
pub trait FmtConst {
fn fmt_const(&self, f: &mut fmt::Formatter) -> fmt::Result;
}
pub trait PhfBorrow<B: ?Sized> {
fn borrow(&self) -> &B;
}
macro_rules! delegate_debug (
($ty:ty) => {
impl FmtConst for $ty {
fn fmt_const(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
}
);
delegate_debug!(str);
delegate_debug!(char);
delegate_debug!(u8);
delegate_debug!(i8);
delegate_debug!(u16);
delegate_debug!(i16);
delegate_debug!(u32);
delegate_debug!(i32);
delegate_debug!(u64);
delegate_debug!(i64);
delegate_debug!(u128);
delegate_debug!(i128);
delegate_debug!(bool);
macro_rules! impl_reflexive(
($($t:ty),*) => (
$(impl PhfBorrow<$t> for $t {
fn borrow(&self) -> &$t {
self
}
})*
)
);
impl_reflexive!(
str,
char,
u8,
i8,
u16,
i16,
u32,
i32,
u64,
i64,
u128,
i128,
bool,
[u8]
);
#[cfg(feature = "std")]
impl PhfBorrow<str> for String {
fn borrow(&self) -> &str {
self
}
}
#[cfg(feature = "std")]
impl PhfBorrow<[u8]> for Vec<u8> {
fn borrow(&self) -> &[u8] {
self
}
}
#[cfg(feature = "std")]
delegate_debug!(String);
#[cfg(feature = "std")]
impl PhfHash for String {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
(**self).phf_hash(state)
}
}
#[cfg(feature = "std")]
impl PhfHash for Vec<u8> {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
(**self).phf_hash(state)
}
}
impl<'a, T: 'a + PhfHash + ?Sized> PhfHash for &'a T {
fn phf_hash<H: Hasher>(&self, state: &mut H) {
(*self).phf_hash(state)
}
}
impl<'a, T: 'a + FmtConst + ?Sized> FmtConst for &'a T {
fn fmt_const(&self, f: &mut fmt::Formatter) -> fmt::Result {
(*self).fmt_const(f)
}
}
impl<'a> PhfBorrow<str> for &'a str {
fn borrow(&self) -> &str {
self
}
}
impl<'a> PhfBorrow<[u8]> for &'a [u8] {
fn borrow(&self) -> &[u8] {
self
}
}
impl PhfHash for str {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
self.as_bytes().phf_hash(state)
}
}
impl PhfHash for [u8] {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
state.write(self);
}
}
impl FmtConst for [u8] {
#[inline]
fn fmt_const(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "&{:?}", self)
}
}
#[cfg(feature = "unicase")]
impl<S> PhfHash for unicase::UniCase<S>
where
unicase::UniCase<S>: Hash,
{
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
self.hash(state)
}
}
#[cfg(feature = "unicase")]
impl<S> FmtConst for unicase::UniCase<S>
where
S: AsRef<str>,
{
fn fmt_const(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_ascii() {
f.write_str("UniCase::ascii(")?;
} else {
f.write_str("UniCase::unicode(")?;
}
self.as_ref().fmt_const(f)?;
f.write_str(")")
}
}
#[cfg(feature = "unicase")]
impl<'b, 'a: 'b, S: ?Sized + 'a> PhfBorrow<unicase::UniCase<&'b S>> for unicase::UniCase<&'a S> {
fn borrow(&self) -> &unicase::UniCase<&'b S> {
self
}
}
#[cfg(feature = "uncased")]
impl PhfHash for uncased::UncasedStr {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
self.hash(state)
}
}
#[cfg(feature = "uncased")]
impl FmtConst for uncased::UncasedStr {
fn fmt_const(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("unsafe { ::std::mem::transmute::<&'static str, &'static UncasedStr>(")?;
self.as_str().fmt_const(f)?;
f.write_str(") }")
}
}
#[cfg(feature = "uncased")]
impl PhfBorrow<uncased::UncasedStr> for &uncased::UncasedStr {
fn borrow(&self) -> &uncased::UncasedStr {
self
}
}
macro_rules! sip_impl (
(le $t:ty) => (
impl PhfHash for $t {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
self.to_le().hash(state);
}
}
);
($t:ty) => (
impl PhfHash for $t {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
self.hash(state);
}
}
)
);
sip_impl!(u8);
sip_impl!(i8);
sip_impl!(le u16);
sip_impl!(le i16);
sip_impl!(le u32);
sip_impl!(le i32);
sip_impl!(le u64);
sip_impl!(le i64);
sip_impl!(le u128);
sip_impl!(le i128);
sip_impl!(bool);
impl PhfHash for char {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
(*self as u32).phf_hash(state)
}
}
fn fmt_array(array: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", array)
}
macro_rules! array_impl (
($t:ty, $n:expr) => (
impl PhfHash for [$t; $n] {
#[inline]
fn phf_hash<H: Hasher>(&self, state: &mut H) {
state.write(self);
}
}
impl FmtConst for [$t; $n] {
fn fmt_const(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt_array(self, f)
}
}
impl PhfBorrow<[$t]> for [$t; $n] {
fn borrow(&self) -> &[$t] {
self
}
}
)
);
array_impl!(u8, 1);
array_impl!(u8, 2);
array_impl!(u8, 3);
array_impl!(u8, 4);
array_impl!(u8, 5);
array_impl!(u8, 6);
array_impl!(u8, 7);
array_impl!(u8, 8);
array_impl!(u8, 9);
array_impl!(u8, 10);
array_impl!(u8, 11);
array_impl!(u8, 12);
array_impl!(u8, 13);
array_impl!(u8, 14);
array_impl!(u8, 15);
array_impl!(u8, 16);
array_impl!(u8, 17);
array_impl!(u8, 18);
array_impl!(u8, 19);
array_impl!(u8, 20);
array_impl!(u8, 21);
array_impl!(u8, 22);
array_impl!(u8, 23);
array_impl!(u8, 24);
array_impl!(u8, 25);
array_impl!(u8, 26);
array_impl!(u8, 27);
array_impl!(u8, 28);
array_impl!(u8, 29);
array_impl!(u8, 30);
array_impl!(u8, 31);
array_impl!(u8, 32);