1- use std:: cmp:: Ordering ;
21use std:: fmt:: { self , Debug } ;
32use std:: hash:: { Hash , Hasher } ;
43use std:: ops:: Deref ;
@@ -11,26 +10,40 @@ mod private {
1110 pub struct PrivateZst ;
1211}
1312
14- /// A reference to a value that is interned, and is known to be unique.
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.
1516///
16- /// Note that it is possible to have a `T` and a `Interned<T>` that are (or
17- /// refer to) equal but different values. But if you have two different
18- /// `Interned<T>`s, they both refer to the same value, at a single location in
19- /// memory. This means that equality and hashing can be done on the value's
20- /// address rather than the value's contents, which can improve performance.
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.)
2122///
22- /// The `PrivateZst` field means you can pattern match with `Interned(v, _)`
23- /// but you can only construct a `Interned` with `new_unchecked`, and not
24- /// directly.
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.
2535#[ rustc_pass_by_value]
2636pub struct Interned < ' a , T > ( pub & ' a T , pub private:: PrivateZst ) ;
2737
2838impl < ' a , T > Interned < ' a , T > {
29- /// Create a new `Interned` value. The value referred to *must* be interned
30- /// and thus be unique, and it *must* remain unique in the future. This
31- /// function has `_unchecked` in the name but is not `unsafe`, because if
32- /// the uniqueness condition is violated condition it will cause incorrect
33- /// behaviour but will not affect memory safety.
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.
3447 #[ inline]
3548 pub const fn new_unchecked ( t : & ' a T ) -> Self {
3649 Interned ( t, private:: PrivateZst )
@@ -64,41 +77,10 @@ impl<'a, T> PartialEq for Interned<'a, T> {
6477
6578impl < ' a , T > Eq for Interned < ' a , T > { }
6679
67- impl < ' a , T : PartialOrd > PartialOrd for Interned < ' a , T > {
68- fn partial_cmp ( & self , other : & Interned < ' a , T > ) -> Option < Ordering > {
69- // Pointer equality implies equality, due to the uniqueness constraint,
70- // but the contents must be compared otherwise.
71- if ptr:: eq ( self . 0 , other. 0 ) {
72- Some ( Ordering :: Equal )
73- } else {
74- let res = self . 0 . partial_cmp ( other. 0 ) ;
75- debug_assert_ne ! ( res, Some ( Ordering :: Equal ) ) ;
76- res
77- }
78- }
79- }
80-
81- impl < ' a , T : Ord > Ord for Interned < ' a , T > {
82- fn cmp ( & self , other : & Interned < ' a , T > ) -> Ordering {
83- // Pointer equality implies equality, due to the uniqueness constraint,
84- // but the contents must be compared otherwise.
85- if ptr:: eq ( self . 0 , other. 0 ) {
86- Ordering :: Equal
87- } else {
88- let res = self . 0 . cmp ( other. 0 ) ;
89- debug_assert_ne ! ( res, Ordering :: Equal ) ;
90- res
91- }
92- }
93- }
94-
95- impl < ' a , T > Hash for Interned < ' a , T >
96- where
97- T : Hash ,
98- {
80+ impl < ' a , T > Hash for Interned < ' a , T > {
9981 #[ inline]
10082 fn hash < H : Hasher > ( & self , s : & mut H ) {
101- // Pointer hashing is sufficient, due to the uniqueness constraint .
83+ // Pointer hashing is sufficient.
10284 ptr:: hash ( self . 0 , s)
10385 }
10486}
0 commit comments