1
+ //! This module helps you efficiently store and retrieve values using interning.
2
+ //!
3
+ //! Interning is a neat trick that keeps only one copy of identical values, saving memory
4
+ //! and making comparisons super fast. Here, we provide the `Interned<T>` struct and the `Internable` trait
5
+ //! to make interning easy for different data types.
6
+ //!
7
+ //! The `Interner` struct handles caching for common types like `String`, `PathBuf`, and `Vec<String>`,
8
+ //! while the `Cache` struct acts as a write-once storage for linking computation steps with their results.
9
+ //!
10
+ //! # Thread Safety
11
+ //!
12
+ //! We use `Mutex` to make sure interning and retrieval are thread-safe. But keep in mind—once a value is
13
+ //! interned, it sticks around for the entire lifetime of the program.
14
+
1
15
use std:: any:: { Any , TypeId } ;
2
16
use std:: borrow:: Borrow ;
3
17
use std:: cell:: RefCell ;
@@ -12,6 +26,9 @@ use std::{fmt, mem};
12
26
13
27
use crate :: core:: builder:: Step ;
14
28
29
+ /// Represents an interned value of type `T`, allowing for efficient comparisons and retrieval.
30
+ ///
31
+ /// This struct stores a unique index referencing the interned value within an internal cache.
15
32
pub struct Interned < T > ( usize , PhantomData < * const T > ) ;
16
33
17
34
impl < T : Internable + Default > Default for Interned < T > {
@@ -111,6 +128,10 @@ impl<T: Internable + Ord> Ord for Interned<T> {
111
128
}
112
129
}
113
130
131
+ /// A structure for managing the interning of values of type `T`.
132
+ ///
133
+ /// `TyIntern<T>` maintains a mapping between values and their interned representations,
134
+ /// ensuring that duplicate values are not stored multiple times.
114
135
struct TyIntern < T : Clone + Eq > {
115
136
items : Vec < T > ,
116
137
set : HashMap < T , Interned < T > > ,
@@ -123,6 +144,9 @@ impl<T: Hash + Clone + Eq> Default for TyIntern<T> {
123
144
}
124
145
125
146
impl < T : Hash + Clone + Eq > TyIntern < T > {
147
+ /// Interns a borrowed value, ensuring it is stored uniquely.
148
+ ///
149
+ /// If the value has been previously interned, the same `Interned<T>` instance is returned.
126
150
fn intern_borrow < B > ( & mut self , item : & B ) -> Interned < T >
127
151
where
128
152
B : Eq + Hash + ToOwned < Owned = T > + ?Sized ,
@@ -138,6 +162,9 @@ impl<T: Hash + Clone + Eq> TyIntern<T> {
138
162
interned
139
163
}
140
164
165
+ /// Interns an owned value, storing it uniquely.
166
+ ///
167
+ /// If the value has been previously interned, the existing `Interned<T>` is returned.
141
168
fn intern ( & mut self , item : T ) -> Interned < T > {
142
169
if let Some ( i) = self . set . get ( & item) {
143
170
return * i;
@@ -148,18 +175,27 @@ impl<T: Hash + Clone + Eq> TyIntern<T> {
148
175
interned
149
176
}
150
177
178
+ /// Retrieves a reference to the interned value associated with the given `Interned<T>` instance.
151
179
fn get ( & self , i : Interned < T > ) -> & T {
152
180
& self . items [ i. 0 ]
153
181
}
154
182
}
155
183
184
+ /// A global interner for managing interned values of common types.
185
+ ///
186
+ /// This structure maintains caches for `String`, `PathBuf`, and `Vec<String>`, ensuring efficient storage
187
+ /// and retrieval of frequently used values.
156
188
#[ derive( Default ) ]
157
189
pub struct Interner {
158
190
strs : Mutex < TyIntern < String > > ,
159
191
paths : Mutex < TyIntern < PathBuf > > ,
160
192
lists : Mutex < TyIntern < Vec < String > > > ,
161
193
}
162
194
195
+ /// Defines the behavior required for a type to be internable.
196
+ ///
197
+ /// Types implementing this trait must provide access to a static cache and define an `intern` method
198
+ /// that ensures values are stored uniquely.
163
199
trait Internable : Clone + Eq + Hash + ' static {
164
200
fn intern_cache ( ) -> & ' static Mutex < TyIntern < Self > > ;
165
201
@@ -187,11 +223,15 @@ impl Internable for Vec<String> {
187
223
}
188
224
189
225
impl Interner {
226
+ /// Interns a string reference, ensuring it is stored uniquely.
227
+ ///
228
+ /// If the string has been previously interned, the same `Interned<String>` instance is returned.
190
229
pub fn intern_str ( & self , s : & str ) -> Interned < String > {
191
230
self . strs . lock ( ) . unwrap ( ) . intern_borrow ( s)
192
231
}
193
232
}
194
233
234
+ /// A global instance of `Interner` that caches common interned values.
195
235
pub static INTERNER : LazyLock < Interner > = LazyLock :: new ( Interner :: default) ;
196
236
197
237
/// This is essentially a `HashMap` which allows storing any type in its input and
@@ -209,10 +249,12 @@ pub struct Cache(
209
249
) ;
210
250
211
251
impl Cache {
252
+ /// Creates a new empty cache.
212
253
pub fn new ( ) -> Cache {
213
254
Cache ( RefCell :: new ( HashMap :: new ( ) ) )
214
255
}
215
256
257
+ /// Stores the result of a computation step in the cache.
216
258
pub fn put < S : Step > ( & self , step : S , value : S :: Output ) {
217
259
let mut cache = self . 0 . borrow_mut ( ) ;
218
260
let type_id = TypeId :: of :: < S > ( ) ;
@@ -225,6 +267,7 @@ impl Cache {
225
267
stepcache. insert ( step, value) ;
226
268
}
227
269
270
+ /// Retrieves a cached result for the given step, if available.
228
271
pub fn get < S : Step > ( & self , step : & S ) -> Option < S :: Output > {
229
272
let mut cache = self . 0 . borrow_mut ( ) ;
230
273
let type_id = TypeId :: of :: < S > ( ) ;
@@ -255,3 +298,6 @@ impl Cache {
255
298
self . 0 . borrow ( ) . contains_key ( & TypeId :: of :: < S > ( ) )
256
299
}
257
300
}
301
+
302
+ #[ cfg( test) ]
303
+ mod tests;
0 commit comments