iddqd/
macros.rs

1//! Macros for this crate.
2
3/// Creates an [`IdHashMap`](crate::IdHashMap) from a list of items.
4///
5/// An optional [`BuildHasher`](core::hash::BuildHasher) that implements
6/// `Default` can be provided as the first argument, followed by a semicolon.
7///
8/// # Panics
9///
10/// Panics if the list of items has duplicate keys. For better error handling,
11/// the item is required to implement `Debug`.
12///
13/// # Examples
14///
15/// ```
16/// # #[cfg(feature = "default-hasher")] {
17/// use iddqd::{IdHashItem, id_hash_map, id_upcast};
18///
19/// #[derive(Debug)]
20/// struct User {
21///     id: u32,
22///     name: String,
23/// }
24///
25/// impl IdHashItem for User {
26///     type Key<'a> = u32;
27///     fn key(&self) -> Self::Key<'_> {
28///         self.id
29///     }
30///     id_upcast!();
31/// }
32///
33/// let map = id_hash_map! {
34///     User { id: 1, name: "Alice".to_string() },
35///     User { id: 2, name: "Bob".to_string() },
36/// };
37/// assert_eq!(map.get(&1).unwrap().name, "Alice");
38/// assert_eq!(map.get(&2).unwrap().name, "Bob");
39///
40/// // With a custom hasher:
41/// let map = id_hash_map! {
42///     foldhash::quality::RandomState;
43///     User { id: 3, name: "Charlie".to_string() },
44///     User { id: 4, name: "Eve".to_string() },
45/// };
46/// assert_eq!(map.get(&3).unwrap().name, "Charlie");
47/// assert_eq!(map.get(&4).unwrap().name, "Eve");
48/// # }
49/// ```
50#[macro_export]
51macro_rules! id_hash_map {
52    ($($item:expr,)+) => { $crate::id_hash_map!($($item),+) };
53    ($($item:expr),*) => {
54        {
55            // Note: `stringify!($key)` is just here to consume the repetition,
56            // but we throw away that string literal during constant evaluation.
57            const CAP: usize = <[()]>::len(&[$({ stringify!($item); }),*]);
58            let mut map = $crate::IdHashMap::with_capacity(CAP);
59            $(
60                map.insert_unique($item).unwrap();
61            )*
62            map
63        }
64    };
65    ($H:ty; $($item:expr,)+) => { $crate::id_hash_map!($H; $($item),+) };
66    ($H:ty; $($item:expr),*) => {
67        {
68            // Note: `stringify!($key)` is just here to consume the repetition,
69            // but we throw away that string literal during constant evaluation.
70            const CAP: usize = <[()]>::len(&[$({ stringify!($item); }),*]);
71            let mut map = $crate::IdHashMap::with_capacity_and_hasher(CAP, <$H>::default());
72            $(
73                map.insert_unique($item).unwrap();
74            )*
75            map
76        }
77    };
78}
79
80/// Creates an [`IdOrdMap`](crate::IdOrdMap) from a list of items.
81///
82/// # Panics
83///
84/// Panics if the list of items has duplicate keys. For better error handling,
85/// the item is required to implement `Debug`.
86///
87/// # Examples
88///
89/// ```
90/// # #[cfg(feature = "std")] {
91/// use iddqd::{IdOrdItem, id_ord_map, id_upcast};
92///
93/// #[derive(Debug)]
94/// struct User {
95///     id: u32,
96///     name: String,
97/// }
98///
99/// impl IdOrdItem for User {
100///     type Key<'a> = u32;
101///     fn key(&self) -> Self::Key<'_> {
102///         self.id
103///     }
104///     id_upcast!();
105/// }
106///
107/// let map = id_ord_map! {
108///     User { id: 1, name: "Alice".to_string() },
109///     User { id: 2, name: "Bob".to_string() },
110/// };
111/// assert_eq!(map.get(&1).unwrap().name, "Alice");
112/// assert_eq!(map.get(&2).unwrap().name, "Bob");
113/// # }
114/// ```
115#[cfg(feature = "std")]
116#[macro_export]
117macro_rules! id_ord_map {
118    ($($item:expr,)+) => { $crate::id_ord_map!($($item),+) };
119    ($($item:expr),*) => {
120        {
121            // Note: `stringify!($key)` is just here to consume the repetition,
122            // but we throw away that string literal during constant evaluation.
123            const CAP: usize = <[()]>::len(&[$({ stringify!($item); }),*]);
124            let mut map = $crate::IdOrdMap::with_capacity(CAP);
125            $(
126                map.insert_unique($item).unwrap();
127            )*
128            map
129        }
130    };
131}
132
133/// Creates a [`BiHashMap`](crate::BiHashMap) from a list of items.
134///
135/// An optional [`BuildHasher`](core::hash::BuildHasher) that implements
136/// `Default` can be provided as the first argument, followed by a semicolon.
137///
138/// # Panics
139///
140/// Panics if the list of items has duplicate keys. For better error handling,
141/// the item is required to implement `Debug`.
142///
143/// # Examples
144///
145/// ```
146/// # #[cfg(feature = "default-hasher")] {
147/// use iddqd::{BiHashItem, bi_hash_map, bi_upcast};
148///
149/// #[derive(Debug)]
150/// struct User {
151///     id: u32,
152///     name: String,
153/// }
154///
155/// impl BiHashItem for User {
156///     type K1<'a> = u32;
157///     type K2<'a> = &'a str;
158///     fn key1(&self) -> Self::K1<'_> {
159///         self.id
160///     }
161///     fn key2(&self) -> Self::K2<'_> {
162///         &self.name
163///     }
164///     bi_upcast!();
165/// }
166///
167/// let map = bi_hash_map! {
168///     User { id: 1, name: "Alice".to_string() },
169///     User { id: 2, name: "Bob".to_string() },
170/// };
171/// assert_eq!(map.get1(&1).unwrap().name, "Alice");
172/// assert_eq!(map.get2("Bob").unwrap().id, 2);
173///
174/// // With a custom hasher:
175/// let map = bi_hash_map! {
176///     foldhash::quality::RandomState;
177///     User { id: 3, name: "Charlie".to_string() },
178///     User { id: 4, name: "Eve".to_string() },
179/// };
180/// assert_eq!(map.get1(&3).unwrap().name, "Charlie");
181/// assert_eq!(map.get2("Eve").unwrap().id, 4);
182/// # }
183/// ```
184#[macro_export]
185macro_rules! bi_hash_map {
186    ($($item:expr,)+) => { $crate::bi_hash_map!($($item),+) };
187    ($($item:expr),*) => {
188        {
189            // Note: `stringify!($key)` is just here to consume the repetition,
190            // but we throw away that string literal during constant evaluation.
191            const CAP: usize = <[()]>::len(&[$({ stringify!($item); }),*]);
192            let mut map = $crate::BiHashMap::with_capacity(CAP);
193            $(
194                map.insert_unique($item).unwrap();
195            )*
196            map
197        }
198    };
199    ($H:ty; $($item:expr,)+) => { $crate::bi_hash_map!($H; $($item),+) };
200    ($H:ty; $($item:expr),*) => {
201        {
202            // Note: `stringify!($key)` is just here to consume the repetition,
203            // but we throw away that string literal during constant evaluation.
204            const CAP: usize = <[()]>::len(&[$({ stringify!($item); }),*]);
205            let mut map = $crate::BiHashMap::with_capacity_and_hasher(CAP, <$H>::default());
206            $(
207                map.insert_unique($item).unwrap();
208            )*
209            map
210        }
211    };
212}
213
214/// Creates a [`TriHashMap`](crate::TriHashMap) from a list of items.
215///
216/// An optional [`BuildHasher`](core::hash::BuildHasher) that implements
217/// `Default` can be provided as the first argument, followed by a semicolon.
218///
219/// # Panics
220///
221/// Panics if the list of items has duplicate keys. For better error handling,
222/// the item is required to implement `Debug`.
223///
224/// # Examples
225///
226/// ```
227/// # #[cfg(feature = "default-hasher")] {
228/// use iddqd::{TriHashItem, tri_hash_map, tri_upcast};
229///
230/// #[derive(Debug)]
231/// struct Person {
232///     id: u32,
233///     name: String,
234///     email: String,
235/// }
236///
237/// impl TriHashItem for Person {
238///     type K1<'a> = u32;
239///     type K2<'a> = &'a str;
240///     type K3<'a> = &'a str;
241///     fn key1(&self) -> Self::K1<'_> {
242///         self.id
243///     }
244///     fn key2(&self) -> Self::K2<'_> {
245///         &self.name
246///     }
247///     fn key3(&self) -> Self::K3<'_> {
248///         &self.email
249///     }
250///     tri_upcast!();
251/// }
252///
253/// let map = tri_hash_map! {
254///     Person { id: 1, name: "Alice".to_string(), email: "alice@example.com".to_string() },
255///     Person { id: 2, name: "Bob".to_string(), email: "bob@example.com".to_string() },
256/// };
257/// assert_eq!(map.get1(&1).unwrap().name, "Alice");
258/// assert_eq!(map.get2("Bob").unwrap().id, 2);
259/// assert_eq!(map.get3("alice@example.com").unwrap().name, "Alice");
260///
261/// // With a custom hasher:
262/// let map = tri_hash_map! {
263///     foldhash::quality::RandomState;
264///     Person { id: 3, name: "Charlie".to_string(), email: "charlie@example.com".to_string() },
265///     Person { id: 4, name: "Eve".to_string(), email: "eve@example.com".to_string() },
266/// };
267/// assert_eq!(map.get1(&3).unwrap().name, "Charlie");
268/// assert_eq!(map.get2("Eve").unwrap().id, 4);
269/// # }
270/// ```
271#[macro_export]
272macro_rules! tri_hash_map {
273    ($($item:expr,)+) => { $crate::tri_hash_map!($($item),+) };
274    ($($item:expr),*) => {
275        {
276            // Note: `stringify!($key)` is just here to consume the repetition,
277            // but we throw away that string literal during constant evaluation.
278            const CAP: usize = <[()]>::len(&[$({ stringify!($item); }),*]);
279            let mut map = $crate::TriHashMap::with_capacity(CAP);
280            $(
281                map.insert_unique($item).unwrap();
282            )*
283            map
284        }
285    };
286    ($H:ty; $($item:expr,)+) => { $crate::tri_hash_map!($H; $($item),+) };
287    ($H:ty; $($item:expr),*) => {
288        {
289            // Note: `stringify!($key)` is just here to consume the repetition,
290            // but we throw away that string literal during constant evaluation.
291            const CAP: usize = <[()]>::len(&[$({ stringify!($item); }),*]);
292            let mut map = $crate::TriHashMap::with_capacity_and_hasher(CAP, <$H>::default());
293            $(
294                map.insert_unique($item).unwrap();
295            )*
296            map
297        }
298    };
299}
300
301/// Implement upcasts for [`IdOrdMap`] or [`IdHashMap`].
302///
303/// The maps in this crate require that the key types' lifetimes are covariant.
304/// This macro assists with implementing this requirement.
305///
306/// The macro is optional, and these implementations can be written by hand as
307/// well.
308///
309/// [`IdOrdMap`]: crate::IdOrdMap
310/// [`IdHashMap`]: crate::IdHashMap
311#[macro_export]
312macro_rules! id_upcast {
313    () => {
314        #[inline]
315        fn upcast_key<'short, 'long: 'short>(
316            long: Self::Key<'long>,
317        ) -> Self::Key<'short>
318        where
319            Self: 'long,
320        {
321            long
322        }
323    };
324}
325
326/// Implement upcasts for [`BiHashMap`].
327///
328/// The maps in this crate require that the key types' lifetimes are covariant.
329/// This macro assists with implementing this requirement.
330///
331/// The macro is optional, and these implementations can be written by hand as
332/// well.
333///
334/// [`BiHashMap`]: crate::BiHashMap
335#[macro_export]
336macro_rules! bi_upcast {
337    () => {
338        #[inline]
339        fn upcast_key1<'short, 'long: 'short>(
340            long: Self::K1<'long>,
341        ) -> Self::K1<'short>
342        where
343            Self: 'long,
344        {
345            long
346        }
347
348        #[inline]
349        fn upcast_key2<'short, 'long: 'short>(
350            long: Self::K2<'long>,
351        ) -> Self::K2<'short>
352        where
353            Self: 'long,
354        {
355            long
356        }
357    };
358}
359
360/// Implement upcasts for [`TriHashMap`].
361///
362/// The maps in this crate require that the key types' lifetimes are covariant.
363/// This macro assists with implementing this requirement.
364///
365/// The macro is optional, and these implementations can be written by hand as
366/// well.
367///
368/// [`TriHashMap`]: crate::TriHashMap
369#[macro_export]
370macro_rules! tri_upcast {
371    () => {
372        #[inline]
373        fn upcast_key1<'short, 'long: 'short>(
374            long: Self::K1<'long>,
375        ) -> Self::K1<'short>
376        where
377            Self: 'long,
378        {
379            long
380        }
381
382        #[inline]
383        fn upcast_key2<'short, 'long: 'short>(
384            long: Self::K2<'long>,
385        ) -> Self::K2<'short>
386        where
387            Self: 'long,
388        {
389            long
390        }
391
392        #[inline]
393        fn upcast_key3<'short, 'long: 'short>(
394            long: Self::K3<'long>,
395        ) -> Self::K3<'short>
396        where
397            Self: 'long,
398        {
399            long
400        }
401    };
402}
403
404// Internal macro to implement diffs.
405#[cfg(feature = "daft")]
406macro_rules! impl_diff_ref_cast {
407    ($self: ident, $diff_ty: ty, $key_method: ident, $get_method: ident, $contains_method: ident, $ref_cast_ty: ty) => {{
408        let hasher = $self.before.hasher().clone();
409        let alloc = $self.before.allocator().clone();
410        let mut diff = <$diff_ty>::with_hasher_in(hasher, alloc);
411        for before_item in $self.before {
412            if let Some(after_item) =
413                $self.after.$get_method(&before_item.$key_method())
414            {
415                diff.common.insert_overwrite(IdLeaf::new(
416                    <$ref_cast_ty>::ref_cast(before_item),
417                    <$ref_cast_ty>::ref_cast(after_item),
418                ));
419            } else {
420                diff.removed
421                    .insert_overwrite(<$ref_cast_ty>::ref_cast(before_item));
422            }
423        }
424        for after_item in $self.after {
425            if !$self.before.$contains_method(&after_item.$key_method()) {
426                diff.added
427                    .insert_overwrite(<$ref_cast_ty>::ref_cast(after_item));
428            }
429        }
430        diff
431    }};
432}