alloy_primitives/map/
mod.rs

1//! Re-exports of map types and utilities.
2//!
3//! This module exports the following types:
4//! - [`HashMap`] and [`HashSet`] from the standard library or `hashbrown` crate. The
5//!   "map-hashbrown" feature can be used to force the use of `hashbrown`, and is required in
6//!   `no_std` environments.
7//! - [`IndexMap`] and [`IndexSet`] from the `indexmap` crate, if the "map-indexmap" feature is
8//!   enabled.
9//! - The previously-listed hash map types prefixed with `Fb`. These are type aliases with
10//!   [`FixedBytes<N>`][fb] as the key, and [`FbBuildHasher`] as the hasher builder. This hasher is
11//!   optimized for hashing fixed-size byte arrays, and wraps around the default hasher builder. It
12//!   performs best when the hasher is `fxhash`, which is enabled by default with the "map-fxhash"
13//!   feature.
14//! - The previously-listed hash map types prefixed with [`Selector`], [`Address`], and [`B256`].
15//!   These use [`FbBuildHasher`] with the respective fixed-size byte array as the key. See the
16//!   previous point for more information.
17//!
18//! Unless specified otherwise, the default hasher builder used by these types is
19//! [`DefaultHashBuilder`]. This hasher prioritizes speed over security. Users who require HashDoS
20//! resistance should enable the "rand" feature so that the hasher is initialized using a random
21//! seed.
22//!
23//! Note that using the types provided in this module may require using different APIs than the
24//! standard library as they might not be generic over the hasher state, such as using
25//! `HashMap::default()` instead of `HashMap::new()`.
26//!
27//! [fb]: crate::FixedBytes
28//! [`Selector`]: crate::Selector
29//! [`Address`]: crate::Address
30//! [`B256`]: crate::B256
31
32use cfg_if::cfg_if;
33
34mod fixed;
35pub use fixed::*;
36
37// The `HashMap` implementation.
38// Use `hashbrown` if requested with "map-hashbrown" or required by `no_std`.
39cfg_if! {
40    if #[cfg(any(feature = "map-hashbrown", not(feature = "std")))] {
41        use hashbrown as imp;
42
43        /// A view into a single entry in a map, which may either be vacant or occupied.
44        ///
45        /// See [`Entry`](imp::hash_map::Entry) for more information.
46        pub type Entry<'a, K, V, S = DefaultHashBuilder> = imp::hash_map::Entry<'a, K, V, S>;
47        /// A view into an occupied entry in a `HashMap`. It is part of the [`Entry`] enum.
48        ///
49        /// See [`OccupiedEntry`](imp::hash_map::OccupiedEntry) for more information.
50        pub type OccupiedEntry<'a, K, V, S = DefaultHashBuilder> = imp::hash_map::OccupiedEntry<'a, K, V, S>;
51        /// A view into a vacant entry in a `HashMap`. It is part of the [`Entry`] enum.
52        ///
53        /// See [`VacantEntry`](imp::hash_map::VacantEntry) for more information.
54        pub type VacantEntry<'a, K, V, S = DefaultHashBuilder> = imp::hash_map::VacantEntry<'a, K, V, S>;
55    } else {
56        use hashbrown as _;
57        use std::collections as imp;
58        #[doc(no_inline)]
59        pub use imp::hash_map::{Entry, OccupiedEntry, VacantEntry};
60    }
61}
62
63#[doc(no_inline)]
64pub use imp::{hash_map, hash_set};
65
66/// A [`HashMap`](imp::HashMap) using the [default hasher](DefaultHasher).
67///
68/// See [`HashMap`](imp::HashMap) for more information.
69pub type HashMap<K, V, S = DefaultHashBuilder> = imp::HashMap<K, V, S>;
70/// A [`HashSet`](imp::HashSet) using the [default hasher](DefaultHasher).
71///
72/// See [`HashSet`](imp::HashSet) for more information.
73pub type HashSet<V, S = DefaultHashBuilder> = imp::HashSet<V, S>;
74
75// Faster hashers.
76cfg_if! {
77    if #[cfg(feature = "map-fxhash")] {
78        #[doc(no_inline)]
79        pub use rustc_hash::{self, FxHasher};
80
81        cfg_if! {
82            if #[cfg(all(feature = "std", feature = "rand"))] {
83                use rustc_hash::FxRandomState as FxBuildHasherInner;
84            } else {
85                use rustc_hash::FxBuildHasher as FxBuildHasherInner;
86            }
87        }
88
89        /// The [`FxHasher`] hasher builder.
90        ///
91        /// This is [`rustc_hash::FxBuildHasher`], unless both the "std" and "rand" features are
92        /// enabled, in which case it will be [`rustc_hash::FxRandomState`] for better security at
93        /// very little cost.
94        pub type FxBuildHasher = FxBuildHasherInner;
95    }
96}
97
98#[cfg(feature = "map-foldhash")]
99#[doc(no_inline)]
100pub use foldhash;
101
102// Default hasher.
103cfg_if! {
104    if #[cfg(feature = "map-foldhash")] {
105        type DefaultHashBuilderInner = foldhash::fast::RandomState;
106    } else if #[cfg(feature = "map-fxhash")] {
107        type DefaultHashBuilderInner = FxBuildHasher;
108    } else if #[cfg(any(feature = "map-hashbrown", not(feature = "std")))] {
109        type DefaultHashBuilderInner = hashbrown::DefaultHashBuilder;
110    } else {
111        type DefaultHashBuilderInner = std::collections::hash_map::RandomState;
112    }
113}
114/// The default [`BuildHasher`](core::hash::BuildHasher) used by [`HashMap`] and [`HashSet`].
115///
116/// See [the module documentation](self) for more information on the default hasher.
117pub type DefaultHashBuilder = DefaultHashBuilderInner;
118/// The default [`Hasher`](core::hash::Hasher) used by [`HashMap`] and [`HashSet`].
119///
120/// See [the module documentation](self) for more information on the default hasher.
121pub type DefaultHasher = <DefaultHashBuilder as core::hash::BuildHasher>::Hasher;
122
123// `indexmap` re-exports.
124cfg_if! {
125    if #[cfg(feature = "map-indexmap")] {
126        #[doc(no_inline)]
127        pub use indexmap::{self, map::Entry as IndexEntry};
128
129        /// [`IndexMap`](indexmap::IndexMap) using the [default hasher](DefaultHasher).
130        ///
131        /// See [`IndexMap`](indexmap::IndexMap) for more information.
132        pub type IndexMap<K, V, S = DefaultHashBuilder> = indexmap::IndexMap<K, V, S>;
133        /// [`IndexSet`](indexmap::IndexSet) using the [default hasher](DefaultHasher).
134        ///
135        /// See [`IndexSet`](indexmap::IndexSet) for more information.
136        pub type IndexSet<V, S = DefaultHashBuilder> = indexmap::IndexSet<V, S>;
137    }
138}
139
140/// This module contains the rayon parallel iterator types for hash maps (HashMap<K, V>).
141///
142/// You will rarely need to interact with it directly unless you have need to name one
143/// of the iterator types.
144#[cfg(feature = "rayon")]
145pub mod rayon {
146    use super::*;
147
148    cfg_if! {
149        if #[cfg(any(feature = "map-hashbrown", not(feature = "std")))] {
150            pub use hashbrown::hash_map::rayon::{
151                IntoParIter as IntoIter,
152                ParDrain as Drain,
153                ParIter as Iter,
154                ParIterMut as IterMut,
155                ParKeys as Keys,
156                ParValues as Values,
157                ParValuesMut as ValuesMut
158            };
159            use ::rayon as _;
160        } else {
161            pub use ::rayon::collections::hash_map::*;
162        }
163    }
164}
165
166#[cfg(test)]
167mod tests {
168    use super::*;
169
170    #[test]
171    fn default_hasher_builder_traits() {
172        let hash_builder = <DefaultHashBuilder as Default>::default();
173        let _hash_builder2 = <DefaultHashBuilder as Clone>::clone(&hash_builder);
174        let mut hasher =
175            <DefaultHashBuilder as core::hash::BuildHasher>::build_hasher(&hash_builder);
176
177        <DefaultHasher as core::hash::Hasher>::write_u8(&mut hasher, 0);
178        let _hasher2 = <DefaultHasher as Clone>::clone(&hasher);
179    }
180
181    // Check that the `Entry` types are correct.
182    fn use_entry(e: Entry<'_, u32, u64>) -> u64 {
183        match e {
184            Entry::Occupied(o) => {
185                let o: OccupiedEntry<'_, u32, u64> = o;
186                *o.get()
187            }
188            Entry::Vacant(v) => {
189                let v: VacantEntry<'_, u32, u64> = v;
190                *v.insert(0)
191            }
192        }
193    }
194
195    #[test]
196    fn test_entry() {
197        let mut map = HashMap::new();
198        map.insert(1, 1);
199        assert_eq!(use_entry(map.entry(0)), 0);
200        assert_eq!(use_entry(map.entry(1)), 1);
201        assert_eq!(use_entry(map.entry(2)), 0);
202    }
203}