@@ -104,57 +104,10 @@ impl<T: Clone + ?Sized> Leak<T> for Cow<'static, T> {
104
104
}
105
105
}
106
106
107
- /// A thread-safe interner which can be used to create [`Interned<T>`] from `&T`
108
- ///
109
- /// For details on interning, see [the module level docs](self).
110
- ///
111
- /// The implementation ensures that two equal values return two equal [`Interned<T>`] values.
112
- pub struct Interner < T : ?Sized + ' static > ( OnceLock < RwLock < HashSet < & ' static T > > > ) ;
113
-
114
- impl < T : ?Sized > Interner < T > {
115
- /// Creates a new empty interner
116
- pub const fn new ( ) -> Self {
117
- Self ( OnceLock :: new ( ) )
118
- }
119
- }
120
-
121
- impl < T : Hash + Eq + ?Sized > Interner < T > {
122
- /// Return the [`Interned<T>`] corresponding to `value`.
123
- ///
124
- /// If it is called the first time for `value`, it will possibly leak the value and return an
125
- /// [`Interned<T>`] using the obtained static reference. Subsequent calls for the same `value`
126
- /// will return [`Interned<T>`] using the same static reference.
127
- pub fn intern < Q : Leak < T > > ( & self , value : Q ) -> Interned < T > {
128
- let lock = self . 0 . get_or_init ( Default :: default) ;
129
- {
130
- let set = lock. read ( ) . unwrap_or_else ( PoisonError :: into_inner) ;
131
- if let Some ( value) = set. get ( value. borrow ( ) ) {
132
- return Interned ( * value) ;
133
- }
134
- }
135
- {
136
- let mut set = lock. write ( ) . unwrap_or_else ( PoisonError :: into_inner) ;
137
- if let Some ( value) = set. get ( value. borrow ( ) ) {
138
- Interned ( * value)
139
- } else {
140
- let leaked = value. leak ( ) ;
141
- set. insert ( leaked) ;
142
- Interned ( leaked)
143
- }
144
- }
145
- }
146
- }
147
-
148
- impl < T : ?Sized > Default for Interner < T > {
149
- fn default ( ) -> Self {
150
- Self :: new ( )
151
- }
152
- }
153
-
154
107
/// A type that can provide static references to equal values.
155
108
pub trait StaticRef {
156
109
/// Returns a static reference to a value equal to `self`, if possible.
157
- /// This method is used by [`OptimizedInterner ::intern`] to optimize the interning process.
110
+ /// This method is used by [`Interner ::intern`] to optimize the interning process.
158
111
///
159
112
/// # Invariant
160
113
///
@@ -181,37 +134,66 @@ pub trait StaticRef {
181
134
/// }
182
135
/// }
183
136
/// ```
184
- fn static_ref ( & self ) -> Option < & ' static Self > ;
137
+ ///
138
+ /// # Provided implementation
139
+ ///
140
+ /// The provided implementation always returns `None`.
141
+ fn static_ref ( & self ) -> Option < & ' static Self > {
142
+ None
143
+ }
185
144
}
186
145
187
- /// An optimized [`Interner`] for types that implement [`StaticRef`].
188
- pub struct OptimizedInterner < T : ?Sized + ' static > ( Interner < T > ) ;
146
+ impl StaticRef for str { }
147
+
148
+ /// A thread-safe interner which can be used to create [`Interned<T>`] from `&T`
149
+ ///
150
+ /// For details on interning, see [the module level docs](self).
151
+ ///
152
+ /// The implementation ensures that two equal values return two equal [`Interned<T>`] values.
153
+ ///
154
+ /// To use an [`Interner<T>`], `T` must implement [`StaticRef`], [`Hash`] and [`Eq`].
155
+ pub struct Interner < T : ?Sized + ' static > ( OnceLock < RwLock < HashSet < & ' static T > > > ) ;
189
156
190
- impl < T : ?Sized > OptimizedInterner < T > {
157
+ impl < T : ?Sized > Interner < T > {
191
158
/// Creates a new empty interner
192
159
pub const fn new ( ) -> Self {
193
- Self ( Interner :: new ( ) )
160
+ Self ( OnceLock :: new ( ) )
194
161
}
195
162
}
196
163
197
- impl < T : StaticRef + Hash + Eq + ?Sized > OptimizedInterner < T > {
164
+ impl < T : StaticRef + Hash + Eq + ?Sized > Interner < T > {
198
165
/// Return the [`Interned<T>`] corresponding to `value`.
199
166
///
200
167
/// If it is called the first time for `value`, it will possibly leak the value and return an
201
168
/// [`Interned<T>`] using the obtained static reference. Subsequent calls for the same `value`
202
169
/// will return [`Interned<T>`] using the same static reference.
203
170
///
204
- /// Compared to [`Interner::intern`], this uses [`StaticRef::static_ref`] to short-circuit
205
- /// the interning process.
171
+ /// This uses [`StaticRef::static_ref`] to short-circuit the interning process.
206
172
pub fn intern < Q : Leak < T > > ( & self , value : Q ) -> Interned < T > {
207
173
if let Some ( value) = value. borrow ( ) . static_ref ( ) {
208
174
return Interned ( value) ;
209
175
}
210
- self . 0 . intern ( value)
176
+ let lock = self . 0 . get_or_init ( Default :: default) ;
177
+ {
178
+ let set = lock. read ( ) . unwrap_or_else ( PoisonError :: into_inner) ;
179
+ if let Some ( value) = set. get ( value. borrow ( ) ) {
180
+ return Interned ( * value) ;
181
+ }
182
+ }
183
+ {
184
+ let mut set = lock. write ( ) . unwrap_or_else ( PoisonError :: into_inner) ;
185
+ if let Some ( value) = set. get ( value. borrow ( ) ) {
186
+ Interned ( * value)
187
+ } else {
188
+ let leaked = value. leak ( ) ;
189
+ set. insert ( leaked) ;
190
+ Interned ( leaked)
191
+ }
192
+ }
211
193
}
212
194
}
213
195
214
- impl < T : ?Sized > Default for OptimizedInterner < T > {
196
+ impl < T : ?Sized > Default for Interner < T > {
215
197
fn default ( ) -> Self {
216
198
Self :: new ( )
217
199
}
@@ -224,33 +206,48 @@ mod tests {
224
206
hash:: { Hash , Hasher } ,
225
207
} ;
226
208
227
- use crate :: intern:: { Interned , Interner , Leak } ;
209
+ use crate :: intern:: { Interned , Interner , Leak , StaticRef } ;
228
210
229
211
#[ test]
230
212
fn zero_sized_type ( ) {
231
213
#[ derive( PartialEq , Eq , Hash , Debug ) ]
232
214
pub struct A ;
233
215
216
+ impl StaticRef for A {
217
+ fn static_ref ( & self ) -> Option < & ' static Self > {
218
+ Some ( & A )
219
+ }
220
+ }
221
+
234
222
impl Leak < A > for A {
235
223
fn leak ( self ) -> & ' static Self {
236
224
& A
237
225
}
238
226
}
239
227
240
228
let interner = Interner :: default ( ) ;
241
- let x = interner. intern ( & A ) ;
242
- let y = interner. intern ( & A ) ;
229
+ let x = interner. intern ( A ) ;
230
+ let y = interner. intern ( A ) ;
243
231
assert_eq ! ( x, y) ;
244
232
}
245
233
246
234
#[ test]
247
235
fn fieldless_enum ( ) {
248
- #[ derive( PartialEq , Eq , Hash , Debug ) ]
236
+ #[ derive( PartialEq , Eq , Hash , Debug , Clone ) ]
249
237
pub enum A {
250
238
X ,
251
239
Y ,
252
240
}
253
241
242
+ impl StaticRef for A {
243
+ fn static_ref ( & self ) -> Option < & ' static Self > {
244
+ Some ( match self {
245
+ A :: X => & A :: X ,
246
+ A :: Y => & A :: Y ,
247
+ } )
248
+ }
249
+ }
250
+
254
251
impl Leak < A > for A {
255
252
fn leak ( self ) -> & ' static Self {
256
253
match self {
0 commit comments