Skip to main content

iddqd/tri_hash_map/
imp.rs

1use super::{IntoIter, Iter, IterMut, RefMut, tables::TriHashMapTables};
2use crate::{
3    DefaultHashBuilder, TriHashItem,
4    errors::DuplicateItem,
5    internal::ValidationError,
6    support::{
7        ItemIndex,
8        alloc::{AllocWrapper, Allocator, Global, global_alloc},
9        borrow::DormantMutRef,
10        fmt_utils::StrDisplayAsDebug,
11        item_set::ItemSet,
12        map_hash::MapHash,
13    },
14};
15use alloc::{collections::BTreeSet, vec::Vec};
16use core::{
17    fmt,
18    hash::{BuildHasher, Hash},
19};
20use equivalent::Equivalent;
21use hashbrown::hash_table::{Entry, VacantEntry};
22
23/// A 1:1:1 (trijective) map for three keys and a value.
24///
25/// The storage mechanism is a fast hash table of integer indexes to items, with
26/// these indexes stored in three hashmaps. This allows for efficient lookups by
27/// any of the three keys, while preventing duplicates.
28///
29/// # Examples
30///
31/// ```
32/// # #[cfg(feature = "default-hasher")] {
33/// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
34///
35/// #[derive(Debug, PartialEq, Eq)]
36/// struct Person {
37///     id: u32,
38///     email: String,
39///     phone: String,
40///     name: String,
41/// }
42///
43/// // Implement TriHashItem to define the three key types.
44/// impl TriHashItem for Person {
45///     type K1<'a> = u32;
46///     type K2<'a> = &'a str;
47///     type K3<'a> = &'a str;
48///
49///     fn key1(&self) -> Self::K1<'_> {
50///         self.id
51///     }
52///
53///     fn key2(&self) -> Self::K2<'_> {
54///         &self.email
55///     }
56///
57///     fn key3(&self) -> Self::K3<'_> {
58///         &self.phone
59///     }
60///
61///     tri_upcast!();
62/// }
63///
64/// // Create a TriHashMap and insert items.
65/// let mut people = TriHashMap::new();
66/// people
67///     .insert_unique(Person {
68///         id: 1,
69///         email: "alice@example.com".to_string(),
70///         phone: "555-1234".to_string(),
71///         name: "Alice".to_string(),
72///     })
73///     .unwrap();
74///
75/// // Lookup by any of the three keys.
76/// let person = people.get1(&1).unwrap();
77/// assert_eq!(person.name, "Alice");
78///
79/// let person = people.get2("alice@example.com").unwrap();
80/// assert_eq!(person.id, 1);
81///
82/// let person = people.get3("555-1234").unwrap();
83/// assert_eq!(person.email, "alice@example.com");
84/// # }
85/// ```
86#[derive(Clone)]
87pub struct TriHashMap<T, S = DefaultHashBuilder, A: Allocator = Global> {
88    pub(super) items: ItemSet<T, A>,
89    // Invariant: the values (ItemIndex) in these tables are valid indexes into
90    // `items`, and are a 1:1 mapping.
91    tables: TriHashMapTables<S, A>,
92}
93
94impl<T: TriHashItem, S: Default, A: Allocator + Default> Default
95    for TriHashMap<T, S, A>
96{
97    fn default() -> Self {
98        Self {
99            items: ItemSet::with_capacity_in(0, A::default()),
100            tables: TriHashMapTables::default(),
101        }
102    }
103}
104
105#[cfg(feature = "default-hasher")]
106impl<T: TriHashItem> TriHashMap<T> {
107    /// Creates a new, empty `TriHashMap`.
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// # #[cfg(feature = "default-hasher")] {
113    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
114    ///
115    /// #[derive(Debug, PartialEq, Eq)]
116    /// struct Person {
117    ///     id: u32,
118    ///     email: String,
119    ///     phone: String,
120    ///     name: String,
121    /// }
122    ///
123    /// impl TriHashItem for Person {
124    ///     type K1<'a> = u32;
125    ///     type K2<'a> = &'a str;
126    ///     type K3<'a> = &'a str;
127    ///
128    ///     fn key1(&self) -> Self::K1<'_> {
129    ///         self.id
130    ///     }
131    ///     fn key2(&self) -> Self::K2<'_> {
132    ///         &self.email
133    ///     }
134    ///     fn key3(&self) -> Self::K3<'_> {
135    ///         &self.phone
136    ///     }
137    ///     tri_upcast!();
138    /// }
139    ///
140    /// let map: TriHashMap<Person> = TriHashMap::new();
141    /// assert!(map.is_empty());
142    /// assert_eq!(map.len(), 0);
143    /// # }
144    /// ```
145    #[inline]
146    pub fn new() -> Self {
147        Self { items: ItemSet::new(), tables: TriHashMapTables::default() }
148    }
149
150    /// Creates a new `TriHashMap` with the given capacity.
151    ///
152    /// # Examples
153    ///
154    /// ```
155    /// # #[cfg(feature = "default-hasher")] {
156    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
157    ///
158    /// #[derive(Debug, PartialEq, Eq)]
159    /// struct Person {
160    ///     id: u32,
161    ///     email: String,
162    ///     phone: String,
163    ///     name: String,
164    /// }
165    ///
166    /// impl TriHashItem for Person {
167    ///     type K1<'a> = u32;
168    ///     type K2<'a> = &'a str;
169    ///     type K3<'a> = &'a str;
170    ///
171    ///     fn key1(&self) -> Self::K1<'_> {
172    ///         self.id
173    ///     }
174    ///     fn key2(&self) -> Self::K2<'_> {
175    ///         &self.email
176    ///     }
177    ///     fn key3(&self) -> Self::K3<'_> {
178    ///         &self.phone
179    ///     }
180    ///     tri_upcast!();
181    /// }
182    ///
183    /// let map: TriHashMap<Person> = TriHashMap::with_capacity(10);
184    /// assert!(map.capacity() >= 10);
185    /// assert!(map.is_empty());
186    /// # }
187    /// ```
188    pub fn with_capacity(capacity: usize) -> Self {
189        Self {
190            items: ItemSet::with_capacity_in(capacity, global_alloc()),
191            tables: TriHashMapTables::with_capacity_and_hasher_in(
192                capacity,
193                DefaultHashBuilder::default(),
194                global_alloc(),
195            ),
196        }
197    }
198}
199
200impl<T: TriHashItem, S: BuildHasher> TriHashMap<T, S> {
201    /// Creates a new, empty `TriHashMap` with the given hasher.
202    ///
203    /// # Examples
204    ///
205    /// ```
206    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
207    /// use std::collections::hash_map::RandomState;
208    ///
209    /// #[derive(Debug, PartialEq, Eq)]
210    /// struct Person {
211    ///     id: u32,
212    ///     email: String,
213    ///     phone: String,
214    ///     name: String,
215    /// }
216    ///
217    /// impl TriHashItem for Person {
218    ///     type K1<'a> = u32;
219    ///     type K2<'a> = &'a str;
220    ///     type K3<'a> = &'a str;
221    ///
222    ///     fn key1(&self) -> Self::K1<'_> {
223    ///         self.id
224    ///     }
225    ///     fn key2(&self) -> Self::K2<'_> {
226    ///         &self.email
227    ///     }
228    ///     fn key3(&self) -> Self::K3<'_> {
229    ///         &self.phone
230    ///     }
231    ///     tri_upcast!();
232    /// }
233    ///
234    /// let map: TriHashMap<Person, RandomState> =
235    ///     TriHashMap::with_hasher(RandomState::new());
236    /// assert!(map.is_empty());
237    /// ```
238    pub const fn with_hasher(hasher: S) -> Self {
239        Self {
240            items: ItemSet::new(),
241            tables: TriHashMapTables::with_hasher(hasher),
242        }
243    }
244
245    /// Creates a new `TriHashMap` with the given capacity and hasher.
246    ///
247    /// # Examples
248    ///
249    /// ```
250    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
251    /// use std::collections::hash_map::RandomState;
252    ///
253    /// #[derive(Debug, PartialEq, Eq)]
254    /// struct Person {
255    ///     id: u32,
256    ///     email: String,
257    ///     phone: String,
258    ///     name: String,
259    /// }
260    ///
261    /// impl TriHashItem for Person {
262    ///     type K1<'a> = u32;
263    ///     type K2<'a> = &'a str;
264    ///     type K3<'a> = &'a str;
265    ///
266    ///     fn key1(&self) -> Self::K1<'_> {
267    ///         self.id
268    ///     }
269    ///     fn key2(&self) -> Self::K2<'_> {
270    ///         &self.email
271    ///     }
272    ///     fn key3(&self) -> Self::K3<'_> {
273    ///         &self.phone
274    ///     }
275    ///     tri_upcast!();
276    /// }
277    ///
278    /// let map: TriHashMap<Person, RandomState> =
279    ///     TriHashMap::with_capacity_and_hasher(10, RandomState::new());
280    /// assert!(map.capacity() >= 10);
281    /// assert!(map.is_empty());
282    /// ```
283    pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
284        Self {
285            items: ItemSet::with_capacity_in(capacity, global_alloc()),
286            tables: TriHashMapTables::with_capacity_and_hasher_in(
287                capacity,
288                hasher,
289                global_alloc(),
290            ),
291        }
292    }
293}
294
295#[cfg(feature = "default-hasher")]
296impl<T: TriHashItem, A: Clone + Allocator>
297    TriHashMap<T, DefaultHashBuilder, A>
298{
299    /// Creates a new empty `TriHashMap` using the given allocator.
300    ///
301    /// Requires the `allocator-api2` feature to be enabled.
302    ///
303    /// # Examples
304    ///
305    /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
306    ///
307    /// ```
308    /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
309    /// use iddqd::{TriHashMap, TriHashItem, tri_upcast};
310    /// # use iddqd_test_utils::bumpalo;
311    ///
312    /// #[derive(Debug, PartialEq, Eq)]
313    /// struct Person {
314    ///     id: u32,
315    ///     email: String,
316    ///     phone: String,
317    ///     name: String,
318    /// }
319    ///
320    /// impl TriHashItem for Person {
321    ///     type K1<'a> = u32;
322    ///     type K2<'a> = &'a str;
323    ///     type K3<'a> = &'a str;
324    ///
325    ///     fn key1(&self) -> Self::K1<'_> {
326    ///         self.id
327    ///     }
328    ///     fn key2(&self) -> Self::K2<'_> {
329    ///         &self.email
330    ///     }
331    ///     fn key3(&self) -> Self::K3<'_> {
332    ///         &self.phone
333    ///     }
334    ///     tri_upcast!();
335    /// }
336    ///
337    /// // Define a new allocator.
338    /// let bump = bumpalo::Bump::new();
339    /// // Create a new TriHashMap using the allocator.
340    /// let map: TriHashMap<Person, _, &bumpalo::Bump> = TriHashMap::new_in(&bump);
341    /// assert!(map.is_empty());
342    /// # }
343    /// ```
344    pub fn new_in(alloc: A) -> Self {
345        Self {
346            items: ItemSet::with_capacity_in(0, alloc.clone()),
347            tables: TriHashMapTables::with_capacity_and_hasher_in(
348                0,
349                DefaultHashBuilder::default(),
350                alloc,
351            ),
352        }
353    }
354
355    /// Creates an empty `TriHashMap` with the specified capacity using the given
356    /// allocator.
357    ///
358    /// Requires the `allocator-api2` feature to be enabled.
359    ///
360    /// # Examples
361    ///
362    /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
363    ///
364    /// ```
365    /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
366    /// use iddqd::{TriHashMap, TriHashItem, tri_upcast};
367    /// # use iddqd_test_utils::bumpalo;
368    ///
369    /// #[derive(Debug, PartialEq, Eq)]
370    /// struct Person {
371    ///     id: u32,
372    ///     email: String,
373    ///     phone: String,
374    ///     name: String,
375    /// }
376    ///
377    /// impl TriHashItem for Person {
378    ///     type K1<'a> = u32;
379    ///     type K2<'a> = &'a str;
380    ///     type K3<'a> = &'a str;
381    ///
382    ///     fn key1(&self) -> Self::K1<'_> {
383    ///         self.id
384    ///     }
385    ///     fn key2(&self) -> Self::K2<'_> {
386    ///         &self.email
387    ///     }
388    ///     fn key3(&self) -> Self::K3<'_> {
389    ///         &self.phone
390    ///     }
391    ///     tri_upcast!();
392    /// }
393    ///
394    /// // Define a new allocator.
395    /// let bump = bumpalo::Bump::new();
396    /// // Create a new TriHashMap with capacity using the allocator.
397    /// let map: TriHashMap<Person, _, &bumpalo::Bump> = TriHashMap::with_capacity_in(10, &bump);
398    /// assert!(map.capacity() >= 10);
399    /// assert!(map.is_empty());
400    /// # }
401    /// ```
402    pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
403        Self {
404            items: ItemSet::with_capacity_in(capacity, alloc.clone()),
405            tables: TriHashMapTables::with_capacity_and_hasher_in(
406                capacity,
407                DefaultHashBuilder::default(),
408                alloc,
409            ),
410        }
411    }
412}
413
414impl<T: TriHashItem, S: Clone + BuildHasher, A: Clone + Allocator>
415    TriHashMap<T, S, A>
416{
417    /// Creates a new, empty `TriHashMap` with the given hasher and allocator.
418    ///
419    /// Requires the `allocator-api2` feature to be enabled.
420    ///
421    /// # Examples
422    ///
423    /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
424    ///
425    /// ```
426    /// # #[cfg(feature = "allocator-api2")] {
427    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
428    /// use std::collections::hash_map::RandomState;
429    /// # use iddqd_test_utils::bumpalo;
430    ///
431    /// #[derive(Debug, PartialEq, Eq)]
432    /// struct Person {
433    ///     id: u32,
434    ///     email: String,
435    ///     phone: String,
436    ///     name: String,
437    /// }
438    ///
439    /// impl TriHashItem for Person {
440    ///     type K1<'a> = u32;
441    ///     type K2<'a> = &'a str;
442    ///     type K3<'a> = &'a str;
443    ///
444    ///     fn key1(&self) -> Self::K1<'_> {
445    ///         self.id
446    ///     }
447    ///     fn key2(&self) -> Self::K2<'_> {
448    ///         &self.email
449    ///     }
450    ///     fn key3(&self) -> Self::K3<'_> {
451    ///         &self.phone
452    ///     }
453    ///     tri_upcast!();
454    /// }
455    ///
456    /// // Define a new allocator.
457    /// let bump = bumpalo::Bump::new();
458    /// let hasher = RandomState::new();
459    /// // Create a new TriHashMap with hasher using the allocator.
460    /// let map: TriHashMap<Person, _, &bumpalo::Bump> =
461    ///     TriHashMap::with_hasher_in(hasher, &bump);
462    /// assert!(map.is_empty());
463    /// # }
464    /// ```
465    pub fn with_hasher_in(hasher: S, alloc: A) -> Self {
466        Self {
467            items: ItemSet::with_capacity_in(0, alloc.clone()),
468            tables: TriHashMapTables::with_capacity_and_hasher_in(
469                0,
470                hasher.clone(),
471                alloc,
472            ),
473        }
474    }
475
476    /// Creates a new `TriHashMap` with the given capacity, hasher, and
477    /// allocator.
478    ///
479    /// Requires the `allocator-api2` feature to be enabled.
480    ///
481    /// # Examples
482    ///
483    /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
484    ///
485    /// ```
486    /// # #[cfg(feature = "allocator-api2")] {
487    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
488    /// use std::collections::hash_map::RandomState;
489    /// # use iddqd_test_utils::bumpalo;
490    ///
491    /// #[derive(Debug, PartialEq, Eq)]
492    /// struct Person {
493    ///     id: u32,
494    ///     email: String,
495    ///     phone: String,
496    ///     name: String,
497    /// }
498    ///
499    /// impl TriHashItem for Person {
500    ///     type K1<'a> = u32;
501    ///     type K2<'a> = &'a str;
502    ///     type K3<'a> = &'a str;
503    ///
504    ///     fn key1(&self) -> Self::K1<'_> {
505    ///         self.id
506    ///     }
507    ///     fn key2(&self) -> Self::K2<'_> {
508    ///         &self.email
509    ///     }
510    ///     fn key3(&self) -> Self::K3<'_> {
511    ///         &self.phone
512    ///     }
513    ///     tri_upcast!();
514    /// }
515    ///
516    /// // Define a new allocator.
517    /// let bump = bumpalo::Bump::new();
518    /// let hasher = RandomState::new();
519    /// // Create a new TriHashMap with capacity and hasher using the allocator.
520    /// let map: TriHashMap<Person, _, &bumpalo::Bump> =
521    ///     TriHashMap::with_capacity_and_hasher_in(10, hasher, &bump);
522    /// assert!(map.capacity() >= 10);
523    /// assert!(map.is_empty());
524    /// # }
525    /// ```
526    pub fn with_capacity_and_hasher_in(
527        capacity: usize,
528        hasher: S,
529        alloc: A,
530    ) -> Self {
531        Self {
532            items: ItemSet::with_capacity_in(capacity, alloc.clone()),
533            tables: TriHashMapTables::with_capacity_and_hasher_in(
534                capacity, hasher, alloc,
535            ),
536        }
537    }
538}
539
540impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> TriHashMap<T, S, A> {
541    /// Returns the hasher.
542    #[cfg(feature = "daft")]
543    #[inline]
544    pub(crate) fn hasher(&self) -> &S {
545        self.tables.hasher()
546    }
547
548    /// Returns the allocator.
549    ///
550    /// Requires the `allocator-api2` feature to be enabled.
551    ///
552    /// # Examples
553    ///
554    /// Using the [`bumpalo`](https://docs.rs/bumpalo) allocator:
555    ///
556    /// ```
557    /// # #[cfg(all(feature = "default-hasher", feature = "allocator-api2"))] {
558    /// use iddqd::{TriHashMap, TriHashItem, tri_upcast};
559    /// # use iddqd_test_utils::bumpalo;
560    ///
561    /// #[derive(Debug, PartialEq, Eq)]
562    /// struct Person {
563    ///     id: u32,
564    ///     email: String,
565    ///     phone: String,
566    ///     name: String,
567    /// }
568    ///
569    /// impl TriHashItem for Person {
570    ///     type K1<'a> = u32;
571    ///     type K2<'a> = &'a str;
572    ///     type K3<'a> = &'a str;
573    ///
574    ///     fn key1(&self) -> Self::K1<'_> {
575    ///         self.id
576    ///     }
577    ///     fn key2(&self) -> Self::K2<'_> {
578    ///         &self.email
579    ///     }
580    ///     fn key3(&self) -> Self::K3<'_> {
581    ///         &self.phone
582    ///     }
583    ///     tri_upcast!();
584    /// }
585    ///
586    /// // Define a new allocator.
587    /// let bump = bumpalo::Bump::new();
588    /// // Create a new TriHashMap using the allocator.
589    /// let map: TriHashMap<Person, _, &bumpalo::Bump> = TriHashMap::new_in(&bump);
590    /// // Access the allocator.
591    /// let allocator = map.allocator();
592    /// # }
593    /// ```
594    #[inline]
595    pub fn allocator(&self) -> &A {
596        self.items.allocator()
597    }
598
599    /// Returns the currently allocated capacity of the map.
600    ///
601    /// # Examples
602    ///
603    /// ```
604    /// # #[cfg(feature = "default-hasher")] {
605    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
606    ///
607    /// #[derive(Debug, PartialEq, Eq)]
608    /// struct Person {
609    ///     id: u32,
610    ///     email: String,
611    ///     phone: String,
612    ///     name: String,
613    /// }
614    ///
615    /// impl TriHashItem for Person {
616    ///     type K1<'a> = u32;
617    ///     type K2<'a> = &'a str;
618    ///     type K3<'a> = &'a str;
619    ///
620    ///     fn key1(&self) -> Self::K1<'_> {
621    ///         self.id
622    ///     }
623    ///     fn key2(&self) -> Self::K2<'_> {
624    ///         &self.email
625    ///     }
626    ///     fn key3(&self) -> Self::K3<'_> {
627    ///         &self.phone
628    ///     }
629    ///     tri_upcast!();
630    /// }
631    ///
632    /// let map: TriHashMap<Person> = TriHashMap::with_capacity(10);
633    /// assert!(map.capacity() >= 10);
634    /// # }
635    /// ```
636    pub fn capacity(&self) -> usize {
637        // items and tables.capacity might theoretically diverge: use
638        // items.capacity.
639        self.items.capacity()
640    }
641
642    /// Returns true if the map is empty.
643    ///
644    /// # Examples
645    ///
646    /// ```
647    /// # #[cfg(feature = "default-hasher")] {
648    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
649    ///
650    /// #[derive(Debug, PartialEq, Eq)]
651    /// struct Person {
652    ///     id: u32,
653    ///     email: String,
654    ///     phone: String,
655    ///     name: String,
656    /// }
657    ///
658    /// impl TriHashItem for Person {
659    ///     type K1<'a> = u32;
660    ///     type K2<'a> = &'a str;
661    ///     type K3<'a> = &'a str;
662    ///
663    ///     fn key1(&self) -> Self::K1<'_> {
664    ///         self.id
665    ///     }
666    ///     fn key2(&self) -> Self::K2<'_> {
667    ///         &self.email
668    ///     }
669    ///     fn key3(&self) -> Self::K3<'_> {
670    ///         &self.phone
671    ///     }
672    ///     tri_upcast!();
673    /// }
674    ///
675    /// let mut map = TriHashMap::new();
676    /// assert!(map.is_empty());
677    ///
678    /// map.insert_unique(Person {
679    ///     id: 1,
680    ///     email: "alice@example.com".to_string(),
681    ///     phone: "555-1234".to_string(),
682    ///     name: "Alice".to_string(),
683    /// })
684    /// .unwrap();
685    /// assert!(!map.is_empty());
686    /// # }
687    /// ```
688    #[inline]
689    pub fn is_empty(&self) -> bool {
690        self.items.is_empty()
691    }
692
693    /// Returns the number of items in the map.
694    ///
695    /// # Examples
696    ///
697    /// ```
698    /// # #[cfg(feature = "default-hasher")] {
699    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
700    ///
701    /// #[derive(Debug, PartialEq, Eq)]
702    /// struct Person {
703    ///     id: u32,
704    ///     email: String,
705    ///     phone: String,
706    ///     name: String,
707    /// }
708    ///
709    /// impl TriHashItem for Person {
710    ///     type K1<'a> = u32;
711    ///     type K2<'a> = &'a str;
712    ///     type K3<'a> = &'a str;
713    ///
714    ///     fn key1(&self) -> Self::K1<'_> {
715    ///         self.id
716    ///     }
717    ///     fn key2(&self) -> Self::K2<'_> {
718    ///         &self.email
719    ///     }
720    ///     fn key3(&self) -> Self::K3<'_> {
721    ///         &self.phone
722    ///     }
723    ///     tri_upcast!();
724    /// }
725    ///
726    /// let mut map = TriHashMap::new();
727    /// assert_eq!(map.len(), 0);
728    ///
729    /// map.insert_unique(Person {
730    ///     id: 1,
731    ///     email: "alice@example.com".to_string(),
732    ///     phone: "555-1234".to_string(),
733    ///     name: "Alice".to_string(),
734    /// })
735    /// .unwrap();
736    /// map.insert_unique(Person {
737    ///     id: 2,
738    ///     email: "bob@example.com".to_string(),
739    ///     phone: "555-5678".to_string(),
740    ///     name: "Bob".to_string(),
741    /// })
742    /// .unwrap();
743    /// assert_eq!(map.len(), 2);
744    /// # }
745    /// ```
746    #[inline]
747    pub fn len(&self) -> usize {
748        self.items.len()
749    }
750
751    /// Clears the map, removing all items.
752    ///
753    /// # Examples
754    ///
755    /// ```
756    /// # #[cfg(feature = "default-hasher")] {
757    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
758    ///
759    /// #[derive(Debug, PartialEq, Eq)]
760    /// struct Person {
761    ///     id: u32,
762    ///     email: String,
763    ///     phone: String,
764    ///     name: String,
765    /// }
766    ///
767    /// impl TriHashItem for Person {
768    ///     type K1<'a> = u32;
769    ///     type K2<'a> = &'a str;
770    ///     type K3<'a> = &'a str;
771    ///
772    ///     fn key1(&self) -> Self::K1<'_> {
773    ///         self.id
774    ///     }
775    ///     fn key2(&self) -> Self::K2<'_> {
776    ///         &self.email
777    ///     }
778    ///     fn key3(&self) -> Self::K3<'_> {
779    ///         &self.phone
780    ///     }
781    ///     tri_upcast!();
782    /// }
783    ///
784    /// let mut map = TriHashMap::new();
785    /// map.insert_unique(Person {
786    ///     id: 1,
787    ///     email: "alice@example.com".to_string(),
788    ///     phone: "555-1234".to_string(),
789    ///     name: "Alice".to_string(),
790    /// })
791    /// .unwrap();
792    /// assert_eq!(map.len(), 1);
793    ///
794    /// map.clear();
795    /// assert!(map.is_empty());
796    /// assert_eq!(map.len(), 0);
797    /// # }
798    /// ```
799    pub fn clear(&mut self) {
800        self.items.clear();
801        self.tables.k1_to_item.clear();
802        self.tables.k2_to_item.clear();
803        self.tables.k3_to_item.clear();
804    }
805
806    /// Reserves capacity for at least `additional` more elements to be inserted
807    /// in the `TriHashMap`. The collection may reserve more space to
808    /// speculatively avoid frequent reallocations. After calling `reserve`,
809    /// capacity will be greater than or equal to `self.len() + additional`.
810    /// Does nothing if capacity is already sufficient.
811    ///
812    /// # Panics
813    ///
814    /// Panics if the new capacity overflows [`isize::MAX`] bytes, and
815    /// [`abort`]s the program in case of an allocation error. Use
816    /// [`try_reserve`](Self::try_reserve) instead if you want to handle memory
817    /// allocation failure.
818    ///
819    /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html
820    /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html
821    ///
822    /// # Examples
823    ///
824    /// ```
825    /// # #[cfg(feature = "default-hasher")] {
826    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
827    ///
828    /// #[derive(Debug, PartialEq, Eq, Hash)]
829    /// struct Item {
830    ///     id: u32,
831    ///     name: String,
832    ///     email: String,
833    /// }
834    ///
835    /// impl TriHashItem for Item {
836    ///     type K1<'a> = u32;
837    ///     type K2<'a> = &'a str;
838    ///     type K3<'a> = &'a str;
839    ///     fn key1(&self) -> Self::K1<'_> {
840    ///         self.id
841    ///     }
842    ///     fn key2(&self) -> Self::K2<'_> {
843    ///         &self.name
844    ///     }
845    ///     fn key3(&self) -> Self::K3<'_> {
846    ///         &self.email
847    ///     }
848    ///     tri_upcast!();
849    /// }
850    ///
851    /// let mut map: TriHashMap<Item> = TriHashMap::new();
852    /// map.reserve(100);
853    /// assert!(map.capacity() >= 100);
854    /// # }
855    /// ```
856    pub fn reserve(&mut self, additional: usize) {
857        self.items.reserve(additional);
858        let items = &self.items;
859        let state = &self.tables.state;
860        self.tables
861            .k1_to_item
862            .reserve(additional, |ix| state.hash_one(items[*ix].key1()));
863        self.tables
864            .k2_to_item
865            .reserve(additional, |ix| state.hash_one(items[*ix].key2()));
866        self.tables
867            .k3_to_item
868            .reserve(additional, |ix| state.hash_one(items[*ix].key3()));
869    }
870
871    /// Tries to reserve capacity for at least `additional` more elements to be
872    /// inserted in the `TriHashMap`. The collection may reserve more space to
873    /// speculatively avoid frequent reallocations. After calling `try_reserve`,
874    /// capacity will be greater than or equal to `self.len() + additional` if
875    /// it returns `Ok(())`. Does nothing if capacity is already sufficient.
876    ///
877    /// # Errors
878    ///
879    /// If the capacity overflows, or the allocator reports a failure, then an
880    /// error is returned.
881    ///
882    /// # Notes
883    ///
884    /// If reservation fails partway through, some internal structures may have
885    /// already increased their capacity. The map remains in a valid state but
886    /// may have uneven capacities across its internal structures.
887    ///
888    /// # Examples
889    ///
890    /// ```
891    /// # #[cfg(feature = "default-hasher")] {
892    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
893    ///
894    /// #[derive(Debug, PartialEq, Eq, Hash)]
895    /// struct Item {
896    ///     id: u32,
897    ///     name: String,
898    ///     email: String,
899    /// }
900    ///
901    /// impl TriHashItem for Item {
902    ///     type K1<'a> = u32;
903    ///     type K2<'a> = &'a str;
904    ///     type K3<'a> = &'a str;
905    ///     fn key1(&self) -> Self::K1<'_> {
906    ///         self.id
907    ///     }
908    ///     fn key2(&self) -> Self::K2<'_> {
909    ///         &self.name
910    ///     }
911    ///     fn key3(&self) -> Self::K3<'_> {
912    ///         &self.email
913    ///     }
914    ///     tri_upcast!();
915    /// }
916    ///
917    /// let mut map: TriHashMap<Item> = TriHashMap::new();
918    /// map.try_reserve(100).expect("allocation should succeed");
919    /// assert!(map.capacity() >= 100);
920    /// # }
921    /// ```
922    pub fn try_reserve(
923        &mut self,
924        additional: usize,
925    ) -> Result<(), crate::errors::TryReserveError> {
926        self.items.try_reserve(additional)?;
927        let items = &self.items;
928        let state = &self.tables.state;
929        self.tables
930            .k1_to_item
931            .try_reserve(additional, |ix| state.hash_one(items[*ix].key1()))
932            .map_err(crate::errors::TryReserveError::from_hashbrown)?;
933        self.tables
934            .k2_to_item
935            .try_reserve(additional, |ix| state.hash_one(items[*ix].key2()))
936            .map_err(crate::errors::TryReserveError::from_hashbrown)?;
937        self.tables
938            .k3_to_item
939            .try_reserve(additional, |ix| state.hash_one(items[*ix].key3()))
940            .map_err(crate::errors::TryReserveError::from_hashbrown)?;
941        Ok(())
942    }
943
944    /// Shrinks the capacity of the map as much as possible. It will drop
945    /// down as much as possible while maintaining the internal rules
946    /// and possibly leaving some space in accordance with the resize policy.
947    ///
948    /// # Examples
949    ///
950    /// ```
951    /// # #[cfg(feature = "default-hasher")] {
952    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
953    ///
954    /// #[derive(Debug, PartialEq, Eq, Hash)]
955    /// struct Item {
956    ///     id: u32,
957    ///     name: String,
958    ///     email: String,
959    /// }
960    ///
961    /// impl TriHashItem for Item {
962    ///     type K1<'a> = u32;
963    ///     type K2<'a> = &'a str;
964    ///     type K3<'a> = &'a str;
965    ///     fn key1(&self) -> Self::K1<'_> {
966    ///         self.id
967    ///     }
968    ///     fn key2(&self) -> Self::K2<'_> {
969    ///         &self.name
970    ///     }
971    ///     fn key3(&self) -> Self::K3<'_> {
972    ///         &self.email
973    ///     }
974    ///     tri_upcast!();
975    /// }
976    ///
977    /// let mut map: TriHashMap<Item> = TriHashMap::with_capacity(100);
978    /// map.insert_unique(Item {
979    ///     id: 1,
980    ///     name: "foo".to_string(),
981    ///     email: "foo@example.com".to_string(),
982    /// })
983    /// .unwrap();
984    /// map.insert_unique(Item {
985    ///     id: 2,
986    ///     name: "bar".to_string(),
987    ///     email: "bar@example.com".to_string(),
988    /// })
989    /// .unwrap();
990    /// assert!(map.capacity() >= 100);
991    /// map.shrink_to_fit();
992    /// assert!(map.capacity() >= 2);
993    /// # }
994    /// ```
995    pub fn shrink_to_fit(&mut self) {
996        let remap = self.items.shrink_to_fit();
997        if !remap.is_identity() {
998            self.tables.k1_to_item.remap_indexes(&remap);
999            self.tables.k2_to_item.remap_indexes(&remap);
1000            self.tables.k3_to_item.remap_indexes(&remap);
1001        }
1002        let items = &self.items;
1003        let state = &self.tables.state;
1004        self.tables
1005            .k1_to_item
1006            .shrink_to_fit(|ix| state.hash_one(items[*ix].key1()));
1007        self.tables
1008            .k2_to_item
1009            .shrink_to_fit(|ix| state.hash_one(items[*ix].key2()));
1010        self.tables
1011            .k3_to_item
1012            .shrink_to_fit(|ix| state.hash_one(items[*ix].key3()));
1013    }
1014
1015    /// Shrinks the capacity of the map with a lower limit. It will drop
1016    /// down no lower than the supplied limit while maintaining the internal
1017    /// rules and possibly leaving some space in accordance with the resize
1018    /// policy.
1019    ///
1020    /// If the current capacity is less than the lower limit, this is a no-op.
1021    ///
1022    /// # Examples
1023    ///
1024    /// ```
1025    /// # #[cfg(feature = "default-hasher")] {
1026    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1027    ///
1028    /// #[derive(Debug, PartialEq, Eq, Hash)]
1029    /// struct Item {
1030    ///     id: u32,
1031    ///     name: String,
1032    ///     email: String,
1033    /// }
1034    ///
1035    /// impl TriHashItem for Item {
1036    ///     type K1<'a> = u32;
1037    ///     type K2<'a> = &'a str;
1038    ///     type K3<'a> = &'a str;
1039    ///     fn key1(&self) -> Self::K1<'_> {
1040    ///         self.id
1041    ///     }
1042    ///     fn key2(&self) -> Self::K2<'_> {
1043    ///         &self.name
1044    ///     }
1045    ///     fn key3(&self) -> Self::K3<'_> {
1046    ///         &self.email
1047    ///     }
1048    ///     tri_upcast!();
1049    /// }
1050    ///
1051    /// let mut map: TriHashMap<Item> = TriHashMap::with_capacity(100);
1052    /// map.insert_unique(Item {
1053    ///     id: 1,
1054    ///     name: "foo".to_string(),
1055    ///     email: "foo@example.com".to_string(),
1056    /// })
1057    /// .unwrap();
1058    /// map.insert_unique(Item {
1059    ///     id: 2,
1060    ///     name: "bar".to_string(),
1061    ///     email: "bar@example.com".to_string(),
1062    /// })
1063    /// .unwrap();
1064    /// assert!(map.capacity() >= 100);
1065    /// map.shrink_to(10);
1066    /// assert!(map.capacity() >= 10);
1067    /// map.shrink_to(0);
1068    /// assert!(map.capacity() >= 2);
1069    /// # }
1070    /// ```
1071    pub fn shrink_to(&mut self, min_capacity: usize) {
1072        let remap = self.items.shrink_to(min_capacity);
1073        if !remap.is_identity() {
1074            self.tables.k1_to_item.remap_indexes(&remap);
1075            self.tables.k2_to_item.remap_indexes(&remap);
1076            self.tables.k3_to_item.remap_indexes(&remap);
1077        }
1078        let items = &self.items;
1079        let state = &self.tables.state;
1080        self.tables
1081            .k1_to_item
1082            .shrink_to(min_capacity, |ix| state.hash_one(items[*ix].key1()));
1083        self.tables
1084            .k2_to_item
1085            .shrink_to(min_capacity, |ix| state.hash_one(items[*ix].key2()));
1086        self.tables
1087            .k3_to_item
1088            .shrink_to(min_capacity, |ix| state.hash_one(items[*ix].key3()));
1089    }
1090
1091    /// Iterates over the items in the map.
1092    ///
1093    /// Similar to [`HashMap`], the iteration order is arbitrary and not
1094    /// guaranteed to be stable.
1095    ///
1096    /// # Examples
1097    ///
1098    /// ```
1099    /// # #[cfg(feature = "default-hasher")] {
1100    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1101    ///
1102    /// #[derive(Debug, PartialEq, Eq)]
1103    /// struct Person {
1104    ///     id: u32,
1105    ///     email: String,
1106    ///     phone: String,
1107    ///     name: String,
1108    /// }
1109    ///
1110    /// impl TriHashItem for Person {
1111    ///     type K1<'a> = u32;
1112    ///     type K2<'a> = &'a str;
1113    ///     type K3<'a> = &'a str;
1114    ///
1115    ///     fn key1(&self) -> Self::K1<'_> {
1116    ///         self.id
1117    ///     }
1118    ///     fn key2(&self) -> Self::K2<'_> {
1119    ///         &self.email
1120    ///     }
1121    ///     fn key3(&self) -> Self::K3<'_> {
1122    ///         &self.phone
1123    ///     }
1124    ///     tri_upcast!();
1125    /// }
1126    ///
1127    /// let mut map = TriHashMap::new();
1128    /// map.insert_unique(Person {
1129    ///     id: 1,
1130    ///     email: "alice@example.com".to_string(),
1131    ///     phone: "555-1234".to_string(),
1132    ///     name: "Alice".to_string(),
1133    /// })
1134    /// .unwrap();
1135    /// map.insert_unique(Person {
1136    ///     id: 2,
1137    ///     email: "bob@example.com".to_string(),
1138    ///     phone: "555-5678".to_string(),
1139    ///     name: "Bob".to_string(),
1140    /// })
1141    /// .unwrap();
1142    ///
1143    /// let mut count = 0;
1144    /// for person in map.iter() {
1145    ///     assert!(person.id == 1 || person.id == 2);
1146    ///     count += 1;
1147    /// }
1148    /// assert_eq!(count, 2);
1149    /// # }
1150    /// ```
1151    ///
1152    /// [`HashMap`]: std::collections::HashMap
1153    #[inline]
1154    pub fn iter(&self) -> Iter<'_, T> {
1155        Iter::new(&self.items)
1156    }
1157
1158    /// Iterates over the items in the map, allowing for mutation.
1159    ///
1160    /// Similar to [`HashMap`], the iteration order is arbitrary and not
1161    /// guaranteed to be stable.
1162    ///
1163    /// # Examples
1164    ///
1165    /// ```
1166    /// # #[cfg(feature = "default-hasher")] {
1167    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1168    ///
1169    /// #[derive(Debug, PartialEq, Eq)]
1170    /// struct Person {
1171    ///     id: u32,
1172    ///     email: String,
1173    ///     phone: String,
1174    ///     name: String,
1175    /// }
1176    ///
1177    /// impl TriHashItem for Person {
1178    ///     type K1<'a> = u32;
1179    ///     type K2<'a> = &'a str;
1180    ///     type K3<'a> = &'a str;
1181    ///
1182    ///     fn key1(&self) -> Self::K1<'_> {
1183    ///         self.id
1184    ///     }
1185    ///     fn key2(&self) -> Self::K2<'_> {
1186    ///         &self.email
1187    ///     }
1188    ///     fn key3(&self) -> Self::K3<'_> {
1189    ///         &self.phone
1190    ///     }
1191    ///     tri_upcast!();
1192    /// }
1193    ///
1194    /// let mut map = TriHashMap::new();
1195    /// map.insert_unique(Person {
1196    ///     id: 1,
1197    ///     email: "alice@example.com".to_string(),
1198    ///     phone: "555-1234".to_string(),
1199    ///     name: "Alice".to_string(),
1200    /// })
1201    /// .unwrap();
1202    ///
1203    /// for mut person in map.iter_mut() {
1204    ///     person.name.push_str(" Updated");
1205    /// }
1206    ///
1207    /// let person = map.get1(&1).unwrap();
1208    /// assert_eq!(person.name, "Alice Updated");
1209    /// # }
1210    /// ```
1211    ///
1212    /// [`HashMap`]: std::collections::HashMap
1213    #[inline]
1214    pub fn iter_mut(&mut self) -> IterMut<'_, T, S, A> {
1215        IterMut::new(&self.tables, &mut self.items)
1216    }
1217
1218    /// Checks general invariants of the map.
1219    ///
1220    /// The code below always upholds these invariants, but it's useful to have
1221    /// an explicit check for tests.
1222    #[doc(hidden)]
1223    pub fn validate(
1224        &self,
1225        compactness: crate::internal::ValidateCompact,
1226    ) -> Result<(), ValidationError>
1227    where
1228        T: fmt::Debug,
1229    {
1230        self.items.validate(compactness)?;
1231        self.tables.validate(self.len(), compactness)?;
1232
1233        // Check that the indexes are all correct.
1234        for (ix, item) in self.items.iter() {
1235            let key1 = item.key1();
1236            let key2 = item.key2();
1237            let key3 = item.key3();
1238
1239            let Some(ix1) = self.find1_index(&key1) else {
1240                return Err(ValidationError::general(format!(
1241                    "item at index {ix} has no key1 index"
1242                )));
1243            };
1244            let Some(ix2) = self.find2_index(&key2) else {
1245                return Err(ValidationError::general(format!(
1246                    "item at index {ix} has no key2 index"
1247                )));
1248            };
1249            let Some(ix3) = self.find3_index(&key3) else {
1250                return Err(ValidationError::general(format!(
1251                    "item at index {ix} has no key3 index"
1252                )));
1253            };
1254
1255            if ix1 != ix || ix2 != ix || ix3 != ix {
1256                return Err(ValidationError::general(format!(
1257                    "item at index {ix} has inconsistent indexes: {ix1}/{ix2}/{ix3}"
1258                )));
1259            }
1260        }
1261
1262        Ok(())
1263    }
1264
1265    /// Inserts a value into the map, removing any conflicting items and
1266    /// returning a list of those items.
1267    ///
1268    /// # Examples
1269    ///
1270    /// ```
1271    /// # #[cfg(feature = "default-hasher")] {
1272    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1273    ///
1274    /// #[derive(Debug, PartialEq, Eq)]
1275    /// struct Person {
1276    ///     id: u32,
1277    ///     email: String,
1278    ///     phone: String,
1279    ///     name: String,
1280    /// }
1281    ///
1282    /// impl TriHashItem for Person {
1283    ///     type K1<'a> = u32;
1284    ///     type K2<'a> = &'a str;
1285    ///     type K3<'a> = &'a str;
1286    ///
1287    ///     fn key1(&self) -> Self::K1<'_> {
1288    ///         self.id
1289    ///     }
1290    ///     fn key2(&self) -> Self::K2<'_> {
1291    ///         &self.email
1292    ///     }
1293    ///     fn key3(&self) -> Self::K3<'_> {
1294    ///         &self.phone
1295    ///     }
1296    ///     tri_upcast!();
1297    /// }
1298    ///
1299    /// let mut map = TriHashMap::new();
1300    ///
1301    /// // First insertion - no conflicts
1302    /// let overwritten = map.insert_overwrite(Person {
1303    ///     id: 1,
1304    ///     email: "alice@example.com".to_string(),
1305    ///     phone: "555-1234".to_string(),
1306    ///     name: "Alice".to_string(),
1307    /// });
1308    /// assert!(overwritten.is_empty());
1309    ///
1310    /// // Overwrite with same id - returns the old item
1311    /// let overwritten = map.insert_overwrite(Person {
1312    ///     id: 1,
1313    ///     email: "alice.new@example.com".to_string(),
1314    ///     phone: "555-9999".to_string(),
1315    ///     name: "Alice New".to_string(),
1316    /// });
1317    /// assert_eq!(overwritten.len(), 1);
1318    /// assert_eq!(overwritten[0].name, "Alice");
1319    /// # }
1320    /// ```
1321    #[doc(alias = "insert")]
1322    pub fn insert_overwrite(&mut self, value: T) -> Vec<T> {
1323        // Trying to write this function for maximal efficiency can get very
1324        // tricky, requiring delicate handling of indexes. We follow a very
1325        // simple approach instead:
1326        //
1327        // 1. Remove items corresponding to keys that are already in the map.
1328        // 2. Add the item to the map.
1329
1330        let mut duplicates = Vec::new();
1331        duplicates.extend(self.remove1(&value.key1()));
1332        duplicates.extend(self.remove2(&value.key2()));
1333        duplicates.extend(self.remove3(&value.key3()));
1334
1335        if self.insert_unique(value).is_err() {
1336            // We should never get here, because we just removed all the
1337            // duplicates.
1338            panic!("insert_unique failed after removing duplicates");
1339        }
1340
1341        duplicates
1342    }
1343
1344    /// Inserts a value into the set, returning an error if any duplicates were
1345    /// added.
1346    ///
1347    /// # Examples
1348    ///
1349    /// ```
1350    /// # #[cfg(feature = "default-hasher")] {
1351    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1352    ///
1353    /// #[derive(Debug, PartialEq, Eq)]
1354    /// struct Person {
1355    ///     id: u32,
1356    ///     email: String,
1357    ///     phone: String,
1358    ///     name: String,
1359    /// }
1360    ///
1361    /// impl TriHashItem for Person {
1362    ///     type K1<'a> = u32;
1363    ///     type K2<'a> = &'a str;
1364    ///     type K3<'a> = &'a str;
1365    ///
1366    ///     fn key1(&self) -> Self::K1<'_> {
1367    ///         self.id
1368    ///     }
1369    ///     fn key2(&self) -> Self::K2<'_> {
1370    ///         &self.email
1371    ///     }
1372    ///     fn key3(&self) -> Self::K3<'_> {
1373    ///         &self.phone
1374    ///     }
1375    ///     tri_upcast!();
1376    /// }
1377    ///
1378    /// let mut map = TriHashMap::new();
1379    ///
1380    /// // Successful insertion
1381    /// assert!(
1382    ///     map.insert_unique(Person {
1383    ///         id: 1,
1384    ///         email: "alice@example.com".to_string(),
1385    ///         phone: "555-1234".to_string(),
1386    ///         name: "Alice".to_string(),
1387    ///     })
1388    ///     .is_ok()
1389    /// );
1390    /// assert!(
1391    ///     map.insert_unique(Person {
1392    ///         id: 2,
1393    ///         email: "bob@example.com".to_string(),
1394    ///         phone: "555-5678".to_string(),
1395    ///         name: "Bob".to_string(),
1396    ///     })
1397    ///     .is_ok()
1398    /// );
1399    ///
1400    /// // Duplicate key1
1401    /// assert!(
1402    ///     map.insert_unique(Person {
1403    ///         id: 1,
1404    ///         email: "charlie@example.com".to_string(),
1405    ///         phone: "555-9999".to_string(),
1406    ///         name: "Charlie".to_string(),
1407    ///     })
1408    ///     .is_err()
1409    /// );
1410    ///
1411    /// // Duplicate key2
1412    /// assert!(
1413    ///     map.insert_unique(Person {
1414    ///         id: 3,
1415    ///         email: "alice@example.com".to_string(),
1416    ///         phone: "555-7777".to_string(),
1417    ///         name: "Alice2".to_string(),
1418    ///     })
1419    ///     .is_err()
1420    /// );
1421    ///
1422    /// // Duplicate key3
1423    /// assert!(
1424    ///     map.insert_unique(Person {
1425    ///         id: 4,
1426    ///         email: "dave@example.com".to_string(),
1427    ///         phone: "555-1234".to_string(),
1428    ///         name: "Dave".to_string(),
1429    ///     })
1430    ///     .is_err()
1431    /// );
1432    /// # }
1433    /// ```
1434    pub fn insert_unique(
1435        &mut self,
1436        value: T,
1437    ) -> Result<(), DuplicateItem<T, &T>> {
1438        let mut duplicates = BTreeSet::new();
1439
1440        // Check for duplicates *before* inserting the new item, because we
1441        // don't want to partially insert the new item and then have to roll
1442        // back.
1443        let state = &self.tables.state;
1444        let (e1, e2, e3) = {
1445            let k1 = value.key1();
1446            let k2 = value.key2();
1447            let k3 = value.key3();
1448
1449            let e1 = detect_dup_or_insert(
1450                self.tables
1451                    .k1_to_item
1452                    .entry(state, k1, |index| self.items[index].key1()),
1453                &mut duplicates,
1454            );
1455            let e2 = detect_dup_or_insert(
1456                self.tables
1457                    .k2_to_item
1458                    .entry(state, k2, |index| self.items[index].key2()),
1459                &mut duplicates,
1460            );
1461            let e3 = detect_dup_or_insert(
1462                self.tables
1463                    .k3_to_item
1464                    .entry(state, k3, |index| self.items[index].key3()),
1465                &mut duplicates,
1466            );
1467            (e1, e2, e3)
1468        };
1469
1470        if !duplicates.is_empty() {
1471            return Err(DuplicateItem::__internal_new(
1472                value,
1473                duplicates.iter().map(|ix| &self.items[*ix]).collect(),
1474            ));
1475        }
1476
1477        let next_index = self.items.assert_can_grow().insert(value);
1478        // e1, e2 and e3 are all Some because if they were None, duplicates
1479        // would be non-empty, and we'd have bailed out earlier.
1480        e1.unwrap().insert(next_index);
1481        e2.unwrap().insert(next_index);
1482        e3.unwrap().insert(next_index);
1483
1484        Ok(())
1485    }
1486
1487    /// Returns true if the map contains a single item that matches all three
1488    /// keys.
1489    ///
1490    /// # Examples
1491    ///
1492    /// ```
1493    /// # #[cfg(feature = "default-hasher")] {
1494    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1495    ///
1496    /// #[derive(Debug, PartialEq, Eq)]
1497    /// struct Person {
1498    ///     id: u32,
1499    ///     email: String,
1500    ///     phone: String,
1501    ///     name: String,
1502    /// }
1503    ///
1504    /// impl TriHashItem for Person {
1505    ///     type K1<'a> = u32;
1506    ///     type K2<'a> = &'a str;
1507    ///     type K3<'a> = &'a str;
1508    ///
1509    ///     fn key1(&self) -> Self::K1<'_> {
1510    ///         self.id
1511    ///     }
1512    ///     fn key2(&self) -> Self::K2<'_> {
1513    ///         &self.email
1514    ///     }
1515    ///     fn key3(&self) -> Self::K3<'_> {
1516    ///         &self.phone
1517    ///     }
1518    ///     tri_upcast!();
1519    /// }
1520    ///
1521    /// let mut map = TriHashMap::new();
1522    /// map.insert_unique(Person {
1523    ///     id: 1,
1524    ///     email: "alice@example.com".to_string(),
1525    ///     phone: "555-1234".to_string(),
1526    ///     name: "Alice".to_string(),
1527    /// }).unwrap();
1528    /// map.insert_unique(Person {
1529    ///     id: 2,
1530    ///     email: "bob@example.com".to_string(),
1531    ///     phone: "555-5678".to_string(),
1532    ///     name: "Bob".to_string(),
1533    /// }).unwrap();
1534    ///
1535    /// assert!(map.contains_key_unique(&1, &"alice@example.com", &"555-1234"));
1536    /// assert!(map.contains_key_unique(&2, &"bob@example.com", &"555-5678"));
1537    /// assert!(!map.contains_key_unique(&1, &"bob@example.com", &"555-1234")); // key1 exists but key2 doesn't match
1538    /// assert!(!map.contains_key_unique(&3, &"charlie@example.com", &"555-9999")); // none of the keys exist
1539    /// # }
1540    /// ```
1541    pub fn contains_key_unique<'a, Q1, Q2, Q3>(
1542        &'a self,
1543        key1: &Q1,
1544        key2: &Q2,
1545        key3: &Q3,
1546    ) -> bool
1547    where
1548        Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1549        Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1550        Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1551    {
1552        self.get_unique(key1, key2, key3).is_some()
1553    }
1554
1555    /// Gets a reference to the unique item associated with the given `key1`,
1556    /// `key2`, and `key3`, if it exists.
1557    ///
1558    /// # Examples
1559    ///
1560    /// ```
1561    /// # #[cfg(feature = "default-hasher")] {
1562    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1563    ///
1564    /// #[derive(Debug, PartialEq, Eq)]
1565    /// struct Person {
1566    ///     id: u32,
1567    ///     email: String,
1568    ///     phone: String,
1569    ///     name: String,
1570    /// }
1571    ///
1572    /// impl TriHashItem for Person {
1573    ///     type K1<'a> = u32;
1574    ///     type K2<'a> = &'a str;
1575    ///     type K3<'a> = &'a str;
1576    ///
1577    ///     fn key1(&self) -> Self::K1<'_> {
1578    ///         self.id
1579    ///     }
1580    ///     fn key2(&self) -> Self::K2<'_> {
1581    ///         &self.email
1582    ///     }
1583    ///     fn key3(&self) -> Self::K3<'_> {
1584    ///         &self.phone
1585    ///     }
1586    ///     tri_upcast!();
1587    /// }
1588    ///
1589    /// let mut map = TriHashMap::new();
1590    /// map.insert_unique(Person {
1591    ///     id: 1,
1592    ///     email: "alice@example.com".to_string(),
1593    ///     phone: "555-1234".to_string(),
1594    ///     name: "Alice".to_string(),
1595    /// })
1596    /// .unwrap();
1597    ///
1598    /// // All three keys must match
1599    /// assert_eq!(
1600    ///     map.get_unique(&1, &"alice@example.com", &"555-1234").unwrap().name,
1601    ///     "Alice"
1602    /// );
1603    ///
1604    /// // If any key doesn't match, returns None
1605    /// assert!(map.get_unique(&1, &"wrong@example.com", &"555-1234").is_none());
1606    /// assert!(map.get_unique(&2, &"alice@example.com", &"555-1234").is_none());
1607    /// # }
1608    /// ```
1609    pub fn get_unique<'a, Q1, Q2, Q3>(
1610        &'a self,
1611        key1: &Q1,
1612        key2: &Q2,
1613        key3: &Q3,
1614    ) -> Option<&'a T>
1615    where
1616        Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1617        Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1618        Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1619    {
1620        let index = self.find1_index(key1)?;
1621        let item = &self.items[index];
1622        if key2.equivalent(&item.key2()) && key3.equivalent(&item.key3()) {
1623            Some(item)
1624        } else {
1625            None
1626        }
1627    }
1628
1629    /// Gets a mutable reference to the unique item associated with the given
1630    /// `key1`, `key2`, and `key3`, if it exists.
1631    ///
1632    /// # Examples
1633    ///
1634    /// ```
1635    /// # #[cfg(feature = "default-hasher")] {
1636    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1637    ///
1638    /// #[derive(Debug, PartialEq, Eq)]
1639    /// struct Person {
1640    ///     id: u32,
1641    ///     email: String,
1642    ///     phone: String,
1643    ///     name: String,
1644    /// }
1645    ///
1646    /// impl TriHashItem for Person {
1647    ///     type K1<'a> = u32;
1648    ///     type K2<'a> = &'a str;
1649    ///     type K3<'a> = &'a str;
1650    ///
1651    ///     fn key1(&self) -> Self::K1<'_> {
1652    ///         self.id
1653    ///     }
1654    ///     fn key2(&self) -> Self::K2<'_> {
1655    ///         &self.email
1656    ///     }
1657    ///     fn key3(&self) -> Self::K3<'_> {
1658    ///         &self.phone
1659    ///     }
1660    ///     tri_upcast!();
1661    /// }
1662    ///
1663    /// let mut map = TriHashMap::new();
1664    /// map.insert_unique(Person {
1665    ///     id: 1,
1666    ///     email: "alice@example.com".to_string(),
1667    ///     phone: "555-1234".to_string(),
1668    ///     name: "Alice".to_string(),
1669    /// })
1670    /// .unwrap();
1671    ///
1672    /// // Modify the item through the mutable reference
1673    /// if let Some(mut person) =
1674    ///     map.get_mut_unique(&1, &"alice@example.com", &"555-1234")
1675    /// {
1676    ///     person.name = "Alice Updated".to_string();
1677    /// }
1678    ///
1679    /// // Verify the change
1680    /// assert_eq!(map.get1(&1).unwrap().name, "Alice Updated");
1681    /// # }
1682    /// ```
1683    pub fn get_mut_unique<'a, Q1, Q2, Q3>(
1684        &'a mut self,
1685        key1: &Q1,
1686        key2: &Q2,
1687        key3: &Q3,
1688    ) -> Option<RefMut<'a, T, S>>
1689    where
1690        Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1691        Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1692        Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1693    {
1694        let (dormant_map, index) = {
1695            let (map, dormant_map) = DormantMutRef::new(self);
1696            let index = map.find1_index(key1)?;
1697            let item = &map.items[index];
1698            if !key2.equivalent(&item.key2()) || !key3.equivalent(&item.key3())
1699            {
1700                return None;
1701            }
1702            (dormant_map, index)
1703        };
1704
1705        // SAFETY: `map` is not used after this point.
1706        let awakened_map = unsafe { dormant_map.awaken() };
1707        let item = &mut awakened_map.items[index];
1708        let state = awakened_map.tables.state.clone();
1709        let hashes = awakened_map.tables.make_hashes(&item);
1710        Some(RefMut::new(state, hashes, item))
1711    }
1712
1713    /// Removes the item uniquely identified by `key1`, `key2`, and `key3`, if
1714    /// it exists.
1715    ///
1716    /// # Examples
1717    ///
1718    /// ```
1719    /// # #[cfg(feature = "default-hasher")] {
1720    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1721    ///
1722    /// #[derive(Debug, PartialEq, Eq)]
1723    /// struct Person {
1724    ///     id: u32,
1725    ///     email: String,
1726    ///     phone: String,
1727    ///     name: String,
1728    /// }
1729    ///
1730    /// impl TriHashItem for Person {
1731    ///     type K1<'a> = u32;
1732    ///     type K2<'a> = &'a str;
1733    ///     type K3<'a> = &'a str;
1734    ///
1735    ///     fn key1(&self) -> Self::K1<'_> {
1736    ///         self.id
1737    ///     }
1738    ///     fn key2(&self) -> Self::K2<'_> {
1739    ///         &self.email
1740    ///     }
1741    ///     fn key3(&self) -> Self::K3<'_> {
1742    ///         &self.phone
1743    ///     }
1744    ///     tri_upcast!();
1745    /// }
1746    ///
1747    /// let mut map = TriHashMap::new();
1748    /// map.insert_unique(Person {
1749    ///     id: 1,
1750    ///     email: "alice@example.com".to_string(),
1751    ///     phone: "555-1234".to_string(),
1752    ///     name: "Alice".to_string(),
1753    /// })
1754    /// .unwrap();
1755    ///
1756    /// // Remove the item using all three keys
1757    /// let removed = map.remove_unique(&1, &"alice@example.com", &"555-1234");
1758    /// assert!(removed.is_some());
1759    /// assert_eq!(removed.unwrap().name, "Alice");
1760    ///
1761    /// // Map is now empty
1762    /// assert!(map.is_empty());
1763    ///
1764    /// // Trying to remove again returns None
1765    /// assert!(map.remove_unique(&1, &"alice@example.com", &"555-1234").is_none());
1766    /// # }
1767    /// ```
1768    pub fn remove_unique<'a, Q1, Q2, Q3>(
1769        &'a mut self,
1770        key1: &Q1,
1771        key2: &Q2,
1772        key3: &Q3,
1773    ) -> Option<T>
1774    where
1775        Q1: Hash + Equivalent<T::K1<'a>> + ?Sized,
1776        Q2: Hash + Equivalent<T::K2<'a>> + ?Sized,
1777        Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,
1778    {
1779        let (dormant_map, remove_index) = {
1780            let (map, dormant_map) = DormantMutRef::new(self);
1781            let remove_index = map.find1_index(key1)?;
1782            let item = &map.items[remove_index];
1783            if !key2.equivalent(&item.key2()) && !key3.equivalent(&item.key3())
1784            {
1785                return None;
1786            }
1787            (dormant_map, remove_index)
1788        };
1789
1790        // SAFETY: `map` is not used after this point.
1791        let awakened_map = unsafe { dormant_map.awaken() };
1792
1793        awakened_map.remove_by_index(remove_index)
1794    }
1795
1796    /// Returns true if the map contains the given `key1`.
1797    ///
1798    /// # Examples
1799    ///
1800    /// ```
1801    /// # #[cfg(feature = "default-hasher")] {
1802    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1803    ///
1804    /// #[derive(Debug, PartialEq, Eq)]
1805    /// struct Person {
1806    ///     id: u32,
1807    ///     email: String,
1808    ///     phone: String,
1809    ///     name: String,
1810    /// }
1811    ///
1812    /// impl TriHashItem for Person {
1813    ///     type K1<'a> = u32;
1814    ///     type K2<'a> = &'a str;
1815    ///     type K3<'a> = &'a str;
1816    ///
1817    ///     fn key1(&self) -> Self::K1<'_> {
1818    ///         self.id
1819    ///     }
1820    ///     fn key2(&self) -> Self::K2<'_> {
1821    ///         &self.email
1822    ///     }
1823    ///     fn key3(&self) -> Self::K3<'_> {
1824    ///         &self.phone
1825    ///     }
1826    ///     tri_upcast!();
1827    /// }
1828    ///
1829    /// let mut map = TriHashMap::new();
1830    /// map.insert_unique(Person {
1831    ///     id: 1,
1832    ///     email: "alice@example.com".to_string(),
1833    ///     phone: "555-1234".to_string(),
1834    ///     name: "Alice".to_string(),
1835    /// })
1836    /// .unwrap();
1837    ///
1838    /// assert!(map.contains_key1(&1));
1839    /// assert!(!map.contains_key1(&2));
1840    /// # }
1841    /// ```
1842    pub fn contains_key1<'a, Q>(&'a self, key1: &Q) -> bool
1843    where
1844        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
1845    {
1846        self.find1_index(key1).is_some()
1847    }
1848
1849    /// Gets a reference to the value associated with the given `key1`.
1850    ///
1851    /// # Examples
1852    ///
1853    /// ```
1854    /// # #[cfg(feature = "default-hasher")] {
1855    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1856    ///
1857    /// #[derive(Debug, PartialEq, Eq)]
1858    /// struct Person {
1859    ///     id: u32,
1860    ///     email: String,
1861    ///     phone: String,
1862    ///     name: String,
1863    /// }
1864    ///
1865    /// impl TriHashItem for Person {
1866    ///     type K1<'a> = u32;
1867    ///     type K2<'a> = &'a str;
1868    ///     type K3<'a> = &'a str;
1869    ///
1870    ///     fn key1(&self) -> Self::K1<'_> {
1871    ///         self.id
1872    ///     }
1873    ///     fn key2(&self) -> Self::K2<'_> {
1874    ///         &self.email
1875    ///     }
1876    ///     fn key3(&self) -> Self::K3<'_> {
1877    ///         &self.phone
1878    ///     }
1879    ///     tri_upcast!();
1880    /// }
1881    ///
1882    /// let mut map = TriHashMap::new();
1883    /// map.insert_unique(Person {
1884    ///     id: 1,
1885    ///     email: "alice@example.com".to_string(),
1886    ///     phone: "555-1234".to_string(),
1887    ///     name: "Alice".to_string(),
1888    /// })
1889    /// .unwrap();
1890    ///
1891    /// assert_eq!(map.get1(&1).unwrap().name, "Alice");
1892    /// assert!(map.get1(&2).is_none());
1893    /// # }
1894    /// ```
1895    pub fn get1<'a, Q>(&'a self, key1: &Q) -> Option<&'a T>
1896    where
1897        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
1898    {
1899        self.find1(key1)
1900    }
1901
1902    /// Gets a mutable reference to the value associated with the given `key1`.
1903    ///
1904    /// # Examples
1905    ///
1906    /// ```
1907    /// # #[cfg(feature = "default-hasher")] {
1908    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1909    ///
1910    /// #[derive(Debug, PartialEq, Eq)]
1911    /// struct Person {
1912    ///     id: u32,
1913    ///     email: String,
1914    ///     phone: String,
1915    ///     name: String,
1916    /// }
1917    ///
1918    /// impl TriHashItem for Person {
1919    ///     type K1<'a> = u32;
1920    ///     type K2<'a> = &'a str;
1921    ///     type K3<'a> = &'a str;
1922    ///
1923    ///     fn key1(&self) -> Self::K1<'_> {
1924    ///         self.id
1925    ///     }
1926    ///     fn key2(&self) -> Self::K2<'_> {
1927    ///         &self.email
1928    ///     }
1929    ///     fn key3(&self) -> Self::K3<'_> {
1930    ///         &self.phone
1931    ///     }
1932    ///     tri_upcast!();
1933    /// }
1934    ///
1935    /// let mut map = TriHashMap::new();
1936    /// map.insert_unique(Person {
1937    ///     id: 1,
1938    ///     email: "alice@example.com".to_string(),
1939    ///     phone: "555-1234".to_string(),
1940    ///     name: "Alice".to_string(),
1941    /// })
1942    /// .unwrap();
1943    ///
1944    /// if let Some(mut person) = map.get1_mut(&1) {
1945    ///     person.name = "Alice Updated".to_string();
1946    /// }
1947    ///
1948    /// assert_eq!(map.get1(&1).unwrap().name, "Alice Updated");
1949    /// # }
1950    /// ```
1951    pub fn get1_mut<'a, Q>(&'a mut self, key1: &Q) -> Option<RefMut<'a, T, S>>
1952    where
1953        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
1954    {
1955        let (dormant_map, index) = {
1956            let (map, dormant_map) = DormantMutRef::new(self);
1957            let index = map.find1_index(key1)?;
1958            (dormant_map, index)
1959        };
1960
1961        // SAFETY: `map` is not used after this point.
1962        let awakened_map = unsafe { dormant_map.awaken() };
1963        let item = &mut awakened_map.items[index];
1964        let state = awakened_map.tables.state.clone();
1965        let hashes = awakened_map.tables.make_hashes(&item);
1966        Some(RefMut::new(state, hashes, item))
1967    }
1968
1969    /// Removes an item from the map by its `key1`.
1970    ///
1971    /// # Examples
1972    ///
1973    /// ```
1974    /// # #[cfg(feature = "default-hasher")] {
1975    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
1976    ///
1977    /// #[derive(Debug, PartialEq, Eq)]
1978    /// struct Person {
1979    ///     id: u32,
1980    ///     email: String,
1981    ///     phone: String,
1982    ///     name: String,
1983    /// }
1984    ///
1985    /// impl TriHashItem for Person {
1986    ///     type K1<'a> = u32;
1987    ///     type K2<'a> = &'a str;
1988    ///     type K3<'a> = &'a str;
1989    ///
1990    ///     fn key1(&self) -> Self::K1<'_> {
1991    ///         self.id
1992    ///     }
1993    ///     fn key2(&self) -> Self::K2<'_> {
1994    ///         &self.email
1995    ///     }
1996    ///     fn key3(&self) -> Self::K3<'_> {
1997    ///         &self.phone
1998    ///     }
1999    ///     tri_upcast!();
2000    /// }
2001    ///
2002    /// let mut map = TriHashMap::new();
2003    /// map.insert_unique(Person {
2004    ///     id: 1,
2005    ///     email: "alice@example.com".to_string(),
2006    ///     phone: "555-1234".to_string(),
2007    ///     name: "Alice".to_string(),
2008    /// })
2009    /// .unwrap();
2010    ///
2011    /// let removed = map.remove1(&1);
2012    /// assert!(removed.is_some());
2013    /// assert_eq!(removed.unwrap().name, "Alice");
2014    /// assert!(map.is_empty());
2015    /// # }
2016    /// ```
2017    pub fn remove1<'a, Q>(&'a mut self, key1: &Q) -> Option<T>
2018    where
2019        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
2020    {
2021        let (dormant_map, remove_index) = {
2022            let (map, dormant_map) = DormantMutRef::new(self);
2023            let remove_index = map.find1_index(key1)?;
2024            (dormant_map, remove_index)
2025        };
2026
2027        // SAFETY: `map` is not used after this point.
2028        let awakened_map = unsafe { dormant_map.awaken() };
2029
2030        awakened_map.remove_by_index(remove_index)
2031    }
2032
2033    /// Returns true if the map contains the given `key2`.
2034    ///
2035    /// # Examples
2036    ///
2037    /// ```
2038    /// # #[cfg(feature = "default-hasher")] {
2039    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2040    ///
2041    /// #[derive(Debug, PartialEq, Eq)]
2042    /// struct Person {
2043    ///     id: u32,
2044    ///     email: String,
2045    ///     phone: String,
2046    ///     name: String,
2047    /// }
2048    ///
2049    /// impl TriHashItem for Person {
2050    ///     type K1<'a> = u32;
2051    ///     type K2<'a> = &'a str;
2052    ///     type K3<'a> = &'a str;
2053    ///
2054    ///     fn key1(&self) -> Self::K1<'_> {
2055    ///         self.id
2056    ///     }
2057    ///     fn key2(&self) -> Self::K2<'_> {
2058    ///         &self.email
2059    ///     }
2060    ///     fn key3(&self) -> Self::K3<'_> {
2061    ///         &self.phone
2062    ///     }
2063    ///     tri_upcast!();
2064    /// }
2065    ///
2066    /// let mut map = TriHashMap::new();
2067    /// map.insert_unique(Person {
2068    ///     id: 1,
2069    ///     email: "alice@example.com".to_string(),
2070    ///     phone: "555-1234".to_string(),
2071    ///     name: "Alice".to_string(),
2072    /// })
2073    /// .unwrap();
2074    ///
2075    /// assert!(map.contains_key2("alice@example.com"));
2076    /// assert!(!map.contains_key2("bob@example.com"));
2077    /// # }
2078    /// ```
2079    pub fn contains_key2<'a, Q>(&'a self, key2: &Q) -> bool
2080    where
2081        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2082    {
2083        self.find2_index(key2).is_some()
2084    }
2085
2086    /// Gets a reference to the value associated with the given `key2`.
2087    ///
2088    /// # Examples
2089    ///
2090    /// ```
2091    /// # #[cfg(feature = "default-hasher")] {
2092    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2093    ///
2094    /// #[derive(Debug, PartialEq, Eq)]
2095    /// struct Person {
2096    ///     id: u32,
2097    ///     email: String,
2098    ///     phone: String,
2099    ///     name: String,
2100    /// }
2101    ///
2102    /// impl TriHashItem for Person {
2103    ///     type K1<'a> = u32;
2104    ///     type K2<'a> = &'a str;
2105    ///     type K3<'a> = &'a str;
2106    ///
2107    ///     fn key1(&self) -> Self::K1<'_> {
2108    ///         self.id
2109    ///     }
2110    ///     fn key2(&self) -> Self::K2<'_> {
2111    ///         &self.email
2112    ///     }
2113    ///     fn key3(&self) -> Self::K3<'_> {
2114    ///         &self.phone
2115    ///     }
2116    ///     tri_upcast!();
2117    /// }
2118    ///
2119    /// let mut map = TriHashMap::new();
2120    /// map.insert_unique(Person {
2121    ///     id: 1,
2122    ///     email: "alice@example.com".to_string(),
2123    ///     phone: "555-1234".to_string(),
2124    ///     name: "Alice".to_string(),
2125    /// })
2126    /// .unwrap();
2127    ///
2128    /// assert_eq!(map.get2("alice@example.com").unwrap().name, "Alice");
2129    /// assert!(map.get2("bob@example.com").is_none());
2130    /// # }
2131    /// ```
2132    pub fn get2<'a, Q>(&'a self, key2: &Q) -> Option<&'a T>
2133    where
2134        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2135    {
2136        self.find2(key2)
2137    }
2138
2139    /// Gets a mutable reference to the value associated with the given `key2`.
2140    ///
2141    /// # Examples
2142    ///
2143    /// ```
2144    /// # #[cfg(feature = "default-hasher")] {
2145    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2146    ///
2147    /// #[derive(Debug, PartialEq, Eq)]
2148    /// struct Person {
2149    ///     id: u32,
2150    ///     email: String,
2151    ///     phone: String,
2152    ///     name: String,
2153    /// }
2154    ///
2155    /// impl TriHashItem for Person {
2156    ///     type K1<'a> = u32;
2157    ///     type K2<'a> = &'a str;
2158    ///     type K3<'a> = &'a str;
2159    ///
2160    ///     fn key1(&self) -> Self::K1<'_> {
2161    ///         self.id
2162    ///     }
2163    ///     fn key2(&self) -> Self::K2<'_> {
2164    ///         &self.email
2165    ///     }
2166    ///     fn key3(&self) -> Self::K3<'_> {
2167    ///         &self.phone
2168    ///     }
2169    ///     tri_upcast!();
2170    /// }
2171    ///
2172    /// let mut map = TriHashMap::new();
2173    /// map.insert_unique(Person {
2174    ///     id: 1,
2175    ///     email: "alice@example.com".to_string(),
2176    ///     phone: "555-1234".to_string(),
2177    ///     name: "Alice".to_string(),
2178    /// })
2179    /// .unwrap();
2180    ///
2181    /// if let Some(mut person) = map.get2_mut("alice@example.com") {
2182    ///     person.name = "Alice Updated".to_string();
2183    /// }
2184    ///
2185    /// assert_eq!(map.get2("alice@example.com").unwrap().name, "Alice Updated");
2186    /// # }
2187    /// ```
2188    pub fn get2_mut<'a, Q>(&'a mut self, key2: &Q) -> Option<RefMut<'a, T, S>>
2189    where
2190        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2191    {
2192        let (dormant_map, index) = {
2193            let (map, dormant_map) = DormantMutRef::new(self);
2194            let index = map.find2_index(key2)?;
2195            (dormant_map, index)
2196        };
2197
2198        // SAFETY: `map` is not used after this point.
2199        let awakened_map = unsafe { dormant_map.awaken() };
2200        let item = &mut awakened_map.items[index];
2201        let state = awakened_map.tables.state.clone();
2202        let hashes = awakened_map.tables.make_hashes(&item);
2203        Some(RefMut::new(state, hashes, item))
2204    }
2205
2206    /// Removes an item from the map by its `key2`.
2207    ///
2208    /// # Examples
2209    ///
2210    /// ```
2211    /// # #[cfg(feature = "default-hasher")] {
2212    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2213    ///
2214    /// #[derive(Debug, PartialEq, Eq)]
2215    /// struct Person {
2216    ///     id: u32,
2217    ///     email: String,
2218    ///     phone: String,
2219    ///     name: String,
2220    /// }
2221    ///
2222    /// impl TriHashItem for Person {
2223    ///     type K1<'a> = u32;
2224    ///     type K2<'a> = &'a str;
2225    ///     type K3<'a> = &'a str;
2226    ///
2227    ///     fn key1(&self) -> Self::K1<'_> {
2228    ///         self.id
2229    ///     }
2230    ///     fn key2(&self) -> Self::K2<'_> {
2231    ///         &self.email
2232    ///     }
2233    ///     fn key3(&self) -> Self::K3<'_> {
2234    ///         &self.phone
2235    ///     }
2236    ///     tri_upcast!();
2237    /// }
2238    ///
2239    /// let mut map = TriHashMap::new();
2240    /// map.insert_unique(Person {
2241    ///     id: 1,
2242    ///     email: "alice@example.com".to_string(),
2243    ///     phone: "555-1234".to_string(),
2244    ///     name: "Alice".to_string(),
2245    /// })
2246    /// .unwrap();
2247    ///
2248    /// let removed = map.remove2("alice@example.com");
2249    /// assert!(removed.is_some());
2250    /// assert_eq!(removed.unwrap().name, "Alice");
2251    /// assert!(map.is_empty());
2252    /// # }
2253    /// ```
2254    pub fn remove2<'a, Q>(&'a mut self, key2: &Q) -> Option<T>
2255    where
2256        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2257    {
2258        let (dormant_map, remove_index) = {
2259            let (map, dormant_map) = DormantMutRef::new(self);
2260            let remove_index = map.find2_index(key2)?;
2261            (dormant_map, remove_index)
2262        };
2263
2264        // SAFETY: `map` is not used after this point.
2265        let awakened_map = unsafe { dormant_map.awaken() };
2266
2267        awakened_map.remove_by_index(remove_index)
2268    }
2269
2270    /// Returns true if the map contains the given `key3`.
2271    ///
2272    /// # Examples
2273    ///
2274    /// ```
2275    /// # #[cfg(feature = "default-hasher")] {
2276    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2277    ///
2278    /// #[derive(Debug, PartialEq, Eq)]
2279    /// struct Person {
2280    ///     id: u32,
2281    ///     email: String,
2282    ///     phone: String,
2283    ///     name: String,
2284    /// }
2285    ///
2286    /// impl TriHashItem for Person {
2287    ///     type K1<'a> = u32;
2288    ///     type K2<'a> = &'a str;
2289    ///     type K3<'a> = &'a str;
2290    ///
2291    ///     fn key1(&self) -> Self::K1<'_> {
2292    ///         self.id
2293    ///     }
2294    ///     fn key2(&self) -> Self::K2<'_> {
2295    ///         &self.email
2296    ///     }
2297    ///     fn key3(&self) -> Self::K3<'_> {
2298    ///         &self.phone
2299    ///     }
2300    ///     tri_upcast!();
2301    /// }
2302    ///
2303    /// let mut map = TriHashMap::new();
2304    /// map.insert_unique(Person {
2305    ///     id: 1,
2306    ///     email: "alice@example.com".to_string(),
2307    ///     phone: "555-1234".to_string(),
2308    ///     name: "Alice".to_string(),
2309    /// })
2310    /// .unwrap();
2311    ///
2312    /// assert!(map.contains_key3("555-1234"));
2313    /// assert!(!map.contains_key3("555-5678"));
2314    /// # }
2315    /// ```
2316    pub fn contains_key3<'a, Q>(&'a self, key3: &Q) -> bool
2317    where
2318        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2319    {
2320        self.find3_index(key3).is_some()
2321    }
2322
2323    /// Gets a reference to the value associated with the given `key3`.
2324    ///
2325    /// # Examples
2326    ///
2327    /// ```
2328    /// # #[cfg(feature = "default-hasher")] {
2329    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2330    ///
2331    /// #[derive(Debug, PartialEq, Eq)]
2332    /// struct Person {
2333    ///     id: u32,
2334    ///     email: String,
2335    ///     phone: String,
2336    ///     name: String,
2337    /// }
2338    ///
2339    /// impl TriHashItem for Person {
2340    ///     type K1<'a> = u32;
2341    ///     type K2<'a> = &'a str;
2342    ///     type K3<'a> = &'a str;
2343    ///
2344    ///     fn key1(&self) -> Self::K1<'_> {
2345    ///         self.id
2346    ///     }
2347    ///     fn key2(&self) -> Self::K2<'_> {
2348    ///         &self.email
2349    ///     }
2350    ///     fn key3(&self) -> Self::K3<'_> {
2351    ///         &self.phone
2352    ///     }
2353    ///     tri_upcast!();
2354    /// }
2355    ///
2356    /// let mut map = TriHashMap::new();
2357    /// map.insert_unique(Person {
2358    ///     id: 1,
2359    ///     email: "alice@example.com".to_string(),
2360    ///     phone: "555-1234".to_string(),
2361    ///     name: "Alice".to_string(),
2362    /// })
2363    /// .unwrap();
2364    ///
2365    /// assert_eq!(map.get3("555-1234").unwrap().name, "Alice");
2366    /// assert!(map.get3("555-5678").is_none());
2367    /// # }
2368    /// ```
2369    pub fn get3<'a, Q>(&'a self, key3: &Q) -> Option<&'a T>
2370    where
2371        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2372    {
2373        self.find3(key3)
2374    }
2375
2376    /// Gets a mutable reference to the value associated with the given `key3`.
2377    ///
2378    /// # Examples
2379    ///
2380    /// ```
2381    /// # #[cfg(feature = "default-hasher")] {
2382    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2383    ///
2384    /// #[derive(Debug, PartialEq, Eq)]
2385    /// struct Person {
2386    ///     id: u32,
2387    ///     email: String,
2388    ///     phone: String,
2389    ///     name: String,
2390    /// }
2391    ///
2392    /// impl TriHashItem for Person {
2393    ///     type K1<'a> = u32;
2394    ///     type K2<'a> = &'a str;
2395    ///     type K3<'a> = &'a str;
2396    ///
2397    ///     fn key1(&self) -> Self::K1<'_> {
2398    ///         self.id
2399    ///     }
2400    ///     fn key2(&self) -> Self::K2<'_> {
2401    ///         &self.email
2402    ///     }
2403    ///     fn key3(&self) -> Self::K3<'_> {
2404    ///         &self.phone
2405    ///     }
2406    ///     tri_upcast!();
2407    /// }
2408    ///
2409    /// let mut map = TriHashMap::new();
2410    /// map.insert_unique(Person {
2411    ///     id: 1,
2412    ///     email: "alice@example.com".to_string(),
2413    ///     phone: "555-1234".to_string(),
2414    ///     name: "Alice".to_string(),
2415    /// })
2416    /// .unwrap();
2417    ///
2418    /// if let Some(mut person) = map.get3_mut("555-1234") {
2419    ///     person.name = "Alice Updated".to_string();
2420    /// }
2421    ///
2422    /// assert_eq!(map.get3("555-1234").unwrap().name, "Alice Updated");
2423    /// # }
2424    /// ```
2425    pub fn get3_mut<'a, Q>(&'a mut self, key3: &Q) -> Option<RefMut<'a, T, S>>
2426    where
2427        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2428    {
2429        let (dormant_map, index) = {
2430            let (map, dormant_map) = DormantMutRef::new(self);
2431            let index = map.find3_index(key3)?;
2432            (dormant_map, index)
2433        };
2434
2435        // SAFETY: `map` is not used after this point.
2436        let awakened_map = unsafe { dormant_map.awaken() };
2437        let item = &mut awakened_map.items[index];
2438        let state = awakened_map.tables.state.clone();
2439        let hashes = awakened_map.tables.make_hashes(&item);
2440        Some(RefMut::new(state, hashes, item))
2441    }
2442
2443    /// Removes an item from the map by its `key3`.
2444    ///
2445    /// # Examples
2446    ///
2447    /// ```
2448    /// # #[cfg(feature = "default-hasher")] {
2449    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2450    ///
2451    /// #[derive(Debug, PartialEq, Eq)]
2452    /// struct Person {
2453    ///     id: u32,
2454    ///     email: String,
2455    ///     phone: String,
2456    ///     name: String,
2457    /// }
2458    ///
2459    /// impl TriHashItem for Person {
2460    ///     type K1<'a> = u32;
2461    ///     type K2<'a> = &'a str;
2462    ///     type K3<'a> = &'a str;
2463    ///
2464    ///     fn key1(&self) -> Self::K1<'_> {
2465    ///         self.id
2466    ///     }
2467    ///     fn key2(&self) -> Self::K2<'_> {
2468    ///         &self.email
2469    ///     }
2470    ///     fn key3(&self) -> Self::K3<'_> {
2471    ///         &self.phone
2472    ///     }
2473    ///     tri_upcast!();
2474    /// }
2475    ///
2476    /// let mut map = TriHashMap::new();
2477    /// map.insert_unique(Person {
2478    ///     id: 1,
2479    ///     email: "alice@example.com".to_string(),
2480    ///     phone: "555-1234".to_string(),
2481    ///     name: "Alice".to_string(),
2482    /// })
2483    /// .unwrap();
2484    ///
2485    /// let removed = map.remove3("555-1234");
2486    /// assert!(removed.is_some());
2487    /// assert_eq!(removed.unwrap().name, "Alice");
2488    /// assert!(map.is_empty());
2489    /// # }
2490    /// ```
2491    pub fn remove3<'a, Q>(&'a mut self, key3: &Q) -> Option<T>
2492    where
2493        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2494    {
2495        let (dormant_map, remove_index) = {
2496            let (map, dormant_map) = DormantMutRef::new(self);
2497            let remove_index = map.find3_index(key3)?;
2498            (dormant_map, remove_index)
2499        };
2500
2501        // SAFETY: `map` is not used after this point.
2502        let awakened_map = unsafe { dormant_map.awaken() };
2503
2504        awakened_map.remove_by_index(remove_index)
2505    }
2506
2507    /// Retains only the elements specified by the predicate.
2508    ///
2509    /// In other words, remove all items `T` for which `f(RefMut<T>)` returns
2510    /// false. The elements are visited in an arbitrary order.
2511    ///
2512    /// The `RefMut<T, S>` wrapper allows mutable access to the item while
2513    /// enforcing that the three keys (`K1`, `K2`, `K3`) remain unchanged. If
2514    /// a key is modified during iteration, the method will panic.
2515    ///
2516    /// # Performance considerations
2517    ///
2518    /// This method may leave the internal storage fragmented. If you need
2519    /// compact storage afterward, call `make_compact()`.
2520    ///
2521    /// # Examples
2522    ///
2523    /// ```
2524    /// # #[cfg(feature = "default-hasher")] {
2525    /// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
2526    ///
2527    /// #[derive(Debug, PartialEq, Eq, Hash)]
2528    /// struct Item {
2529    ///     id: u32,
2530    ///     name: String,
2531    ///     code: String,
2532    ///     value: u32,
2533    /// }
2534    ///
2535    /// impl TriHashItem for Item {
2536    ///     type K1<'a> = u32;
2537    ///     type K2<'a> = &'a str;
2538    ///     type K3<'a> = &'a str;
2539    ///
2540    ///     fn key1(&self) -> Self::K1<'_> {
2541    ///         self.id
2542    ///     }
2543    ///     fn key2(&self) -> Self::K2<'_> {
2544    ///         &self.name
2545    ///     }
2546    ///     fn key3(&self) -> Self::K3<'_> {
2547    ///         &self.code
2548    ///     }
2549    ///
2550    ///     tri_upcast!();
2551    /// }
2552    ///
2553    /// let mut map = TriHashMap::new();
2554    /// map.insert_unique(Item {
2555    ///     id: 1,
2556    ///     name: "foo".to_string(),
2557    ///     code: "x".to_string(),
2558    ///     value: 42,
2559    /// })
2560    /// .unwrap();
2561    /// map.insert_unique(Item {
2562    ///     id: 2,
2563    ///     name: "bar".to_string(),
2564    ///     code: "y".to_string(),
2565    ///     value: 20,
2566    /// })
2567    /// .unwrap();
2568    /// map.insert_unique(Item {
2569    ///     id: 3,
2570    ///     name: "baz".to_string(),
2571    ///     code: "z".to_string(),
2572    ///     value: 99,
2573    /// })
2574    /// .unwrap();
2575    ///
2576    /// // Retain only items where value is greater than 30
2577    /// map.retain(|item| item.value > 30);
2578    ///
2579    /// assert_eq!(map.len(), 2);
2580    /// assert_eq!(map.get1(&1).unwrap().value, 42);
2581    /// assert_eq!(map.get1(&3).unwrap().value, 99);
2582    /// assert!(map.get1(&2).is_none());
2583    /// # }
2584    /// ```
2585    pub fn retain<'a, F>(&'a mut self, mut f: F)
2586    where
2587        F: FnMut(RefMut<'a, T, S>) -> bool,
2588    {
2589        let hash_state = self.tables.state.clone();
2590        let (_, mut dormant_items) = DormantMutRef::new(&mut self.items);
2591
2592        self.tables.k1_to_item.retain(|index| {
2593            let (item, dormant_items) = {
2594                // SAFETY: All uses of `items` ended in the previous iteration.
2595                let items = unsafe { dormant_items.reborrow() };
2596                let (items, dormant_items) = DormantMutRef::new(items);
2597                let item: &'a mut T = items
2598                    .get_mut(index)
2599                    .expect("all indexes are present in self.items");
2600                (item, dormant_items)
2601            };
2602
2603            let (hashes, dormant_item) = {
2604                let (item, dormant_item): (&'a mut T, _) =
2605                    DormantMutRef::new(item);
2606                // Use T::k1(item) rather than item.key() to force the key
2607                // trait function to be called for T rather than &mut T.
2608                let key1 = T::key1(item);
2609                let key2 = T::key2(item);
2610                let key3 = T::key3(item);
2611                let hash1 = hash_state.hash_one(key1);
2612                let hash2 = hash_state.hash_one(key2);
2613                let hash3 = hash_state.hash_one(key3);
2614                (
2615                    [
2616                        MapHash::new(hash1),
2617                        MapHash::new(hash2),
2618                        MapHash::new(hash3),
2619                    ],
2620                    dormant_item,
2621                )
2622            };
2623
2624            let hash2 = hashes[1].hash();
2625            let hash3 = hashes[2].hash();
2626            let retain = {
2627                // SAFETY: The original item is no longer used after the second
2628                // block above. dormant_items, from which item is derived, is
2629                // currently dormant.
2630                let item = unsafe { dormant_item.awaken() };
2631
2632                let ref_mut = RefMut::new(hash_state.clone(), hashes, item);
2633                f(ref_mut)
2634            };
2635
2636            if retain {
2637                true
2638            } else {
2639                // SAFETY: The original items is no longer used after the first
2640                // block above, and item + dormant_item have been dropped after
2641                // being used above.
2642                let items = unsafe { dormant_items.awaken() };
2643                items.remove(index);
2644                let k2_entry = self
2645                    .tables
2646                    .k2_to_item
2647                    .find_entry_by_hash(hash2, |map2_index| {
2648                        map2_index == index
2649                    });
2650                let k3_entry = self
2651                    .tables
2652                    .k3_to_item
2653                    .find_entry_by_hash(hash3, |map3_index| {
2654                        map3_index == index
2655                    });
2656
2657                let mut is_inconsistent = false;
2658                if let Ok(k2_entry) = k2_entry {
2659                    k2_entry.remove();
2660                } else {
2661                    is_inconsistent = true;
2662                }
2663                if let Ok(k3_entry) = k3_entry {
2664                    k3_entry.remove();
2665                } else {
2666                    is_inconsistent = true;
2667                }
2668                if is_inconsistent {
2669                    // This happening means there's an inconsistency among
2670                    // the maps.
2671                    panic!(
2672                        "inconsistency among k1_to_item, k2_to_item, k3_to_item"
2673                    );
2674                }
2675
2676                false
2677            }
2678        });
2679    }
2680
2681    fn find1<'a, Q>(&'a self, k: &Q) -> Option<&'a T>
2682    where
2683        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
2684    {
2685        self.find1_index(k).map(|ix| &self.items[ix])
2686    }
2687
2688    fn find1_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
2689    where
2690        Q: Hash + Equivalent<T::K1<'a>> + ?Sized,
2691    {
2692        self.tables
2693            .k1_to_item
2694            .find_index(&self.tables.state, k, |index| self.items[index].key1())
2695    }
2696
2697    fn find2<'a, Q>(&'a self, k: &Q) -> Option<&'a T>
2698    where
2699        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2700    {
2701        self.find2_index(k).map(|ix| &self.items[ix])
2702    }
2703
2704    fn find2_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
2705    where
2706        Q: Hash + Equivalent<T::K2<'a>> + ?Sized,
2707    {
2708        self.tables
2709            .k2_to_item
2710            .find_index(&self.tables.state, k, |index| self.items[index].key2())
2711    }
2712
2713    fn find3<'a, Q>(&'a self, k: &Q) -> Option<&'a T>
2714    where
2715        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2716    {
2717        self.find3_index(k).map(|ix| &self.items[ix])
2718    }
2719
2720    fn find3_index<'a, Q>(&'a self, k: &Q) -> Option<ItemIndex>
2721    where
2722        Q: Hash + Equivalent<T::K3<'a>> + ?Sized,
2723    {
2724        self.tables
2725            .k3_to_item
2726            .find_index(&self.tables.state, k, |index| self.items[index].key3())
2727    }
2728
2729    pub(super) fn remove_by_index(
2730        &mut self,
2731        remove_index: ItemIndex,
2732    ) -> Option<T> {
2733        // For panic safety, look up all three table entries while `self.items`
2734        // still holds the value, then remove from all three tables and items
2735        // in sequence. hashbrown's `find_entry` is panic-safe under
2736        // user-`Hash`/`Eq` panics (the table is not mutated until
2737        // `OccupiedEntry::remove` is called), so a panic during the lookups
2738        // leaves items and all three tables unmodified.
2739        let item = self.items.get(remove_index)?;
2740        let key1 = item.key1();
2741        let key2 = item.key2();
2742        let key3 = item.key3();
2743        let state = &self.tables.state;
2744        let Ok(entry1) =
2745            self.tables
2746                .k1_to_item
2747                .find_entry(state, &key1, |index| self.items[index].key1())
2748        else {
2749            panic!("remove_index {remove_index} not found in k1_to_item");
2750        };
2751        let Ok(entry2) =
2752            self.tables
2753                .k2_to_item
2754                .find_entry(state, &key2, |index| self.items[index].key2())
2755        else {
2756            panic!("remove_index {remove_index} not found in k2_to_item");
2757        };
2758        let Ok(entry3) =
2759            self.tables
2760                .k3_to_item
2761                .find_entry(state, &key3, |index| self.items[index].key3())
2762        else {
2763            panic!("remove_index {remove_index} not found in k3_to_item");
2764        };
2765        // Drop the keys so that `self.items` can be mutated below.
2766        drop((key1, key2, key3));
2767        entry1.remove();
2768        entry2.remove();
2769        entry3.remove();
2770        Some(
2771            self.items
2772                .remove(remove_index)
2773                .expect("items[remove_index] was Occupied above"),
2774        )
2775    }
2776}
2777
2778impl<'a, T, S, A: Allocator> fmt::Debug for TriHashMap<T, S, A>
2779where
2780    T: TriHashItem + fmt::Debug,
2781    T::K1<'a>: fmt::Debug,
2782    T::K2<'a>: fmt::Debug,
2783    T::K3<'a>: fmt::Debug,
2784    T: 'a,
2785{
2786    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2787        let mut map = f.debug_map();
2788        for item in self.items.values() {
2789            let key: KeyMap<'_, T> = KeyMap {
2790                key1: item.key1(),
2791                key2: item.key2(),
2792                key3: item.key3(),
2793            };
2794
2795            // SAFETY:
2796            //
2797            // * Lifetime extension: for a type T and two lifetime params 'a and
2798            //   'b, T<'a> and T<'b> aren't guaranteed to have the same layout,
2799            //   but (a) that is true today and (b) it would be shocking and
2800            //   break half the Rust ecosystem if that were to change in the
2801            //   future.
2802            // * We only use key within the scope of this block before immediately
2803            //   dropping it. In particular, map.entry calls key.fmt() without
2804            //   holding a reference to it.
2805            let key: KeyMap<'a, T> = unsafe {
2806                core::mem::transmute::<KeyMap<'_, T>, KeyMap<'a, T>>(key)
2807            };
2808
2809            map.entry(&key, item);
2810        }
2811        map.finish()
2812    }
2813}
2814
2815struct KeyMap<'a, T: TriHashItem + 'a> {
2816    key1: T::K1<'a>,
2817    key2: T::K2<'a>,
2818    key3: T::K3<'a>,
2819}
2820
2821impl<'a, T: TriHashItem> fmt::Debug for KeyMap<'a, T>
2822where
2823    T::K1<'a>: fmt::Debug,
2824    T::K2<'a>: fmt::Debug,
2825    T::K3<'a>: fmt::Debug,
2826{
2827    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2828        // We don't want to show key1 and key2 as a tuple since it's
2829        // misleading (suggests maps of tuples). The best we can do
2830        // instead is to show "{k1: abc, k2: xyz, k3: def}"
2831        f.debug_map()
2832            .entry(&StrDisplayAsDebug("k1"), &self.key1)
2833            .entry(&StrDisplayAsDebug("k2"), &self.key2)
2834            .entry(&StrDisplayAsDebug("k3"), &self.key3)
2835            .finish()
2836    }
2837}
2838
2839impl<T: TriHashItem + PartialEq, S: Clone + BuildHasher, A: Allocator> PartialEq
2840    for TriHashMap<T, S, A>
2841{
2842    fn eq(&self, other: &Self) -> bool {
2843        // Implementing PartialEq for TriHashMap is tricky because TriHashMap is
2844        // not semantically like an IndexMap: two maps are equivalent even if
2845        // their items are in a different order. In other words, any permutation
2846        // of items is equivalent.
2847        //
2848        // We also can't sort the items because they're not necessarily Ord.
2849        //
2850        // So we write a custom equality check that checks that each key in one
2851        // map points to the same item as in the other map.
2852
2853        if self.items.len() != other.items.len() {
2854            return false;
2855        }
2856
2857        // Walk over all the items in the first map and check that they point to
2858        // the same item in the second map.
2859        for item in self.items.values() {
2860            let k1 = item.key1();
2861            let k2 = item.key2();
2862            let k3 = item.key3();
2863
2864            // Check that the indexes are the same in the other map.
2865            let Some(other_ix1) = other.find1_index(&k1) else {
2866                return false;
2867            };
2868            let Some(other_ix2) = other.find2_index(&k2) else {
2869                return false;
2870            };
2871            let Some(other_ix3) = other.find3_index(&k3) else {
2872                return false;
2873            };
2874
2875            if other_ix1 != other_ix2 || other_ix1 != other_ix3 {
2876                // All the keys were present but they didn't point to the same
2877                // item.
2878                return false;
2879            }
2880
2881            // Check that the other map's item is the same as this map's
2882            // item. (This is what we use the `PartialEq` bound on T for.)
2883            //
2884            // Because we've checked that other_ix1, other_ix2 and other_ix3 are
2885            // Some, we know that it is valid and points to the expected item.
2886            let other_item = &other.items[other_ix1];
2887            if item != other_item {
2888                return false;
2889            }
2890        }
2891
2892        true
2893    }
2894}
2895
2896// The Eq bound on T ensures that the TriHashMap forms an equivalence class.
2897impl<T: TriHashItem + Eq, S: Clone + BuildHasher, A: Allocator> Eq
2898    for TriHashMap<T, S, A>
2899{
2900}
2901
2902/// The `Extend` implementation overwrites duplicates. In the future, there will
2903/// also be an `extend_unique` method that will return an error.
2904impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> Extend<T>
2905    for TriHashMap<T, S, A>
2906{
2907    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
2908        // Keys may already be present in the map, or multiple times in the
2909        // iterator. Reserve the entire hint lower bound if the map is empty.
2910        // Otherwise reserve half the hint (rounded up), so the map will only
2911        // resize twice in the worst case.
2912        let iter = iter.into_iter();
2913        let reserve = if self.is_empty() {
2914            iter.size_hint().0
2915        } else {
2916            iter.size_hint().0.div_ceil(2)
2917        };
2918        self.reserve(reserve);
2919        for item in iter {
2920            self.insert_overwrite(item);
2921        }
2922    }
2923}
2924
2925fn detect_dup_or_insert<'a, A: Allocator>(
2926    item: Entry<'a, ItemIndex, AllocWrapper<A>>,
2927    duplicates: &mut BTreeSet<ItemIndex>,
2928) -> Option<VacantEntry<'a, ItemIndex, AllocWrapper<A>>> {
2929    match item {
2930        Entry::Vacant(slot) => Some(slot),
2931        Entry::Occupied(slot) => {
2932            duplicates.insert(*slot.get());
2933            None
2934        }
2935    }
2936}
2937
2938impl<'a, T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
2939    for &'a TriHashMap<T, S, A>
2940{
2941    type Item = &'a T;
2942    type IntoIter = Iter<'a, T>;
2943
2944    #[inline]
2945    fn into_iter(self) -> Self::IntoIter {
2946        self.iter()
2947    }
2948}
2949
2950impl<'a, T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
2951    for &'a mut TriHashMap<T, S, A>
2952{
2953    type Item = RefMut<'a, T, S>;
2954    type IntoIter = IterMut<'a, T, S, A>;
2955
2956    #[inline]
2957    fn into_iter(self) -> Self::IntoIter {
2958        self.iter_mut()
2959    }
2960}
2961
2962impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator
2963    for TriHashMap<T, S, A>
2964{
2965    type Item = T;
2966    type IntoIter = IntoIter<T, A>;
2967
2968    #[inline]
2969    fn into_iter(self) -> Self::IntoIter {
2970        IntoIter::new(self.items)
2971    }
2972}
2973
2974/// The `FromIterator` implementation for `TriHashMap` overwrites duplicate
2975/// items.
2976impl<T: TriHashItem, S: Default + Clone + BuildHasher, A: Default + Allocator>
2977    FromIterator<T> for TriHashMap<T, S, A>
2978{
2979    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
2980        let mut map = TriHashMap::default();
2981        for item in iter {
2982            map.insert_overwrite(item);
2983        }
2984        map
2985    }
2986}