1
1
#![doc = include_str!("../README.md")]
2
#![forbid(unsafe_code)]
3
#![warn(
4
    clippy::cargo,
5
    missing_docs,
6
    // clippy::missing_docs_in_private_items,
7
    clippy::pedantic,
8
    future_incompatible,
9
    rust_2018_idioms,
10
)]
11
#![allow(
12
    clippy::missing_errors_doc,
13
    clippy::option_if_let_else,
14
    clippy::module_name_repetitions
15
)]
16

            
17
use std::fmt::{Debug, Display};
18
use std::hash::{BuildHasher, Hash};
19
use std::ops::Deref;
20
use std::path::Path;
21

            
22
/// Global interning pools.
23
pub mod global;
24
mod pool;
25
/// Shared interning pools that have no global state.
26
pub mod shared;
27
#[cfg(test)]
28
mod tests;
29

            
30
use crate::pool::{PoolKindSealed, SharedData};
31

            
32
/// A kind of interning pool. Currently there are only two types of pools:
33
///
34
/// - Global, used through the [`global::StringPool`],
35
///   [`GlobalPath`](global::GlobalPath), and
36
///   [`GlobalBuffer`](global::GlobalBuffer) types.
37
/// - Shared, used through the [`StringPool`](shared::StringPool),
38
///   [`PathPool`](shared::PathPool), and [`BufferPool`](shared::BufferPool)
39
///   types.
40
pub trait PoolKind<S>: Clone + PartialEq + PoolKindSealed<S> {}
41

            
42
/// A type that ensures only one copy of each value exists in its pool, enabling
43
/// quicker lookups by not requiring full comparisons.
44
///
45
/// After all instances of a given [`Pooled`] are dropped, the underlying
46
/// storage is released.
47
///
48
/// This type's [`Hash`] implementation is different than the wrapped type's
49
/// hash implementation. This type avoids implementing `Borrow<T>` to prevent
50
/// using incompatible [`Hash`] implementations to look up values in
51
/// `HashMap`s/`HashSet`s where this type is
52
/// used as the key.
53
pub struct Pooled<P, S>(SharedData<P, S>)
54
where
55
    P: PoolKind<S>,
56
    S: BuildHasher;
57

            
58
impl<P, S> Pooled<P, S>
59
where
60
    P: PoolKind<S>,
61
    S: BuildHasher,
62
{
63
    /// Returns true if `this` and `other` point to the exact same instance of
64
    /// the value. Returns false if `this` and `other` are from different pools
65
    /// or if the index within the pool does not match.
66
    ///
67
    /// This function never compares the contents of the contained values.
68
    #[must_use]
69
11
    pub fn ptr_eq<P2, S2>(this: &Self, other: &Pooled<P2, S2>) -> bool
70
11
    where
71
11
        P: PartialEq<P2>,
72
11
        P2: PoolKind<S2>,
73
11
        S2: BuildHasher,
74
11
    {
75
11
        this.0 .0.pool == other.0 .0.pool && this.0 .0.index == other.0 .0.index
76
11
    }
77
}
78

            
79
impl<P, S> Clone for Pooled<P, S>
80
where
81
    P: PoolKind<S>,
82
    S: BuildHasher,
83
{
84
1127
    fn clone(&self) -> Self {
85
1127
        Self(self.0.clone())
86
1127
    }
87
}
88

            
89
impl<P, S> Hash for Pooled<P, S>
90
where
91
    P: PoolKind<S>,
92
    S: BuildHasher,
93
{
94
6
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
95
6
        self.0 .0.index.hash(state);
96
6
    }
97
}
98

            
99
impl<P, S> Eq for Pooled<P, S>
100
where
101
    P: PoolKind<S>,
102
    S: BuildHasher,
103
{
104
}
105

            
106
impl<PSelf, POther, SSelf, SOther, T> PartialEq<Pooled<POther, SOther>> for Pooled<PSelf, SSelf>
107
where
108
    PSelf: PoolKind<SSelf, Pooled = T> + PartialEq<POther>,
109
    POther: PoolKind<SOther, Pooled = T>,
110
    T: PartialEq,
111
    SSelf: BuildHasher,
112
    SOther: BuildHasher,
113
{
114
26
    fn eq(&self, other: &Pooled<POther, SOther>) -> bool {
115
26
        if self.0 .0.pool == other.0 .0.pool {
116
13
            self.0 .0.index == other.0 .0.index
117
        } else {
118
13
            **self == **other
119
        }
120
26
    }
121
}
122

            
123
impl<P, S> Display for Pooled<P, S>
124
where
125
    P: PoolKind<S>,
126
    P::Pooled: Display,
127
    S: BuildHasher,
128
{
129
1
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130
1
        Display::fmt(&**self, f)
131
1
    }
132
}
133

            
134
impl<P, S> Debug for Pooled<P, S>
135
where
136
    P: PoolKind<S>,
137
    P::Pooled: Debug,
138
    S: BuildHasher,
139
{
140
2
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141
2
        Debug::fmt(&**self, f)
142
2
    }
