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}