Skip to main content

indexmap/
macros.rs

1/// Create an [`IndexMap`][crate::IndexMap] from a list of key-value pairs
2/// and a [`BuildHasherDefault`][core::hash::BuildHasherDefault]-wrapped custom hasher.
3///
4/// ## Example
5///
6/// ```
7/// use indexmap::indexmap_with_default;
8/// use fnv::FnvHasher;
9///
10/// let map = indexmap_with_default!{
11///     FnvHasher;
12///     "a" => 1,
13///     "b" => 2,
14/// };
15/// assert_eq!(map["a"], 1);
16/// assert_eq!(map["b"], 2);
17/// assert_eq!(map.get("c"), None);
18///
19/// // "a" is the first key
20/// assert_eq!(map.keys().next(), Some(&"a"));
21/// ```
22///
23/// This can also be initialized in `const` contexts:
24///
25/// ```
26/// use indexmap::{IndexMap, indexmap_with_default};
27/// use fnv::FnvBuildHasher; // = BuildHasherDefault<FnvHasher>
28/// use std::sync::Mutex;
29///
30/// static GLOBAL: Mutex<IndexMap<String, i32, FnvBuildHasher>> =
31///     Mutex::new(indexmap_with_default!());
32///
33/// if let Ok(mut map) = GLOBAL.lock() {
34///     map.insert("a".into(), 1);
35///     map.insert("b".into(), 2);
36/// }
37///
38/// assert_eq!(GLOBAL.lock().unwrap()["a"], 1);
39/// assert_eq!(GLOBAL.lock().unwrap()["b"], 2);
40/// ```
41#[macro_export]
42macro_rules! indexmap_with_default {
43    () => { const {
44        $crate::IndexMap::with_hasher(
45            // Let type inference figure out the hasher:
46            ::core::hash::BuildHasherDefault::new(),
47        )
48    }};
49    ($H:ty $(;)?) => { const {
50        $crate::IndexMap::with_hasher(
51            // Specify your custom `H` (must implement Default + Hasher) as the hasher:
52            ::core::hash::BuildHasherDefault::<$H>::new(),
53        )
54    }};
55    ($H:ty; $($key:expr => $value:expr),+ $(,)?) => {{
56        let mut map = $crate::IndexMap::with_capacity_and_hasher(
57            // Note: `stringify!($key)` is just here to consume the repetition,
58            // but we throw away that string literal during constant evaluation.
59            const { <[()]>::len(&[$({ stringify!($key); }),*]) },
60            // Specify your custom `H` (must implement Default + Hasher) as the hasher:
61            ::core::hash::BuildHasherDefault::<$H>::new(),
62        );
63        $(
64            map.insert($key, $value);
65        )+
66        map
67    }};
68}
69
70#[cfg(feature = "std")]
71#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
72#[macro_export]
73/// Create an [`IndexMap`][crate::IndexMap] from a list of key-value pairs
74///
75/// ## Example
76///
77/// ```
78/// use indexmap::indexmap;
79///
80/// let map = indexmap!{
81///     "a" => 1,
82///     "b" => 2,
83/// };
84/// assert_eq!(map["a"], 1);
85/// assert_eq!(map["b"], 2);
86/// assert_eq!(map.get("c"), None);
87///
88/// // "a" is the first key
89/// assert_eq!(map.keys().next(), Some(&"a"));
90/// ```
91macro_rules! indexmap {
92    () => { $crate::IndexMap::new() };
93    ($($key:expr => $value:expr),+ $(,)?) => {{
94        let mut map = $crate::IndexMap::with_capacity(
95            // Note: `stringify!($key)` is just here to consume the repetition,
96            // but we throw away that string literal during constant evaluation.
97            const { <[()]>::len(&[$({ stringify!($key); }),*]) },
98        );
99        $(
100            map.insert($key, $value);
101        )+
102        map
103    }};
104}
105
106/// Create an [`IndexSet`][crate::IndexSet] from a list of values
107/// and a [`BuildHasherDefault`][core::hash::BuildHasherDefault]-wrapped custom hasher.
108///
109/// ## Example
110///
111/// ```
112/// use indexmap::indexset_with_default;
113/// use fnv::FnvHasher;
114///
115/// let set = indexset_with_default!{
116///     FnvHasher;
117///     "a",
118///     "b",
119/// };
120/// assert!(set.contains("a"));
121/// assert!(set.contains("b"));
122/// assert!(!set.contains("c"));
123///
124/// // "a" is the first value
125/// assert_eq!(set.iter().next(), Some(&"a"));
126/// ```
127///
128/// This can also be initialized in `const` contexts:
129///
130/// ```
131/// use indexmap::{IndexSet, indexset_with_default};
132/// use fnv::FnvBuildHasher; // = BuildHasherDefault<FnvHasher>
133/// use std::sync::Mutex;
134///
135/// static INTERN: Mutex<IndexSet<String, FnvBuildHasher>> =
136///     Mutex::new(indexset_with_default!());
137///
138/// if let Ok(mut set) = INTERN.lock() {
139///     set.insert("a".into());
140///     set.insert("b".into());
141///     set.insert("c".into());
142/// }
143///
144/// assert!(INTERN.lock().unwrap().contains("a"));
145/// assert!(INTERN.lock().unwrap().contains("b"));
146/// assert!(INTERN.lock().unwrap().contains("c"));
147/// ```
148#[macro_export]
149macro_rules! indexset_with_default {
150    () => { const {
151        $crate::IndexSet::with_hasher(
152            // Let type inference figure out the hasher:
153            ::core::hash::BuildHasherDefault::new(),
154        )
155    }};
156    ($H:ty $(;)?) => { const {
157        $crate::IndexSet::with_hasher(
158            // Specify your custom `H` (must implement Default + Hasher) as the hasher:
159            ::core::hash::BuildHasherDefault::<$H>::new(),
160        )
161    }};
162    ($H:ty; $($value:expr),+ $(,)?) => {{
163        let mut set = $crate::IndexSet::with_capacity_and_hasher(
164            // Note: `stringify!($value)` is just here to consume the repetition,
165            // but we throw away that string literal during constant evaluation.
166            const { <[()]>::len(&[$({ stringify!($value); }),*]) },
167            // Specify your custom `H` (must implement Default + Hasher) as the hasher:
168            ::core::hash::BuildHasherDefault::<$H>::new(),
169        );
170        $(
171            set.insert($value);
172        )+
173        set
174    }};
175}
176
177#[cfg(feature = "std")]
178#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
179#[macro_export]
180/// Create an [`IndexSet`][crate::IndexSet] from a list of values
181///
182/// ## Example
183///
184/// ```
185/// use indexmap::indexset;
186///
187/// let set = indexset!{
188///     "a",
189///     "b",
190/// };
191/// assert!(set.contains("a"));
192/// assert!(set.contains("b"));
193/// assert!(!set.contains("c"));
194///
195/// // "a" is the first value
196/// assert_eq!(set.iter().next(), Some(&"a"));
197/// ```
198macro_rules! indexset {
199    () => { $crate::IndexSet::new() };
200    ($($value:expr),+ $(,)?) => {{
201        let mut set = $crate::IndexSet::with_capacity(
202            // Note: `stringify!($value)` is just here to consume the repetition,
203            // but we throw away that string literal during constant evaluation.
204            const { <[()]>::len(&[$({ stringify!($value); }),*]) },
205        );
206        $(
207            set.insert($value);
208        )+
209        set
210    }};
211}
212
213// generate all the Iterator methods by just forwarding to the underlying
214// self.iter and mapping its element.
215macro_rules! iterator_methods {
216    // $map_elt is the mapping function from the underlying iterator's element
217    // same mapping function for both options and iterators
218    ($map_elt:expr) => {
219        fn next(&mut self) -> Option<Self::Item> {
220            self.iter.next().map($map_elt)
221        }
222
223        fn size_hint(&self) -> (usize, Option<usize>) {
224            self.iter.size_hint()
225        }
226
227        fn count(self) -> usize {
228            self.iter.len()
229        }
230
231        fn nth(&mut self, n: usize) -> Option<Self::Item> {
232            self.iter.nth(n).map($map_elt)
233        }
234
235        fn last(mut self) -> Option<Self::Item> {
236            self.next_back()
237        }
238
239        fn collect<C>(self) -> C
240        where
241            C: FromIterator<Self::Item>,
242        {
243            // NB: forwarding this directly to standard iterators will
244            // allow it to leverage unstable traits like `TrustedLen`.
245            self.iter.map($map_elt).collect()
246        }
247    };
248}
249
250macro_rules! double_ended_iterator_methods {
251    // $map_elt is the mapping function from the underlying iterator's element
252    // same mapping function for both options and iterators
253    ($map_elt:expr) => {
254        fn next_back(&mut self) -> Option<Self::Item> {
255            self.iter.next_back().map($map_elt)
256        }
257
258        fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
259            self.iter.nth_back(n).map($map_elt)
260        }
261    };
262}
263
264// generate `ParallelIterator` methods by just forwarding to the underlying
265// self.entries and mapping its elements.
266#[cfg(feature = "rayon")]
267macro_rules! parallel_iterator_methods {
268    // $map_elt is the mapping function from the underlying iterator's element
269    ($map_elt:expr) => {
270        fn drive_unindexed<C>(self, consumer: C) -> C::Result
271        where
272            C: UnindexedConsumer<Self::Item>,
273        {
274            self.entries
275                .into_par_iter()
276                .map($map_elt)
277                .drive_unindexed(consumer)
278        }
279
280        // NB: This allows indexed collection, e.g. directly into a `Vec`, but the
281        // underlying iterator must really be indexed.  We should remove this if we
282        // start having tombstones that must be filtered out.
283        fn opt_len(&self) -> Option<usize> {
284            Some(self.entries.len())
285        }
286    };
287}
288
289// generate `IndexedParallelIterator` methods by just forwarding to the underlying
290// self.entries and mapping its elements.
291#[cfg(feature = "rayon")]
292macro_rules! indexed_parallel_iterator_methods {
293    // $map_elt is the mapping function from the underlying iterator's element
294    ($map_elt:expr) => {
295        fn drive<C>(self, consumer: C) -> C::Result
296        where
297            C: Consumer<Self::Item>,
298        {
299            self.entries.into_par_iter().map($map_elt).drive(consumer)
300        }
301
302        fn len(&self) -> usize {
303            self.entries.len()
304        }
305
306        fn with_producer<CB>(self, callback: CB) -> CB::Output
307        where
308            CB: ProducerCallback<Self::Item>,
309        {
310            self.entries
311                .into_par_iter()
312                .map($map_elt)
313                .with_producer(callback)
314        }
315    };
316}