rustc_data_structures/
hashes.rs

1//! rustc encodes a lot of hashes. If hashes are stored as `u64` or `u128`, a `derive(Encodable)`
2//! will apply varint encoding to the hashes, which is less efficient than directly encoding the 8
3//! or 16 bytes of the hash.
4//!
5//! The types in this module represent 64-bit or 128-bit hashes produced by a `StableHasher`.
6//! `Hash64` and `Hash128` expose some utility functions to encourage users to not extract the inner
7//! hash value as an integer type and accidentally apply varint encoding to it.
8//!
9//! In contrast with `Fingerprint`, users of these types cannot and should not attempt to construct
10//! and decompose these types into constituent pieces. The point of these types is only to
11//! connect the fact that they can only be produced by a `StableHasher` to their
12//! `Encode`/`Decode` impls.
13
14use std::fmt;
15use std::ops::BitXorAssign;
16
17use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
18
19use crate::stable_hasher::{FromStableHash, StableHasherHash};
20
21#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
22pub struct Hash64 {
23    inner: u64,
24}
25
26impl Hash64 {
27    pub const ZERO: Hash64 = Hash64 { inner: 0 };
28
29    #[inline]
30    pub fn new(n: u64) -> Self {
31        Self { inner: n }
32    }
33
34    #[inline]
35    pub fn as_u64(self) -> u64 {
36        self.inner
37    }
38}
39
40impl BitXorAssign<u64> for Hash64 {
41    #[inline]
42    fn bitxor_assign(&mut self, rhs: u64) {
43        self.inner ^= rhs;
44    }
45}
46
47impl<S: Encoder> Encodable<S> for Hash64 {
48    #[inline]
49    fn encode(&self, s: &mut S) {
50        s.emit_raw_bytes(&self.inner.to_le_bytes());
51    }
52}
53
54impl<D: Decoder> Decodable<D> for Hash64 {
55    #[inline]
56    fn decode(d: &mut D) -> Self {
57        Self { inner: u64::from_le_bytes(d.read_raw_bytes(8).try_into().unwrap()) }
58    }
59}
60
61impl FromStableHash for Hash64 {
62    type Hash = StableHasherHash;
63
64    #[inline]
65    fn from(StableHasherHash([_0, __1]): Self::Hash) -> Self {
66        Self { inner: _0 }
67    }
68}
69
70impl fmt::Debug for Hash64 {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        self.inner.fmt(f)
73    }
74}
75
76impl fmt::LowerHex for Hash64 {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        fmt::LowerHex::fmt(&self.inner, f)
79    }
80}
81
82#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
83pub struct Hash128 {
84    inner: u128,
85}
86
87// We expect Hash128 to be well mixed. So there's no point in hashing both parts.
88//
89// This also allows using Hash128-containing types in UnHash-based hashmaps, which would otherwise
90// debug_assert! that we're hashing more than a single u64.
91impl std::hash::Hash for Hash128 {
92    fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
93        h.write_u64(self.truncate().as_u64());
94    }
95}
96
97impl Hash128 {
98    #[inline]
99    pub fn truncate(self) -> Hash64 {
100        Hash64 { inner: self.inner as u64 }
101    }
102
103    #[inline]
104    pub fn wrapping_add(self, other: Self) -> Self {
105        Self { inner: self.inner.wrapping_add(other.inner) }
106    }
107
108    #[inline]
109    pub fn as_u128(self) -> u128 {
110        self.inner
111    }
112}
113
114impl<S: Encoder> Encodable<S> for Hash128 {
115    #[inline]
116    fn encode(&self, s: &mut S) {
117        s.emit_raw_bytes(&self.inner.to_le_bytes());
118    }
119}
120
121impl<D: Decoder> Decodable<D> for Hash128 {
122    #[inline]
123    fn decode(d: &mut D) -> Self {
124        Self { inner: u128::from_le_bytes(d.read_raw_bytes(16).try_into().unwrap()) }
125    }
126}
127
128impl FromStableHash for Hash128 {
129    type Hash = StableHasherHash;
130
131    #[inline]
132    fn from(StableHasherHash([_0, _1]): Self::Hash) -> Self {
133        Self { inner: u128::from(_0) | (u128::from(_1) << 64) }
134    }
135}
136
137impl fmt::Debug for Hash128 {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        self.inner.fmt(f)
140    }
141}
142
143impl fmt::LowerHex for Hash128 {
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        fmt::LowerHex::fmt(&self.inner, f)
146    }
147}