rspack_allocative/
key.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is dual-licensed under either the MIT license found in the
5 * LICENSE-MIT file in the root directory of this source tree or the Apache
6 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
7 * of this source tree. You may select, at your option, one of the
8 * above-listed licenses.
9 */
10
11use std::any;
12use std::cmp::Ordering;
13use std::hash::Hash;
14use std::hash::Hasher;
15use std::ops::Deref;
16
17/// Hashed string, which is a key while descending into a tree (e.g. type name or field name).
18#[derive(Clone, Eq, PartialEq, Debug)]
19pub struct Key {
20    hash: u64,
21    s: &'static str,
22}
23
24impl PartialOrd for Key {
25    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
26        Some(self.cmp(other))
27    }
28}
29
30impl Ord for Key {
31    fn cmp(&self, other: &Self) -> Ordering {
32        self.s.cmp(other.s)
33    }
34}
35
36#[allow(clippy::derived_hash_with_manual_eq)]
37impl Hash for Key {
38    fn hash<H: Hasher>(&self, state: &mut H) {
39        self.hash.hash(state);
40    }
41}
42
43impl Deref for Key {
44    type Target = str;
45
46    fn deref(&self) -> &str {
47        self.s
48    }
49}
50
51impl Key {
52    /// Must be identical to `allocative_derive::hash`.
53    const fn hash(s: &str) -> u64 {
54        let mut hash = 0xcbf29ce484222325;
55        let mut i = 0;
56        while i < s.len() {
57            let b = s.as_bytes()[i];
58            hash ^= b as u64;
59            hash = hash.wrapping_mul(0x100000001b3);
60            i += 1;
61        }
62        hash
63    }
64
65    /// Compute hash.
66    pub const fn new(s: &'static str) -> Key {
67        let hash = Self::hash(s);
68        Key::new_unchecked(hash, s)
69    }
70
71    pub const fn new_unchecked(hash: u64, s: &'static str) -> Key {
72        Key { hash, s }
73    }
74
75    pub fn for_type_name<T: ?Sized>() -> Key {
76        // Compute hash at compile time.
77        #[cfg(rust_nightly)]
78        return Key {
79            hash: AllocativeKeyForType::<T>::KEY.hash,
80            s: AllocativeKeyForType::<T>::KEY.s,
81        };
82        // Hope optimizer folds this to constant (it doesn't for long type names).
83        #[cfg(not(rust_nightly))]
84        return Key::new(any::type_name::<T>());
85    }
86}
87
88#[cfg(rust_nightly)]
89struct AllocativeKeyForType<T: ?Sized>(std::marker::PhantomData<fn(&T)>);
90
91#[cfg(rust_nightly)]
92impl<T: ?Sized> AllocativeKeyForType<T> {
93    /// Force compute it at compile time. Const fn does not guarantee that.
94    pub const KEY: Key = Key::new(any::type_name::<T>());
95}