1#![warn(clippy::pedantic, rust_2018_idioms, missing_docs)]
7
8use std::{
9 collections::hash_map::RandomState,
10 fmt::Debug,
11 hash::{BuildHasher, Hash, Hasher as _},
12 marker::PhantomData,
13 mem::{replace, ManuallyDrop},
14};
15
16use hashbrown::{hash_table::Entry as RawEntry, HashTable};
17use mut_guard::MutGuard;
18
19#[doc(hidden)]
20pub mod doc_examples;
21pub mod entry;
22#[doc(hidden)]
23pub mod iter;
24mod mut_guard;
25#[cfg(feature = "serde")]
26mod serde;
27#[cfg(feature = "typesize")]
28mod typesize;
29
30#[cfg(feature = "serde")]
31pub use serde::serialize_as_map;
32
33fn hash_one<S: BuildHasher, H: Hash>(build_hasher: &S, val: H) -> u64 {
34 let mut hasher = build_hasher.build_hasher();
35 val.hash(&mut hasher);
36 hasher.finish()
37}
38
39pub trait ExtractKey<K: Hash + Eq> {
45 fn extract_key(&self) -> &K;
47}
48
49pub struct ExtractMap<K, V, S = RandomState> {
59 table: hashbrown::HashTable<V>,
61 phantom: PhantomData<K>,
62 build_hasher: S,
63}
64
65impl<K, V, S: Default> Default for ExtractMap<K, V, S> {
66 fn default() -> Self {
67 Self::with_hasher(S::default())
68 }
69}
70
71impl<K, V> ExtractMap<K, V, RandomState> {
72 #[must_use]
74 pub fn new() -> Self {
75 Self::with_hasher(RandomState::new())
76 }
77
78 #[must_use]
91 pub fn with_capacity(capacity: usize) -> Self {
92 Self::with_capacity_and_hasher(capacity, RandomState::new())
93 }
94}
95
96impl<K, V, S> ExtractMap<K, V, S> {
97 #[must_use]
99 pub fn with_hasher(hash_builder: S) -> Self {
100 Self {
101 table: HashTable::new(),
102 phantom: PhantomData,
103 build_hasher: hash_builder,
104 }
105 }
106
107 #[must_use]
122 pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self {
123 Self {
124 table: HashTable::with_capacity(capacity),
125 phantom: PhantomData,
126 build_hasher: hash_builder,
127 }
128 }
129}
130
131impl<K, V, S> ExtractMap<K, V, S>
132where
133 K: Hash + Eq,
134 V: ExtractKey<K>,
135 S: BuildHasher,
136{
137 fn raw_entry(&mut self, key: &K) -> RawEntry<'_, V> {
138 self.table.entry(
139 hash_one(&self.build_hasher, key),
140 |v| key == v.extract_key(),
141 |v| hash_one(&self.build_hasher, v.extract_key()),
142 )
143 }
144
145 pub fn insert(&mut self, value: V) -> Option<V> {
161 match self.raw_entry(value.extract_key()) {
162 RawEntry::Occupied(entry) => Some(replace(entry.into_mut(), value)),
163 RawEntry::Vacant(entry) => {
164 entry.insert(value);
165 None
166 }
167 }
168 }
169
170 pub fn remove(&mut self, key: &K) -> Option<V> {
185 let hash = hash_one(&self.build_hasher, key);
186 let entry = self.table.find_entry(hash, |v| key == v.extract_key());
187
188 match entry {
189 Ok(entry) => Some(entry.remove().0),
190 Err(_) => None,
191 }
192 }
193
194 #[must_use]
196 pub fn contains_key(&self, key: &K) -> bool {
197 self.get(key).is_some()
198 }
199
200 #[must_use]
202 pub fn get(&self, key: &K) -> Option<&V> {
203 let hash = hash_one(&self.build_hasher, key);
204 self.table.find(hash, |v| key == v.extract_key())
205 }
206
207 #[must_use]
212 pub fn get_mut<'a>(&'a mut self, key: &K) -> Option<MutGuard<'a, K, V, S>> {
213 let value = self.remove(key)?;
214 Some(MutGuard {
215 value: ManuallyDrop::new(value),
216 map: self,
217 })
218 }
219}
220
221impl<K, V, S> ExtractMap<K, V, S> {
222 #[must_use]
224 pub fn capacity(&self) -> usize {
225 self.table.capacity()
226 }
227
228 #[must_use]
230 pub fn len(&self) -> usize {
231 self.table.len()
232 }
233
234 #[must_use]
236 pub fn is_empty(&self) -> bool {
237 self.table.is_empty()
238 }
239
240 pub fn allocation_size(&self) -> usize {
245 self.table.allocation_size()
246 }
247
248 pub fn iter(&self) -> iter::Iter<'_, V> {
254 self.into_iter()
255 }
256
257 pub fn iter_mut(&mut self) -> iter::IterMut<'_, V> {
263 self.into_iter()
264 }
265}
266
267impl<K, V: Clone, S: Clone> Clone for ExtractMap<K, V, S> {
268 fn clone(&self) -> Self {
269 Self {
270 build_hasher: self.build_hasher.clone(),
271 table: self.table.clone(),
272 phantom: PhantomData,
273 }
274 }
275
276 fn clone_from(&mut self, source: &Self) {
277 self.table.clone_from(&source.table);
278 self.build_hasher.clone_from(&source.build_hasher);
279 }
280}
281
282impl<K, V, S> Debug for ExtractMap<K, V, S>
283where
284 K: Debug + Hash + Eq,
285 V: Debug + ExtractKey<K>,
286{
287 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
288 f.debug_map()
289 .entries(self.iter().map(|v| (v.extract_key(), v)))
290 .finish()
291 }
292}
293
294impl<K, V, S> PartialEq for ExtractMap<K, V, S>
295where
296 K: Hash + Eq,
297 V: ExtractKey<K> + PartialEq,
298 S: BuildHasher,
299{
300 fn eq(&self, other: &Self) -> bool {
301 if self.len() != other.len() {
302 return false;
303 }
304
305 self.iter().all(|v| {
306 let k = v.extract_key();
307
308 other.get(k).is_some_and(|other_v| {
309 let other_k = other_v.extract_key();
310 k == other_k && v == other_v
311 })
312 })
313 }
314}
315
316impl<K, V, S> FromIterator<V> for ExtractMap<K, V, S>
317where
318 K: Hash + Eq,
319 V: ExtractKey<K>,
320 S: BuildHasher + Default,
321{
322 fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
323 let iter = iter.into_iter();
324 let mut this = Self::with_capacity_and_hasher(iter.size_hint().0, S::default());
325
326 for value in iter {
327 this.insert(value);
328 }
329
330 this
331 }
332}
333
334impl<K, V, S> Extend<V> for ExtractMap<K, V, S>
335where
336 K: Hash + Eq,
337 V: ExtractKey<K>,
338 S: BuildHasher,
339{
340 fn extend<T: IntoIterator<Item = V>>(&mut self, iter: T) {
341 for item in iter {
342 self.insert(item);
343 }
344 }
345}