1#![doc(html_root_url = "https://docs.rs/phf_shared/0.14.0")]
6#![cfg_attr(not(feature = "std"), no_std)]
7
8#[cfg(feature = "std")]
9extern crate std as core;
10
11use core::fmt;
12use core::hash::{Hash, Hasher};
13use core::num::Wrapping;
14use siphasher::sip128::{Hash128, Hasher128, SipHasher13};
15
16mod hasher;
17use hasher::PortableSipHasher;
18
19#[cfg(feature = "ptrhash")]
20pub mod ptrhash;
21
22#[non_exhaustive]
23pub struct Hashes {
24 pub g: u32,
25 pub f1: u32,
26 pub f2: u32,
27}
28
29pub type HashKey = u64;
33
34#[inline]
35pub fn displace(f1: u32, f2: u32, d1: u32, d2: u32) -> u32 {
36 (Wrapping(d2) + Wrapping(f1) * Wrapping(d1) + Wrapping(f2)).0
37}
38
39#[inline]
41pub fn hash<T: ?Sized + PhfHash>(x: &T, key: &HashKey) -> Hashes {
42 let mut hasher = PortableSipHasher::new(SipHasher13::new_with_keys(0, *key));
43 x.phf_hash(&mut hasher);
44
45 let Hash128 {
46 h1: lower,
47 h2: upper,
48 } = hasher.finish128();
49
50 Hashes {
51 g: (lower >> 32) as u32,
52 f1: lower as u32,
53 f2: upper as u32,
54 }
55}
56
57#[inline]
63pub fn get_index(hashes: &Hashes, disps: &[(u32, u32)], len: usize) -> u32 {
64 let (d1, d2) = disps[(hashes.g % (disps.len() as u32)) as usize];
65 displace(hashes.f1, hashes.f2, d1, d2) % (len as u32)
66}
67
68pub trait PhfHash {
74 fn phf_hash<H: Hasher>(&self, state: &mut H);
76
77 fn phf_hash_slice<H: Hasher>(data: &[Self], state: &mut H)
79 where
80 Self: Sized,
81 {
82 state.write_u64(data.len() as u64);
83 for piece in data {
84 piece.phf_hash(state);
85 }
86 }
87}
88
89pub trait FmtConst {
91 fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
93}
94
95pub trait PhfBorrow<B: ?Sized> {
136 fn borrow(&self) -> &B;
138}
139
140pub trait PhfEq<B: ?Sized> {
148 fn phf_eq(&self, other: &B) -> bool;
150}
151
152impl<K, B: ?Sized + Eq> PhfEq<B> for K
153where
154 K: PhfBorrow<B>,
155{
156 fn phf_eq(&self, other: &B) -> bool {
157 self.borrow() == other
158 }
159}
160
161macro_rules! delegate_debug (
166 ($ty:ty) => {
167 impl FmtConst for $ty {
168 fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 write!(f, "{:?}", self)
170 }
171 }
172 }
173);
174
175delegate_debug!(str);
176delegate_debug!(char);
177delegate_debug!(u8);
178delegate_debug!(i8);
179delegate_debug!(u16);
180delegate_debug!(i16);
181delegate_debug!(u32);
182delegate_debug!(i32);
183delegate_debug!(u64);
184delegate_debug!(i64);
185delegate_debug!(usize);
186delegate_debug!(isize);
187delegate_debug!(u128);
188delegate_debug!(i128);
189delegate_debug!(bool);
190
191macro_rules! impl_reflexive(
193 ($($t:ty),*) => (
194 $(impl PhfBorrow<$t> for $t {
195 fn borrow(&self) -> &$t {
196 self
197 }
198 })*
199 )
200);
201
202impl_reflexive!(
203 str,
204 char,
205 u8,
206 i8,
207 u16,
208 i16,
209 u32,
210 i32,
211 u64,
212 i64,
213 usize,
214 isize,
215 u128,
216 i128,
217 bool,
218 [u8]
219);
220
221#[cfg(feature = "std")]
222impl PhfBorrow<str> for String {
223 fn borrow(&self) -> &str {
224 self
225 }
226}
227
228#[cfg(feature = "std")]
229delegate_debug!(String);
230
231#[cfg(feature = "std")]
232impl PhfHash for String {
233 #[inline]
234 fn phf_hash<H: Hasher>(&self, state: &mut H) {
235 (**self).phf_hash(state)
236 }
237}
238
239#[cfg(feature = "std")]
240impl<T: PhfHash> PhfHash for Vec<T> {
241 #[inline]
242 fn phf_hash<H: Hasher>(&self, state: &mut H) {
243 self.as_slice().phf_hash(state)
244 }
245}
246
247impl<'a, T: 'a + PhfHash + ?Sized> PhfHash for &'a T {
248 fn phf_hash<H: Hasher>(&self, state: &mut H) {
249 (*self).phf_hash(state)
250 }
251}
252
253impl<'a, T: 'a + FmtConst + ?Sized> FmtConst for &'a T {
254 fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 (*self).fmt_const(f)
256 }
257}
258
259impl PhfBorrow<str> for &str {
260 fn borrow(&self) -> &str {
261 self
262 }
263}
264
265#[cfg(feature = "std")]
266impl<T> PhfBorrow<[T]> for Vec<T> {
267 fn borrow(&self) -> &[T] {
268 self
269 }
270}
271
272impl<T> PhfBorrow<[T]> for &[T] {
273 fn borrow(&self) -> &[T] {
274 self
275 }
276}
277
278impl<T, const N: usize> PhfBorrow<[T; N]> for &[T; N] {
279 fn borrow(&self) -> &[T; N] {
280 self
281 }
282}
283
284impl PhfHash for str {
285 #[inline]
286 fn phf_hash<H: Hasher>(&self, state: &mut H) {
287 self.as_bytes().phf_hash(state)
288 }
289}
290
291#[cfg(feature = "unicase")]
292impl<S> PhfHash for unicase::UniCase<S>
293where
294 unicase::UniCase<S>: Hash,
295{
296 #[inline]
297 fn phf_hash<H: Hasher>(&self, state: &mut H) {
298 self.hash(state)
299 }
300}
301
302#[cfg(feature = "unicase")]
303impl<S> FmtConst for unicase::UniCase<S>
304where
305 S: AsRef<str>,
306{
307 fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308 if self.is_ascii() {
309 f.write_str("UniCase::ascii(")?;
310 } else {
311 f.write_str("UniCase::unicode(")?;
312 }
313
314 self.as_ref().fmt_const(f)?;
315 f.write_str(")")
316 }
317}
318
319#[cfg(feature = "unicase")]
320impl<'b, 'a: 'b, S: ?Sized + 'a> PhfBorrow<unicase::UniCase<&'b S>> for unicase::UniCase<&'a S> {
321 fn borrow(&self) -> &unicase::UniCase<&'b S> {
322 self
323 }
324}
325
326#[cfg(feature = "unicase")]
327impl<S> PhfHash for unicase::Ascii<S>
328where
329 unicase::Ascii<S>: Hash,
330{
331 #[inline]
332 fn phf_hash<H: Hasher>(&self, state: &mut H) {
333 self.hash(state)
334 }
335}
336
337#[cfg(feature = "unicase")]
338impl<S> FmtConst for unicase::Ascii<S>
339where
340 S: AsRef<str>,
341{
342 fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 f.write_str("Ascii::new(")?;
344 self.as_ref().fmt_const(f)?;
345 f.write_str(")")
346 }
347}
348
349#[cfg(feature = "unicase")]
350impl<'b, 'a: 'b, S: ?Sized + 'a> PhfBorrow<unicase::Ascii<&'b S>> for unicase::Ascii<&'a S> {
351 fn borrow(&self) -> &unicase::Ascii<&'b S> {
352 self
353 }
354}
355
356#[cfg(feature = "uncased")]
357impl PhfHash for uncased::UncasedStr {
358 #[inline]
359 fn phf_hash<H: Hasher>(&self, state: &mut H) {
360 self.hash(state)
361 }
362}
363
364#[cfg(feature = "uncased")]
365impl FmtConst for uncased::UncasedStr {
366 fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 f.write_str("UncasedStr::new(")?;
368 self.as_str().fmt_const(f)?;
369 f.write_str(")")
370 }
371}
372
373#[cfg(feature = "uncased")]
374impl PhfBorrow<uncased::UncasedStr> for &uncased::UncasedStr {
375 fn borrow(&self) -> &uncased::UncasedStr {
376 self
377 }
378}
379
380macro_rules! integer_impl (
381 ($t:ty) => (
382 impl PhfHash for $t {
383 #[inline]
384 fn phf_hash<H: Hasher>(&self, state: &mut H) {
385 self.hash(state);
386 }
387
388 }
390 )
391);
392
393integer_impl!(u16);
394integer_impl!(i16);
395integer_impl!(u32);
396integer_impl!(i32);
397integer_impl!(u64);
398integer_impl!(i64);
399integer_impl!(usize);
400integer_impl!(isize);
401integer_impl!(u128);
402integer_impl!(i128);
403
404macro_rules! single_byte_impl (
405 ($t:ty) => (
406 impl PhfHash for $t {
407 #[inline]
408 fn phf_hash<H: Hasher>(&self, state: &mut H) {
409 self.hash(state);
410 }
411
412 #[inline]
413 fn phf_hash_slice<H: Hasher>(slice: &[$t], state: &mut H) {
414 state.write_u64(slice.len() as u64);
416 state.write(unsafe { &*(slice as *const [$t] as *const [u8]) });
417 }
418 }
419 )
420);
421
422single_byte_impl!(u8);
423single_byte_impl!(i8);
424single_byte_impl!(bool);
427
428impl PhfHash for char {
429 #[inline]
430 fn phf_hash<H: Hasher>(&self, state: &mut H) {
431 (*self as u32).phf_hash(state)
432 }
433}
434
435impl<T: PhfHash, const N: usize> PhfHash for [T; N] {
436 #[inline]
437 fn phf_hash<H: Hasher>(&self, state: &mut H) {
438 <[T]>::phf_hash(self, state);
439 }
440}
441
442impl<T: PhfHash> PhfHash for [T] {
443 #[inline]
444 fn phf_hash<H: Hasher>(&self, state: &mut H) {
445 T::phf_hash_slice(self, state);
446 }
447}
448
449fn fmt_slice<T: core::fmt::Debug>(slice: &[T], f: &mut fmt::Formatter<'_>) -> fmt::Result {
451 write!(f, "&{:?}", slice)
453}
454
455fn fmt_array<T: core::fmt::Debug>(array: &[T], f: &mut fmt::Formatter<'_>) -> fmt::Result {
456 write!(f, "{:?}", array)
457}
458
459macro_rules! slice_impl (
460 ($t:ty) => (
461 impl FmtConst for [$t] {
462 fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
463 fmt_slice(self, f)
464 }
465 }
466
467 #[cfg(feature = "std")]
468 impl FmtConst for Vec<$t> {
469 fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470 self.as_slice().fmt_const(f)
471 }
472 }
473 )
474);
475
476macro_rules! array_impl (
477 ($t:ty) => (
478 impl<const N: usize> FmtConst for [$t; N] {
479 fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
480 fmt_array(self, f)
481 }
482 }
483
484 impl<const N: usize> PhfBorrow<[$t]> for [$t; N] {
485 fn borrow(&self) -> &[$t] {
486 self
487 }
488 }
489 )
490);
491
492slice_impl!(u8);
493slice_impl!(i8);
494slice_impl!(u16);
495slice_impl!(i16);
496slice_impl!(u32);
497slice_impl!(i32);
498slice_impl!(u64);
499slice_impl!(i64);
500slice_impl!(usize);
501slice_impl!(isize);
502slice_impl!(u128);
503slice_impl!(i128);
504slice_impl!(bool);
505slice_impl!(char);
506
507array_impl!(u8);
508array_impl!(i8);
509array_impl!(u16);
510array_impl!(i16);
511array_impl!(u32);
512array_impl!(i32);
513array_impl!(u64);
514array_impl!(i64);
515array_impl!(usize);
516array_impl!(isize);
517array_impl!(u128);
518array_impl!(i128);
519array_impl!(bool);
520array_impl!(char);
521
522macro_rules! tuple_impl {
523 ($($t:ident),+) => {
524 impl<$($t: PhfHash),+> PhfHash for ($($t,)+) {
525 fn phf_hash<HS: Hasher>(&self, state: &mut HS) {
526 #[allow(non_snake_case)]
527 let ($($t,)+) = self;
528 $(
529 $t.phf_hash(state);
530 )+
531 }
532 }
533
534 impl<$($t: FmtConst),+> FmtConst for ($($t,)+) {
535 fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
536 #[allow(non_snake_case)]
537 let ($($t,)+) = self;
538 write!(f, "(")?;
539 let mut first = true;
540 $(
541 if !core::mem::replace(&mut first, false) {
542 write!(f, ", ")?;
543 }
544 $t.fmt_const(f)?;
545 )+
546 write!(f, ")")
547 }
548 }
549 };
550}
551
552macro_rules! tuple_eq_impl {
553 ($(($left_ty:ident, $left:ident, $right_ty:ident, $right:ident)),+) => {
554 impl<$($left_ty, $right_ty),+> PhfEq<($($right_ty,)+)> for ($($left_ty,)+)
555 where
556 $($left_ty: PartialEq<$right_ty>),+
557 {
558 fn phf_eq(&self, other: &($($right_ty,)+)) -> bool {
559 let ($($left,)+) = self;
560 let ($($right,)+) = other;
561 true $(&& $left == $right)+
562 }
563 }
564 };
565}
566
567tuple_impl!(A);
568tuple_impl!(A, B);
569tuple_impl!(A, B, C);
570tuple_impl!(A, B, C, D);
571tuple_impl!(A, B, C, D, E);
572tuple_impl!(A, B, C, D, E, F);
573tuple_impl!(A, B, C, D, E, F, G);
574tuple_impl!(A, B, C, D, E, F, G, HT);
575tuple_impl!(A, B, C, D, E, F, G, HT, I);
576tuple_impl!(A, B, C, D, E, F, G, HT, I, J);
577tuple_impl!(A, B, C, D, E, F, G, HT, I, J, K);
578tuple_impl!(A, B, C, D, E, F, G, HT, I, J, K, L);
579
580tuple_eq_impl!((A, a, AT, at));
581tuple_eq_impl!((A, a, AT, at), (B, b, BT, bt));
582tuple_eq_impl!((A, a, AT, at), (B, b, BT, bt), (C, c, CT, ct));
583tuple_eq_impl!(
584 (A, a, AT, at),
585 (B, b, BT, bt),
586 (C, c, CT, ct),
587 (D, d, DT, dt)
588);
589tuple_eq_impl!(
590 (A, a, AT, at),
591 (B, b, BT, bt),
592 (C, c, CT, ct),
593 (D, d, DT, dt),
594 (E, e, ET, et)
595);
596tuple_eq_impl!(
597 (A, a, AT, at),
598 (B, b, BT, bt),
599 (C, c, CT, ct),
600 (D, d, DT, dt),
601 (E, e, ET, et),
602 (F, ff, FT, ft)
603);
604tuple_eq_impl!(
605 (A, a, AT, at),
606 (B, b, BT, bt),
607 (C, c, CT, ct),
608 (D, d, DT, dt),
609 (E, e, ET, et),
610 (F, ff, FT, ft),
611 (G, g, GT, gt)
612);
613tuple_eq_impl!(
614 (A, a, AT, at),
615 (B, b, BT, bt),
616 (C, c, CT, ct),
617 (D, d, DT, dt),
618 (E, e, ET, et),
619 (F, ff, FT, ft),
620 (G, g, GT, gt),
621 (H, h, HT, ht)
622);
623tuple_eq_impl!(
624 (A, a, AT, at),
625 (B, b, BT, bt),
626 (C, c, CT, ct),
627 (D, d, DT, dt),
628 (E, e, ET, et),
629 (F, ff, FT, ft),
630 (G, g, GT, gt),
631 (H, h, HT, ht),
632 (I, i, IT, it)
633);
634tuple_eq_impl!(
635 (A, a, AT, at),
636 (B, b, BT, bt),
637 (C, c, CT, ct),
638 (D, d, DT, dt),
639 (E, e, ET, et),
640 (F, ff, FT, ft),
641 (G, g, GT, gt),
642 (H, h, HT, ht),
643 (I, i, IT, it),
644 (J, j, JT, jt)
645);
646tuple_eq_impl!(
647 (A, a, AT, at),
648 (B, b, BT, bt),
649 (C, c, CT, ct),
650 (D, d, DT, dt),
651 (E, e, ET, et),
652 (F, ff, FT, ft),
653 (G, g, GT, gt),
654 (H, h, HT, ht),
655 (I, i, IT, it),
656 (J, j, JT, jt),
657 (K, k, KT, kt)
658);
659tuple_eq_impl!(
660 (A, a, AT, at),
661 (B, b, BT, bt),
662 (C, c, CT, ct),
663 (D, d, DT, dt),
664 (E, e, ET, et),
665 (F, ff, FT, ft),
666 (G, g, GT, gt),
667 (H, h, HT, ht),
668 (I, i, IT, it),
669 (J, j, JT, jt),
670 (K, k, KT, kt),
671 (L, l, LT, lt)
672);
673
674#[cfg(test)]
675mod tests {
676 use super::*;
677
678 #[derive(PartialEq, Debug)]
679 enum HashCall {
680 Bytes(Vec<u8>),
681 U8(u8),
682 U16(u16),
683 U32(u32),
684 U64(u64),
685 U128(u128),
686 Usize(usize),
687 I8(i8),
688 I16(i16),
689 I32(i32),
690 I64(i64),
691 I128(i128),
692 Isize(isize),
693 }
695
696 #[derive(PartialEq, Debug)]
697 struct TestHasher {
698 calls: Vec<HashCall>,
699 }
700
701 impl Hasher for TestHasher {
702 fn finish(&self) -> u64 {
703 panic!("only used for tests");
704 }
705 fn write(&mut self, bytes: &[u8]) {
706 self.calls.push(HashCall::Bytes(bytes.to_vec()));
707 }
708 fn write_u8(&mut self, i: u8) {
709 self.calls.push(HashCall::U8(i));
710 }
711 fn write_u16(&mut self, i: u16) {
712 self.calls.push(HashCall::U16(i));
713 }
714 fn write_u32(&mut self, i: u32) {
715 self.calls.push(HashCall::U32(i));
716 }
717 fn write_u64(&mut self, i: u64) {
718 self.calls.push(HashCall::U64(i));
719 }
720 fn write_u128(&mut self, i: u128) {
721 self.calls.push(HashCall::U128(i));
722 }
723 fn write_usize(&mut self, i: usize) {
724 self.calls.push(HashCall::Usize(i));
725 }
726 fn write_i8(&mut self, i: i8) {
727 self.calls.push(HashCall::I8(i));
728 }
729 fn write_i16(&mut self, i: i16) {
730 self.calls.push(HashCall::I16(i));
731 }
732 fn write_i32(&mut self, i: i32) {
733 self.calls.push(HashCall::I32(i));
734 }
735 fn write_i64(&mut self, i: i64) {
736 self.calls.push(HashCall::I64(i));
737 }
738 fn write_i128(&mut self, i: i128) {
739 self.calls.push(HashCall::I128(i));
740 }
741 fn write_isize(&mut self, i: isize) {
742 self.calls.push(HashCall::Isize(i));
743 }
744 }
745
746 fn test_hash<T: PhfHash>(x: T) -> Vec<HashCall> {
747 let mut state = TestHasher { calls: Vec::new() };
748 x.phf_hash(&mut state);
749 state.calls
750 }
751
752 #[test]
753 fn byte_slices_are_hashed_efficiently() {
754 assert_eq!(
755 test_hash(&[1u8, 2, 3]),
756 [HashCall::U64(3), HashCall::Bytes([1, 2, 3].to_vec())]
757 );
758 assert_eq!(
759 test_hash(&[1i8, 2, 3]),
760 [HashCall::U64(3), HashCall::Bytes([1, 2, 3].to_vec())]
761 );
762 assert_eq!(
763 test_hash(&[false, true]),
764 [HashCall::U64(2), HashCall::Bytes([0, 1].to_vec())]
765 );
766 }
767
768 #[test]
769 fn slices_and_arrays_are_hashed_consistently() {
770 assert_eq!(test_hash(&[1u8, 2, 3]), test_hash(&[1u8, 2, 3][..]));
771 assert_eq!(test_hash(&[1u16, 2, 3]), test_hash(&[1u16, 2, 3][..]));
772 }
773
774 #[test]
775 fn array_reference_borrow_is_generic() {
776 fn assert_borrow<K, B: ?Sized>()
777 where
778 K: PhfBorrow<B>,
779 {
780 }
781
782 assert_borrow::<&[u32; 2], [u32; 2]>();
783 assert_borrow::<&[bool; 2], [bool; 2]>();
784 assert_borrow::<&[char; 2], [char; 2]>();
785 }
786
787 #[test]
788 fn tuple_eq_allows_shorter_reference_lifetimes() {
789 fn assert_ref_tuple<'a>(key: &(&'a str, &'a str)) -> bool
790 where
791 (&'static str, &'static str): PhfEq<(&'a str, &'a str)>,
792 {
793 ("a", "b").phf_eq(key)
794 }
795
796 fn assert_mixed_tuple<'a>(key: &(u32, &'a str)) -> bool
797 where
798 (u32, &'static str): PhfEq<(u32, &'a str)>,
799 {
800 (1, "a").phf_eq(key)
801 }
802
803 let a = String::from("a");
804 let b = String::from("b");
805 assert!(assert_ref_tuple(&(a.as_str(), b.as_str())));
806 assert!(assert_mixed_tuple(&(1, a.as_str())));
807 }
808
809 #[test]
810 fn variable_width_slice_elements_are_delimited() {
811 assert_ne!(test_hash(&["ab", "c"]), test_hash(&["a", "bc"]));
812
813 let key = 0;
814 let left = hash(&["ab", "c"], &key);
815 let right = hash(&["a", "bc"], &key);
816 assert!(
817 (left.g, left.f1, left.f2) != (right.g, right.f1, right.f2),
818 "different string arrays must not produce identical PHF hashes"
819 );
820 }
821}