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}