Skip to main content

axhash_indexmap/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4#[cfg(not(feature = "std"))]
5extern crate alloc;
6
7use core::fmt;
8use core::hash::{BuildHasher, BuildHasherDefault, Hash};
9use core::ops::{Deref, DerefMut, Index};
10
11// ── Re-exports ────────────────────────────────────────────────────────────────
12
13/// The [`BuildHasher`](core::hash::BuildHasher) used for seeded / custom
14/// construction via [`AxIndexMap::with_hasher`].
15pub use axhash_core::{AxBuildHasher, AxHasher};
16
17/// Raw `indexmap::IndexMap` — available without a direct `indexmap` dep.
18pub use indexmap::IndexMap as RawIndexMap;
19
20/// Raw `indexmap::IndexSet` — available without a direct `indexmap` dep.
21pub use indexmap::IndexSet as RawIndexSet;
22
23/// [`indexmap::map::Entry`] re-exported for ergonomic `match` arms.
24pub use indexmap::map::Entry as MapEntry;
25pub use indexmap::map::OccupiedEntry as MapOccupiedEntry;
26pub use indexmap::map::VacantEntry as MapVacantEntry;
27
28// ── Compatibility type aliases ────────────────────────────────────────────────
29// These expose raw `indexmap` types with `AxHasher` baked in via the
30// standard-library `BuildHasherDefault<H>` adaptor.  Because they are plain
31// type aliases (no wrapper struct), third-party crates such as Serde can
32// derive `Serialize` / `Deserialize` on structs that contain them without
33// any extra configuration.
34
35/// Drop-in `indexmap::IndexMap` with [`AxHasher`] as the default hasher.
36/// Insertion order is fully preserved.  Use this alias when maximum
37/// third-party compatibility matters (e.g. Serde `#[derive]`).
38pub type IndexMap<K, V> = RawIndexMap<K, V, BuildHasherDefault<AxHasher>>;
39
40/// Drop-in `indexmap::IndexSet` with [`AxHasher`] as the default hasher.
41/// Insertion order is fully preserved.  Use this alias when maximum
42/// third-party compatibility matters (e.g. Serde `#[derive]`).
43pub type IndexSet<T> = RawIndexSet<T, BuildHasherDefault<AxHasher>>;
44
45// ── AxIndexMap ────────────────────────────────────────────────────────────────
46/// `AxIndexMap<K, V>` is a thin newtype wrapper around [`IndexMap<K, V>`] that
47/// adds the familiar `::new()` / `::with_capacity()` constructor syntax (which
48/// `indexmap` 2.x only provides on the default-`RandomState` form).
49/// Every method on `indexmap::IndexMap` is accessible via `Deref`.
50pub struct AxIndexMap<K, V, S = BuildHasherDefault<AxHasher>>(RawIndexMap<K, V, S>);
51
52impl<K, V> AxIndexMap<K, V, BuildHasherDefault<AxHasher>> {
53    /// Creates an empty map with the default [`AxHasher`].
54    ///
55    /// The map is initially created with a capacity of 0.
56    #[inline(always)]
57    pub fn new() -> Self {
58        Self(RawIndexMap::with_hasher(BuildHasherDefault::default()))
59    }
60
61    /// Creates an empty map with at least the given capacity and the default
62    /// [`AxHasher`].
63    #[inline(always)]
64    pub fn with_capacity(capacity: usize) -> Self {
65        Self(RawIndexMap::with_capacity_and_hasher(
66            capacity,
67            BuildHasherDefault::default(),
68        ))
69    }
70}
71
72impl<K, V, S: BuildHasher> AxIndexMap<K, V, S> {
73    /// Creates an empty map that uses the supplied `hasher`.
74    ///
75    /// Use this when you need a custom seed (e.g. [`AxBuildHasher::with_seed`])
76    /// or a completely different [`BuildHasher`].
77    #[inline(always)]
78    pub fn with_hasher(hasher: S) -> Self {
79        Self(RawIndexMap::with_hasher(hasher))
80    }
81
82    /// Creates an empty map with at least the given capacity that uses the
83    /// supplied `hasher`.
84    #[inline(always)]
85    pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
86        Self(RawIndexMap::with_capacity_and_hasher(capacity, hasher))
87    }
88
89    /// Consumes the wrapper and returns the underlying [`RawIndexMap`].
90    #[inline(always)]
91    pub fn into_inner(self) -> RawIndexMap<K, V, S> {
92        self.0
93    }
94}
95
96// ── Deref / DerefMut ─────────────────────────────────────────────────────────
97
98impl<K, V, S> Deref for AxIndexMap<K, V, S> {
99    type Target = RawIndexMap<K, V, S>;
100
101    #[inline]
102    fn deref(&self) -> &Self::Target {
103        &self.0
104    }
105}
106
107impl<K, V, S> DerefMut for AxIndexMap<K, V, S> {
108    #[inline]
109    fn deref_mut(&mut self) -> &mut Self::Target {
110        &mut self.0
111    }
112}
113
114// ── Standard traits ───────────────────────────────────────────────────────────
115
116impl<K, V> Default for AxIndexMap<K, V, BuildHasherDefault<AxHasher>> {
117    #[inline]
118    fn default() -> Self {
119        Self::new()
120    }
121}
122
123impl<K: fmt::Debug, V: fmt::Debug, S> fmt::Debug for AxIndexMap<K, V, S> {
124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125        self.0.fmt(f)
126    }
127}
128
129impl<K: Clone, V: Clone, S: Clone> Clone for AxIndexMap<K, V, S> {
130    #[inline]
131    fn clone(&self) -> Self {
132        Self(self.0.clone())
133    }
134}
135
136impl<K: Hash + Eq, V: PartialEq, S: BuildHasher> PartialEq for AxIndexMap<K, V, S> {
137    fn eq(&self, other: &Self) -> bool {
138        self.0 == other.0
139    }
140}
141
142impl<K: Hash + Eq, V: Eq, S: BuildHasher> Eq for AxIndexMap<K, V, S> {}
143
144impl<K, Q, V, S> Index<&Q> for AxIndexMap<K, V, S>
145where
146    K: Hash + Eq + core::borrow::Borrow<Q>,
147    Q: Hash + Eq + ?Sized,
148    S: BuildHasher,
149{
150    type Output = V;
151
152    #[inline]
153    fn index(&self, key: &Q) -> &Self::Output {
154        self.0.index(key)
155    }
156}
157
158// ── FromIterator / Extend ─────────────────────────────────────────────────────
159
160impl<K: Hash + Eq, V> FromIterator<(K, V)> for AxIndexMap<K, V, BuildHasherDefault<AxHasher>> {
161    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
162        let iter = iter.into_iter();
163        let (lower, _) = iter.size_hint();
164        let mut map = Self::with_capacity(lower);
165        map.extend(iter);
166        map
167    }
168}
169
170impl<K: Hash + Eq, V, S: BuildHasher> Extend<(K, V)> for AxIndexMap<K, V, S> {
171    #[inline]
172    fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
173        self.0.extend(iter);
174    }
175}
176
177// ── IntoIterator ──────────────────────────────────────────────────────────────
178
179impl<K, V, S> IntoIterator for AxIndexMap<K, V, S> {
180    type Item = (K, V);
181    type IntoIter = indexmap::map::IntoIter<K, V>;
182
183    #[inline]
184    fn into_iter(self) -> Self::IntoIter {
185        self.0.into_iter()
186    }
187}
188
189impl<'a, K, V, S> IntoIterator for &'a AxIndexMap<K, V, S> {
190    type Item = (&'a K, &'a V);
191    type IntoIter = indexmap::map::Iter<'a, K, V>;
192
193    #[inline]
194    fn into_iter(self) -> Self::IntoIter {
195        self.0.iter()
196    }
197}
198
199impl<'a, K, V, S> IntoIterator for &'a mut AxIndexMap<K, V, S> {
200    type Item = (&'a K, &'a mut V);
201    type IntoIter = indexmap::map::IterMut<'a, K, V>;
202
203    #[inline]
204    fn into_iter(self) -> Self::IntoIter {
205        self.0.iter_mut()
206    }
207}
208
209// ── From conversions ──────────────────────────────────────────────────────────
210
211impl<K, V, S> From<RawIndexMap<K, V, S>> for AxIndexMap<K, V, S> {
212    #[inline]
213    fn from(inner: RawIndexMap<K, V, S>) -> Self {
214        Self(inner)
215    }
216}
217
218impl<K, V, S> From<AxIndexMap<K, V, S>> for RawIndexMap<K, V, S> {
219    #[inline]
220    fn from(wrapper: AxIndexMap<K, V, S>) -> Self {
221        wrapper.0
222    }
223}
224
225// ── AxIndexSet ────────────────────────────────────────────────────────────────
226
227/// Insertion-ordered set backed by [indexmap] with [`AxHasher`] as the default
228/// hasher.
229///
230/// `AxIndexSet<T>` is a thin newtype wrapper around [`IndexSet<T>`] that adds
231/// the familiar `::new()` / `::with_capacity()` constructor syntax.
232/// Every method on `indexmap::IndexSet` is accessible via `Deref`.
233///
234/// [indexmap]: https://crates.io/crates/indexmap
235pub struct AxIndexSet<T, S = BuildHasherDefault<AxHasher>>(RawIndexSet<T, S>);
236
237impl<T> AxIndexSet<T, BuildHasherDefault<AxHasher>> {
238    /// Creates an empty set with the default [`AxHasher`].
239    #[inline(always)]
240    pub fn new() -> Self {
241        Self(RawIndexSet::with_hasher(BuildHasherDefault::default()))
242    }
243
244    /// Creates an empty set with at least the given capacity and the default
245    /// [`AxHasher`].
246    #[inline(always)]
247    pub fn with_capacity(capacity: usize) -> Self {
248        Self(RawIndexSet::with_capacity_and_hasher(
249            capacity,
250            BuildHasherDefault::default(),
251        ))
252    }
253}
254
255impl<T, S: BuildHasher> AxIndexSet<T, S> {
256    /// Creates an empty set that uses the supplied `hasher`.
257    #[inline(always)]
258    pub fn with_hasher(hasher: S) -> Self {
259        Self(RawIndexSet::with_hasher(hasher))
260    }
261
262    /// Creates an empty set with at least the given capacity that uses the
263    /// supplied `hasher`.
264    #[inline(always)]
265    pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
266        Self(RawIndexSet::with_capacity_and_hasher(capacity, hasher))
267    }
268
269    /// Consumes the wrapper and returns the underlying [`RawIndexSet`].
270    #[inline(always)]
271    pub fn into_inner(self) -> RawIndexSet<T, S> {
272        self.0
273    }
274}
275
276// ── Deref / DerefMut ─────────────────────────────────────────────────────────
277
278impl<T, S> Deref for AxIndexSet<T, S> {
279    type Target = RawIndexSet<T, S>;
280
281    #[inline]
282    fn deref(&self) -> &Self::Target {
283        &self.0
284    }
285}
286
287impl<T, S> DerefMut for AxIndexSet<T, S> {
288    #[inline]
289    fn deref_mut(&mut self) -> &mut Self::Target {
290        &mut self.0
291    }
292}
293
294// ── Standard traits ───────────────────────────────────────────────────────────
295
296impl<T> Default for AxIndexSet<T, BuildHasherDefault<AxHasher>> {
297    #[inline]
298    fn default() -> Self {
299        Self::new()
300    }
301}
302
303impl<T: fmt::Debug, S> fmt::Debug for AxIndexSet<T, S> {
304    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        self.0.fmt(f)
306    }
307}
308
309impl<T: Clone, S: Clone> Clone for AxIndexSet<T, S> {
310    #[inline]
311    fn clone(&self) -> Self {
312        Self(self.0.clone())
313    }
314}
315
316impl<T: Hash + Eq, S: BuildHasher> PartialEq for AxIndexSet<T, S> {
317    fn eq(&self, other: &Self) -> bool {
318        self.0 == other.0
319    }
320}
321
322impl<T: Hash + Eq, S: BuildHasher> Eq for AxIndexSet<T, S> {}
323
324// ── FromIterator / Extend ─────────────────────────────────────────────────────
325
326impl<T: Hash + Eq> FromIterator<T> for AxIndexSet<T, BuildHasherDefault<AxHasher>> {
327    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
328        let iter = iter.into_iter();
329        let (lower, _) = iter.size_hint();
330        let mut set = Self::with_capacity(lower);
331        set.extend(iter);
332        set
333    }
334}
335
336impl<T: Hash + Eq, S: BuildHasher> Extend<T> for AxIndexSet<T, S> {
337    #[inline]
338    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
339        self.0.extend(iter);
340    }
341}
342
343// ── IntoIterator ──────────────────────────────────────────────────────────────
344
345impl<T, S> IntoIterator for AxIndexSet<T, S> {
346    type Item = T;
347    type IntoIter = indexmap::set::IntoIter<T>;
348
349    #[inline]
350    fn into_iter(self) -> Self::IntoIter {
351        self.0.into_iter()
352    }
353}
354
355impl<'a, T, S> IntoIterator for &'a AxIndexSet<T, S> {
356    type Item = &'a T;
357    type IntoIter = indexmap::set::Iter<'a, T>;
358
359    #[inline]
360    fn into_iter(self) -> Self::IntoIter {
361        self.0.iter()
362    }
363}
364
365// ── From conversions ──────────────────────────────────────────────────────────
366
367impl<T, S> From<RawIndexSet<T, S>> for AxIndexSet<T, S> {
368    #[inline]
369    fn from(inner: RawIndexSet<T, S>) -> Self {
370        Self(inner)
371    }
372}
373
374impl<T, S> From<AxIndexSet<T, S>> for RawIndexSet<T, S> {
375    #[inline]
376    fn from(wrapper: AxIndexSet<T, S>) -> Self {
377        wrapper.0
378    }
379}
380
381// ── Free constructor functions ────────────────────────────────────────────────
382//
383// Convenience aliases for the most common construction patterns.
384// These are thin wrappers around `AxIndexMap::new()` etc.
385
386/// Creates an empty [`AxIndexMap`] using the default [`AxHasher`].
387#[inline(always)]
388pub fn new_map<K, V>() -> AxIndexMap<K, V> {
389    AxIndexMap::new()
390}
391
392/// Creates an [`AxIndexMap`] pre-allocated to at least `capacity` entries.
393#[inline(always)]
394pub fn map_with_capacity<K, V>(capacity: usize) -> AxIndexMap<K, V> {
395    AxIndexMap::with_capacity(capacity)
396}
397
398/// Creates an empty [`AxIndexSet`] using the default [`AxHasher`].
399#[inline(always)]
400pub fn new_set<T>() -> AxIndexSet<T> {
401    AxIndexSet::new()
402}
403
404/// Creates an [`AxIndexSet`] pre-allocated to at least `capacity` entries.
405#[inline(always)]
406pub fn set_with_capacity<T>(capacity: usize) -> AxIndexSet<T> {
407    AxIndexSet::with_capacity(capacity)
408}
409
410// ── Tests ─────────────────────────────────────────────────────────────────────
411
412#[cfg(test)]
413mod tests {
414    use super::*;
415    use core::hash::BuildHasherDefault;
416
417    // ── AxIndexMap constructors ───────────────────────────────────────────────
418
419    #[test]
420    fn map_constructors() {
421        let m1: AxIndexMap<&str, u32> = AxIndexMap::default();
422        let m2: AxIndexMap<&str, u32> = AxIndexMap::new();
423        let m3: AxIndexMap<&str, u32> = new_map();
424        let m4: AxIndexMap<&str, u32> = AxIndexMap::with_hasher(BuildHasherDefault::default());
425        assert!(m1.is_empty() && m2.is_empty() && m3.is_empty() && m4.is_empty());
426    }
427
428    #[test]
429    fn map_with_capacity_constructors() {
430        let m1: AxIndexMap<u32, u32> = AxIndexMap::with_capacity(64);
431        let m2: AxIndexMap<u32, u32> = map_with_capacity(64);
432        assert!(m1.capacity() >= 64 && m2.capacity() >= 64);
433    }
434
435    #[test]
436    fn map_seeded_hasher() {
437        let mut map: AxIndexMap<&str, i32, AxBuildHasher> =
438            AxIndexMap::with_hasher(AxBuildHasher::with_seed(0xc0ffee_deadbeef));
439        map.insert("seeded", -1);
440        assert_eq!(map["seeded"], -1);
441    }
442
443    #[test]
444    fn map_insertion_order_preserved() {
445        let mut map: AxIndexMap<&str, u32> = AxIndexMap::new();
446        let words = ["delta", "alpha", "charlie", "bravo"];
447        for (i, w) in words.iter().enumerate() {
448            map.insert(w, i as u32);
449        }
450        assert_eq!(map.keys().copied().collect::<Vec<_>>(), words);
451    }
452
453    #[test]
454    fn map_index_based_access() {
455        let mut map: AxIndexMap<&str, u32> = AxIndexMap::new();
456        map.insert("first", 1);
457        map.insert("second", 2);
458        map.insert("third", 3);
459        assert_eq!(map.get_index(0), Some((&"first", &1)));
460        assert_eq!(map.get_index(2), Some((&"third", &3)));
461        assert_eq!(map.get_index(3), None);
462    }
463
464    #[test]
465    fn map_entry_api() {
466        let mut map: AxIndexMap<&str, u32> = AxIndexMap::new();
467        for _ in 0..3 {
468            map.entry("counter").and_modify(|n| *n += 1).or_insert(0);
469        }
470        assert_eq!(map["counter"], 2);
471    }
472
473    #[test]
474    fn map_from_iterator() {
475        let map: AxIndexMap<&str, u32> = [("a", 1u32), ("b", 2), ("c", 3)].into_iter().collect();
476        assert_eq!(map.len(), 3);
477        assert_eq!(map.get_index(0), Some((&"a", &1)));
478    }
479
480    #[test]
481    fn map_extend() {
482        let mut map: AxIndexMap<u32, u32> = AxIndexMap::new();
483        map.extend([(1, 10), (2, 20), (3, 30)]);
484        assert_eq!(map.len(), 3);
485        assert_eq!(map[&2], 20);
486    }
487
488    #[test]
489    fn map_retain() {
490        let mut map: AxIndexMap<u32, u32> = (0u32..10).map(|i| (i, i * i)).collect();
491        map.retain(|_, v| *v > 25);
492        assert!(map.values().all(|&v| v > 25));
493    }
494
495    #[test]
496    fn map_sort_keys() {
497        let mut map: AxIndexMap<&str, u32> = AxIndexMap::new();
498        map.insert("banana", 2);
499        map.insert("apple", 1);
500        map.insert("cherry", 3);
501        map.sort_keys();
502        assert_eq!(
503            map.keys().copied().collect::<Vec<_>>(),
504            ["apple", "banana", "cherry"]
505        );
506    }
507
508    #[test]
509    fn map_swap_remove() {
510        let mut map: AxIndexMap<u32, u32> = (0u32..5).map(|i| (i, i)).collect();
511        map.swap_remove(&2);
512        assert_eq!(map.len(), 4);
513        assert!(!map.contains_key(&2));
514    }
515
516    #[test]
517    fn map_into_inner_roundtrip() {
518        let mut raw: RawIndexMap<&str, i32, BuildHasherDefault<AxHasher>> =
519            RawIndexMap::with_hasher(BuildHasherDefault::default());
520        raw.insert("x", 99);
521        let ax: AxIndexMap<&str, i32> = raw.into();
522        assert_eq!(ax["x"], 99);
523        let raw: RawIndexMap<&str, i32, BuildHasherDefault<AxHasher>> = ax.into();
524        assert_eq!(raw["x"], 99);
525    }
526
527    // ── Type alias: IndexMap ──────────────────────────────────────────────────
528
529    #[test]
530    fn alias_indexmap_basic() {
531        let mut map: IndexMap<&str, u32> = RawIndexMap::with_hasher(BuildHasherDefault::default());
532        map.insert("hello", 42);
533        assert_eq!(map["hello"], 42);
534        // Insertion order preserved.
535        map.insert("world", 7);
536        assert_eq!(map.get_index(0), Some((&"hello", &42)));
537    }
538
539    #[test]
540    fn alias_indexmap_collect() {
541        let map: IndexMap<&str, u32> = [("a", 1u32), ("b", 2), ("c", 3)]
542            .into_iter()
543            .collect::<RawIndexMap<_, _, BuildHasherDefault<AxHasher>>>();
544        assert_eq!(map.len(), 3);
545    }
546
547    // ── AxIndexSet constructors ───────────────────────────────────────────────
548
549    #[test]
550    fn set_constructors() {
551        let s1: AxIndexSet<u32> = AxIndexSet::default();
552        let s2: AxIndexSet<u32> = AxIndexSet::new();
553        let s3: AxIndexSet<u32> = new_set();
554        let s4: AxIndexSet<u32> = AxIndexSet::with_hasher(BuildHasherDefault::default());
555        assert!(s1.is_empty() && s2.is_empty() && s3.is_empty() && s4.is_empty());
556    }
557
558    #[test]
559    fn set_with_capacity_constructors() {
560        let s1: AxIndexSet<u64> = AxIndexSet::with_capacity(128);
561        let s2: AxIndexSet<u64> = set_with_capacity(128);
562        assert!(s1.capacity() >= 128 && s2.capacity() >= 128);
563    }
564
565    #[test]
566    fn set_insertion_order_and_dedup() {
567        let mut set: AxIndexSet<u32> = AxIndexSet::new();
568        for n in [5, 3, 1, 3, 5, 2, 4, 2] {
569            set.insert(n);
570        }
571        assert_eq!(set.iter().copied().collect::<Vec<_>>(), [5, 3, 1, 2, 4]);
572    }
573
574    #[test]
575    fn set_index_based_access() {
576        let set: AxIndexSet<&str> = ["x", "y", "z"].into_iter().collect();
577        assert_eq!(set.get_index(0), Some(&"x"));
578        assert_eq!(set.get_index(2), Some(&"z"));
579    }
580
581    #[test]
582    fn set_operations() {
583        let a: AxIndexSet<u32> = [1, 2, 3, 4].into_iter().collect();
584        let b: AxIndexSet<u32> = [3, 4, 5, 6].into_iter().collect();
585        assert_eq!(a.union(&b).count(), 6);
586        assert_eq!(a.intersection(&b).count(), 2);
587        assert_eq!(a.difference(&b).count(), 2);
588    }
589
590    #[test]
591    fn set_from_iterator_dedup() {
592        let set: AxIndexSet<i32> = [1, 2, 3, 2, 1, 4].into_iter().collect();
593        assert_eq!(set.len(), 4);
594    }
595
596    #[test]
597    fn set_extend() {
598        let mut set: AxIndexSet<u32> = AxIndexSet::new();
599        set.extend([1u32, 2, 3]);
600        set.extend([3u32, 4, 5]);
601        assert_eq!(set.len(), 5);
602    }
603
604    #[test]
605    fn set_sort() {
606        let mut set: AxIndexSet<u32> = [5, 3, 1, 4, 2].into_iter().collect();
607        set.sort();
608        assert_eq!(set.iter().copied().collect::<Vec<_>>(), [1, 2, 3, 4, 5]);
609    }
610
611    #[test]
612    fn set_into_inner_roundtrip() {
613        let mut raw: RawIndexSet<u64, BuildHasherDefault<AxHasher>> =
614            RawIndexSet::with_hasher(BuildHasherDefault::default());
615        raw.insert(42u64);
616        let ax: AxIndexSet<u64> = raw.into();
617        assert!(ax.contains(&42));
618        let raw: RawIndexSet<u64, BuildHasherDefault<AxHasher>> = ax.into();
619        assert!(raw.contains(&42));
620    }
621
622    // ── Type alias: IndexSet ──────────────────────────────────────────────────
623
624    #[test]
625    fn alias_indexset_basic() {
626        let mut set: IndexSet<u32> = RawIndexSet::with_hasher(BuildHasherDefault::default());
627        set.insert(1);
628        set.insert(2);
629        set.insert(2);
630        assert_eq!(set.len(), 2);
631        assert_eq!(set.get_index(0), Some(&1));
632    }
633}