rustc_data_structures/intern.rs
1use std::fmt::{self, Debug};
2use std::hash::{Hash, Hasher};
3use std::ops::Deref;
4use std::ptr;
5
6use crate::stable_hash::{StableHash, StableHashCtxt, StableHasher};
7
8mod private {
9 #[derive(Clone, Copy, Debug)]
10 pub struct PrivateZst;
11}
12
13/// This type is a reference with one special behaviour: the reference pointer (i.e. the address of
14/// the value referred to) is used for equality and hashing, rather than the value's contents, as
15/// would occur with a vanilla reference. There are two cases when this is useful.
16///
17/// - Types where uniqueness is guaranteed. This is most commonly achieved via interning -- hence
18/// the name `Interned` -- though it may also be possible via other means. In this case, the use
19/// of `Interned` is primarily a performance optimization, because pointer equality/hashing gives
20/// the same results as value equality/hashing, but is faster. (The use of the `Interned` type
21/// also provides documentation about the interned-ness.)
22///
23/// Note that in this case it is possible to have a `T` and a `Interned<T>` that are (or refer
24/// to) equal but different values. But if you have two different `Interned<T>`s, they both refer
25/// to the same value, at a single location in memory.
26///
27/// - Types with identity, where distinct values should always be considered unequal, even if they
28/// have equal values. These are rare in Rust, but do occur sometimes. In this case, the use of
29/// `Interned` gives different behaviour, because pointer equality/hashing gives different result
30/// to value equality/hashing, and is also faster.
31///
32/// The `PrivateZst` field means you can pattern match with `Interned(v, _)` but you can only
33/// construct a `Interned` with `new_unchecked`, and not directly. This means that all creation
34/// points can be audited easily.
35#[rustc_pass_by_value]
36pub struct Interned<'a, T>(pub &'a T, pub private::PrivateZst);
37
38impl<'a, T> Interned<'a, T> {
39 /// Create a new `Interned` value. The value referred to *must* satisfy one of the following
40 /// two conditions.
41 /// - It must be unique and it must remain unique in the future.
42 /// - It must be of a type with "identity" such that distinct values should always be
43 /// considered unequal.
44 ///
45 /// This function has `_unchecked` in the name but is not `unsafe`, because if neither of these
46 /// conditions is met it will cause incorrect behaviour but will not affect memory safety.
47 #[inline]
48 pub const fn new_unchecked(t: &'a T) -> Self {
49 Interned(t, private::PrivateZst)
50 }
51}
52
53impl<'a, T> Clone for Interned<'a, T> {
54 fn clone(&self) -> Self {
55 *self
56 }
57}
58
59impl<'a, T> Copy for Interned<'a, T> {}
60
61impl<'a, T> Deref for Interned<'a, T> {
62 type Target = T;
63
64 #[inline]
65 fn deref(&self) -> &T {
66 self.0
67 }
68}
69
70impl<'a, T> PartialEq for Interned<'a, T> {
71 #[inline]
72 fn eq(&self, other: &Self) -> bool {
73 // Pointer equality implies equality, due to the uniqueness constraint.
74 ptr::eq(self.0, other.0)
75 }
76}
77
78impl<'a, T> Eq for Interned<'a, T> {}
79
80impl<'a, T> Hash for Interned<'a, T> {
81 #[inline]
82 fn hash<H: Hasher>(&self, s: &mut H) {
83 // Pointer hashing is sufficient.
84 ptr::hash(self.0, s)
85 }
86}
87
88impl<T> StableHash for Interned<'_, T>
89where
90 T: StableHash,
91{
92 fn stable_hash<Hcx: StableHashCtxt>(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
93 self.0.stable_hash(hcx, hasher);
94 }
95}
96
97impl<T: Debug> Debug for Interned<'_, T> {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 self.0.fmt(f)
100 }
101}
102
103#[cfg(test)]
104mod tests;