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}