143
}
144

            
145
impl<P, S> Deref for Pooled<P, S>
146
where
147
    P: PoolKind<S>,
148
    S: BuildHasher,
149
{
150
    type Target = P::Pooled;
151

            
152
40
    fn deref(&self) -> &Self::Target {
153
40
        &self.0 .0.value
154
40
    }
155
}
156

            
157
impl<P, S> PartialEq<str> for Pooled<P, S>
158
where
159
    P: PoolKind<S, Pooled = Box<str>>,
160
    S: BuildHasher,
161
{
162
4
    fn eq(&self, other: &str) -> bool {
163
4
        &***self == other
164
4
    }
165
}
166

            
167
impl<'a, P, S> PartialEq<&'a str> for Pooled<P, S>
168
where
169
    P: PoolKind<S, Pooled = Box<str>>,
170
    S: BuildHasher,
171
{
172
2
    fn eq(&self, other: &&'a str) -> bool {
173
2
        self == *other
174
2
    }
175
}
176

            
177
impl<P, S> PartialEq<[u8]> for Pooled<P, S>
178
where
179
    P: PoolKind<S, Pooled = Box<[u8]>>,
180
    S: BuildHasher,
181
{
182
4
    fn eq(&self, other: &[u8]) -> bool {
183
4
        &***self == other
184
4
    }
185
}
186

            
187
impl<'a, P, S> PartialEq<&'a [u8]> for Pooled<P, S>
188
where
189
    P: PoolKind<S, Pooled = Box<[u8]>>,
190
    S: BuildHasher,
191
{
192
2
    fn eq(&self, other: &&'a [u8]) -> bool {
193
2
        self == *other
194
2
    }
195
}
196

            
197
impl<P, S> PartialEq<Path> for Pooled<P, S>
198
where
199
    P: PoolKind<S, Pooled = Box<Path>>,
200
    S: BuildHasher,
201
{
202
3
    fn eq(&self, other: &Path) -> bool {
203
3
        &***self == other
204
3
    }
205
}
206

            
207
impl<'a, P, S> PartialEq<&'a Path> for Pooled<P, S>
208
where
209
    P: PoolKind<S, Pooled = Box<Path>>,
210
    S: BuildHasher,
211
{
212
2
    fn eq(&self, other: &&'a Path) -> bool {
213
2
        self == *other
214
2
    }
215
}
216

            
217
impl<P, S> Ord for Pooled<P, S>
218
where
219
    P: PoolKind<S>,
220
    S: BuildHasher,
221
{
222
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
223
        (**self).cmp(&**other)
224
    }
225
}
226

            
227
impl<P, S> PartialOrd for Pooled<P, S>
228
where
229
    P: PoolKind<S>,
230
    S: BuildHasher,
231
{
232
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
233
        Some(self.cmp(other))
234
    }
235
}
236

            
237
impl<P, S> PartialOrd<str> for Pooled<P, S>
238
where
239
    P: PoolKind<S, Pooled = Box<str>>,
240
    S: BuildHasher,
241
{
242
    fn partial_cmp(&self, other: &str) -> Option<std::cmp::Ordering> {
243
        (**self).as_ref().partial_cmp(other)
244
    }
245
}
246

            
247
impl<'a, P, S> PartialOrd<&'a str> for Pooled<P, S>
248
where
249
    P: PoolKind<S, Pooled = Box<str>>,
250
    S: BuildHasher,
251
{
252
    fn partial_cmp(&self, other: &&'a str) -> Option<std::cmp::Ordering> {
253
        self.partial_cmp(*other)
254
    }
255
}
256

            
257
impl<P, S> PartialOrd<Path> for Pooled<P, S>
258
where
259
    P: PoolKind<S, Pooled = Box<Path>>,
260
    S: BuildHasher,
261
{
262
    fn partial_cmp(&self, other: &Path) -> Option<std::cmp::Ordering> {
263
        (**self).as_ref().partial_cmp(other)
264
    }
265
}
266

            
267
impl<'a, P, S> PartialOrd<&'a Path> for Pooled<P, S>
268
where
269
    P: PoolKind<S, Pooled = Box<Path>>,
270
    S: BuildHasher,
271
{
272
    fn partial_cmp(&self, other: &&'a Path) -> Option<std::cmp::Ordering> {
273
        self.partial_cmp(*other)
274
    }
275
}
276

            
277
impl<P, S> PartialOrd<[u8]> for Pooled<P, S>
278
where
279
    P: PoolKind<S, Pooled = Box<[u8]>>,
280
    S: BuildHasher,
281
{
282
    fn partial_cmp(&self, other: &[u8]) -> Option<std::cmp::Ordering> {
283
        (**self).as_ref().partial_cmp(other)
284
    }
285
}
286

            
287
impl<'a, P, S> PartialOrd<&'a [u8]> for Pooled<P, S>
288
where
289
    P: PoolKind<S, Pooled = Box<[u8]>>,
290
    S: BuildHasher,
291
{
292
    fn partial_cmp(&self, other: &&'a [u8]) -> Option<std::cmp::Ordering> {
293
        self.partial_cmp(*other)
294
    }
295
}