about summary refs log tree commit diff
path: root/compiler/rustc_hashes
diff options
context:
space:
mode:
authorBen Kimock <kimockb@gmail.com>2025-02-15 15:18:19 -0500
committerBen Kimock <kimockb@gmail.com>2025-02-16 16:18:30 -0500
commit4cf21866e8f18449ea0c41ee1ba031c05419d94c (patch)
tree1bb6febab86e57c90e368461886364404a60cf0f /compiler/rustc_hashes
parent1d7cf0ff407beea447334c2784d39658e4be3ca0 (diff)
downloadrust-4cf21866e8f18449ea0c41ee1ba031c05419d94c.tar.gz
rust-4cf21866e8f18449ea0c41ee1ba031c05419d94c.zip
Move hashes from rustc_data_structure to rustc_hashes so they can be shared with rust-analyzer
Diffstat (limited to 'compiler/rustc_hashes')
-rw-r--r--compiler/rustc_hashes/Cargo.toml9
-rw-r--r--compiler/rustc_hashes/src/lib.rs131
2 files changed, 140 insertions, 0 deletions
diff --git a/compiler/rustc_hashes/Cargo.toml b/compiler/rustc_hashes/Cargo.toml
new file mode 100644
index 00000000000..c2bae2fe8cb
--- /dev/null
+++ b/compiler/rustc_hashes/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "rustc_hashes"
+version = "0.0.0"
+edition = "2021"
+
+[dependencies]
+# tidy-alphabetical-start
+rustc-stable-hash = { version = "0.1.0" }
+# tidy-alphabetical-end
diff --git a/compiler/rustc_hashes/src/lib.rs b/compiler/rustc_hashes/src/lib.rs
new file mode 100644
index 00000000000..3755caaaa29
--- /dev/null
+++ b/compiler/rustc_hashes/src/lib.rs
@@ -0,0 +1,131 @@
+//! rustc encodes a lot of hashes. If hashes are stored as `u64` or `u128`, a `derive(Encodable)`
+//! will apply varint encoding to the hashes, which is less efficient than directly encoding the 8
+//! or 16 bytes of the hash. And if that hash depends on the `StableCrateHash` (which most in rustc
+//! do), the varint encoding will make the number of bytes encoded fluctuate between compiler
+//! versions.
+//!
+//! The types in this module represent 64-bit or 128-bit hashes produced by a `StableHasher`.
+//! `Hash64` and `Hash128` expose some utility functions to encourage users to not extract the inner
+//! hash value as an integer type and accidentally apply varint encoding to it.
+//!
+//! In contrast with `Fingerprint`, users of these types cannot and should not attempt to construct
+//! and decompose these types into constituent pieces. The point of these types is only to
+//! connect the fact that they can only be produced by a `StableHasher` to their
+//! `Encode`/`Decode` impls.
+
+use std::fmt;
+use std::ops::BitXorAssign;
+
+use rustc_stable_hash::{FromStableHash, SipHasher128Hash as StableHasherHash};
+
+/// A `u64` but encoded with a fixed size; for hashes this encoding is more compact than `u64`.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
+pub struct Hash64 {
+    inner: u64,
+}
+
+impl Hash64 {
+    pub const ZERO: Hash64 = Hash64 { inner: 0 };
+
+    #[inline]
+    pub fn new(n: u64) -> Self {
+        Self { inner: n }
+    }
+
+    #[inline]
+    pub fn as_u64(self) -> u64 {
+        self.inner
+    }
+
+    #[inline]
+    pub fn wrapping_add(self, other: Self) -> Self {
+        Self { inner: self.inner.wrapping_add(other.inner) }
+    }
+}
+
+impl BitXorAssign<u64> for Hash64 {
+    #[inline]
+    fn bitxor_assign(&mut self, rhs: u64) {
+        self.inner ^= rhs;
+    }
+}
+
+impl FromStableHash for Hash64 {
+    type Hash = StableHasherHash;
+
+    #[inline]
+    fn from(StableHasherHash([_0, __1]): Self::Hash) -> Self {
+        Self { inner: _0 }
+    }
+}
+
+impl fmt::Debug for Hash64 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.inner.fmt(f)
+    }
+}
+
+impl fmt::LowerHex for Hash64 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::LowerHex::fmt(&self.inner, f)
+    }
+}
+
+/// A `u128` but encoded with a fixed size; for hashes this encoding is more compact than `u128`.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
+pub struct Hash128 {
+    inner: u128,
+}
+
+// We expect Hash128 to be well mixed. So there's no point in hashing both parts.
+//
+// This also allows using Hash128-containing types in UnHash-based hashmaps, which would otherwise
+// debug_assert! that we're hashing more than a single u64.
+impl std::hash::Hash for Hash128 {
+    fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
+        h.write_u64(self.truncate().as_u64());
+    }
+}
+
+impl Hash128 {
+    #[inline]
+    pub fn new(n: u128) -> Self {
+        Self { inner: n }
+    }
+
+    #[inline]
+    pub fn truncate(self) -> Hash64 {
+        Hash64 { inner: self.inner as u64 }
+    }
+
+    #[inline]
+    pub fn wrapping_add(self, other: Self) -> Self {
+        Self { inner: self.inner.wrapping_add(other.inner) }
+    }
+
+    #[inline]
+    pub fn as_u128(self) -> u128 {
+        self.inner
+    }
+}
+
+impl FromStableHash for Hash128 {
+    type Hash = StableHasherHash;
+
+    #[inline]
+    fn from(StableHasherHash([_0, _1]): Self::Hash) -> Self {
+        Self { inner: u128::from(_0) | (u128::from(_1) << 64) }
+    }
+}
+
+impl fmt::Debug for Hash128 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.inner.fmt(f)
+    }
+}
+
+impl fmt::LowerHex for Hash128 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::LowerHex::fmt(&self.inner, f)
+    }
+}