1use std::fmt::{self, Debug};
2use std::hash::{Hash, Hasher};
3use std::ops::Deref;
4use std::ptr;
56use crate::stable_hash::{StableHash, StableHashCtxt, StableHasher};
78mod private {
9#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for PrivateZst { }
#[automatically_derived]
impl ::core::clone::Clone for PrivateZst {
#[inline]
fn clone(&self) -> PrivateZst { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for PrivateZst { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for PrivateZst {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "PrivateZst")
}
}Debug)]
10pub struct PrivateZst;
11}
1213/// 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);
3738impl<'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]
48pub const fn new_unchecked(t: &'a T) -> Self {
49Interned(t, private::PrivateZst)
50 }
51}
5253impl<'a, T> Clonefor Interned<'a, T> {
54fn clone(&self) -> Self {
55*self56 }
57}
5859impl<'a, T> Copyfor Interned<'a, T> {}
6061impl<'a, T> Dereffor Interned<'a, T> {
62type Target = T;
6364#[inline]
65fn deref(&self) -> &T {
66self.0
67}
68}
6970impl<'a, T> PartialEqfor Interned<'a, T> {
71#[inline]
72fn eq(&self, other: &Self) -> bool {
73// Pointer equality implies equality, due to the uniqueness constraint.
74ptr::eq(self.0, other.0)
75 }
76}
7778impl<'a, T> Eqfor Interned<'a, T> {}
7980impl<'a, T> Hashfor Interned<'a, T> {
81#[inline]
82fn hash<H: Hasher>(&self, s: &mut H) {
83// Pointer hashing is sufficient.
84ptr::hash(self.0, s)
85 }
86}
8788impl<T> StableHashfor Interned<'_, T>
89where
90T: StableHash,
91{
92fn stable_hash<Hcx: StableHashCtxt>(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
93self.0.stable_hash(hcx, hasher);
94 }
95}
9697impl<T: Debug> Debugfor Interned<'_, T> {
98fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99self.0.fmt(f)
100 }
101}
102103#[cfg(test)]
104mod tests;