Skip to main content

metrics_util/
common.rs

1use std::fmt::Debug;
2use std::hash::{Hash, Hasher};
3
4use metrics::Key;
5use rapidhash::fast::RapidHasher;
6
7/// A type that can hash itself.
8///
9/// In high-performance use cases, an object can pre-hash itself, or memoize its hash value, when it
10/// is anticipated that an object will be hashed multiple times. Rather than the standard library
11/// `Hash` trait, `Hashable` exposes an interface that forces objects to hash themselves entirely,
12/// providing only the resulting 8-byte hash.
13///
14/// As a key may sometimes need to be rehashed, we need to ensure that the same hashing algorithm
15/// used to pre-generate the hash for this value is used when rehashing it.  All implementors must
16/// define the hashing algorithm used by specifying the `Hasher` associated type.
17///
18/// A default implementation, [`DefaultHashable`], is provided that utilizes the same hashing
19/// algorithm that [`Key`][metrics::Key] uses, which is high-performance.  This type can be used to
20/// satisfy `Hashable` so long as the type itself is already [`Hash`].
21pub trait Hashable: Hash {
22    /// The hasher implementation used internally.
23    type Hasher: Hasher + Default;
24
25    /// Generate the hash of this object.
26    #[inline]
27    fn hashable(&self) -> u64 {
28        let mut hasher = Self::Hasher::default();
29        self.hash(&mut hasher);
30        hasher.finish()
31    }
32}
33
34impl Hashable for Key {
35    type Hasher = KeyHasher;
36
37    #[inline]
38    fn hashable(&self) -> u64 {
39        self.get_hash()
40    }
41}
42
43/// A no-op hasher for pre-hashed [`Key`][metrics::Key] types.
44///
45/// This hasher is designed for use with [`Key`][metrics::Key], which pre-computes its hash at
46/// construction time. When `Key::hash()` is called, it writes the pre-computed hash via
47/// `write_u64()`, and `finish()` simply returns that value.
48///
49/// This ensures that `HashMap<Key, V, BuildHasherDefault<KeyHasher>>` lookups work correctly
50/// when using raw_entry APIs with pre-computed hashes.
51///
52/// # Panics
53///
54/// Panics if `finish()` is called without first calling `write_u64()`, or if any write method
55/// other than `write_u64()` is called. This hasher is specifically for pre-hashed keys only.
56#[derive(Debug, Default)]
57pub struct KeyHasher {
58    hash: Option<u64>,
59}
60
61impl Hasher for KeyHasher {
62    #[inline(always)]
63    fn finish(&self) -> u64 {
64        self.hash.expect("KeyHasher::finish() called without write_u64(); KeyHasher is only for pre-hashed Key types")
65    }
66
67    fn write(&mut self, _bytes: &[u8]) {
68        panic!("KeyHasher::write() called; KeyHasher only supports write_u64() for pre-hashed Key types");
69    }
70
71    #[inline(always)]
72    fn write_u64(&mut self, i: u64) {
73        self.hash = Some(i);
74    }
75}
76
77/// A wrapper type that provides `Hashable` for any type that is `Hash`.
78///
79/// As part of using [`Registry`][crate::registry::Registry], the chosen key type must implement
80/// [`Hashable`].  For use cases where performance is not the utmost concern and there is no desire
81/// to deal with pre-hashing keys, `DefaultHashable` can be used to wrap the key type and provide
82/// the implementation of `Hashable` so long as `H` itself is `Hash`.
83#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
84pub struct DefaultHashable<H: Hash>(pub H);
85
86impl<H: Hash> Hashable for DefaultHashable<H> {
87    type Hasher = RapidHasher<'static>;
88
89    fn hashable(&self) -> u64 {
90        let mut hasher = RapidHasher::default();
91        self.hash(&mut hasher);
92        hasher.finish()
93    }
94}