1#[macro_export]
31macro_rules! hlist {
32 () => { $crate::hlist::HNil };
33 (...$rest:expr) => { $rest };
34 ($a:expr) => { $crate::hlist![$a,] };
35 ($a:expr, $($tok:tt)*) => {
36 $crate::hlist::HCons {
37 head: $a,
38 tail: $crate::hlist![$($tok)*],
39 }
40 };
41}
42
43#[macro_export]
69macro_rules! hlist_pat {
70 () => { $crate::hlist::HNil };
71 (...) => { _ };
72 (...$rest:pat) => { $rest };
73 (_) => { $crate::hlist_pat![_,] };
74 ($a:pat) => { $crate::hlist_pat![$a,] };
75 (_, $($tok:tt)*) => {
76 $crate::hlist::HCons {
77 tail: $crate::hlist_pat![$($tok)*],
78 ..
79 }
80 };
81 ($a:pat, $($tok:tt)*) => {
82 $crate::hlist::HCons {
83 head: $a,
84 tail: $crate::hlist_pat![$($tok)*],
85 }
86 };
87}
88
89#[macro_export]
106macro_rules! HList {
107 () => { $crate::hlist::HNil };
108 (...$Rest:ty) => { $Rest };
109 ($A:ty) => { $crate::HList![$A,] };
110 ($A:ty, $($tok:tt)*) => {
111 $crate::hlist::HCons<$A, $crate::HList![$($tok)*]>
112 };
113}
114
115#[macro_export]
134macro_rules! Coprod {
135 () => { $crate::coproduct::CNil };
136 (...$Rest:ty) => { $Rest };
137 ($A:ty) => { $crate::Coprod![$A,] };
138 ($A:ty, $($tok:tt)*) => {
139 $crate::coproduct::Coproduct<$A, $crate::Coprod![$($tok)*]>
140 };
141}
142
143#[macro_export]
193macro_rules! field {
194 (($($repeated: ty),*), $value: expr) => {
196 $crate::field!( ($($repeated),*), $value, concat!( $(stringify!($repeated)),* ) )
197 };
198 (($($repeated: ty,)*), $value: expr) => {
200 $crate::field!( ($($repeated),*), $value )
201 };
202 ($name_type: ty, $value: expr) => {
204 $crate::field!( $name_type, $value, stringify!($name_type) )
205 };
206 ($name_type: ty, $value: expr, $name: expr) => {
208 $crate::labelled::field_with_name::<$name_type,_>($name, $value)
209 }
210}
211
212#[macro_export]
237macro_rules! poly_fn {
238 ([$($tparams: tt),*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty $body: block , $($rest: tt)*)
240 => { $crate::poly_fn!(
241 p~ [$($tparams, )*] |$arg: $arg_typ| -> $ret_typ $body, ~p f~ ~f $($rest)*
242 )};
243 ([$($tparams: tt, )*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty $body: block , $($rest: tt)*)
245 => { $crate::poly_fn!(
246 p~ [$($tparams, )*] |$arg: $arg_typ| -> $ret_typ $body, ~p f~ ~f $($rest)*
247 )};
248 (|$arg: ident : $arg_typ: ty| -> $ret_typ: ty $body: block, $($rest: tt)*)
250 => { $crate::poly_fn!(
251 p~ ~p f~ |$arg: $arg_typ| -> $ret_typ $body, ~f $($rest)*
252 )};
253
254 (p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty $p_body: block , )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty $f_body: block , )* ~f [$($tparams: tt),*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty $body: block , $($rest: tt)*)
256 => { $crate::poly_fn!(
257 p~ [$($tparams, )*] |$arg: $arg_typ| -> $ret_typ $body, $( [$($pars, )*] |$p_args: $p_arg_typ| -> $p_ret_typ $p_body, )* ~p f~ $(|$f_args: $f_arg_typ| -> $f_ret_typ $f_body, )* ~f $($rest)*
258 )};
259 (p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty { $p_body: block }, )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty $f_body: block, )* ~f [$($tparams: tt, )*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty $body: block, $($rest: tt)*)
261 => { $crate::poly_fn!(
262 p~ [$($tparams, )*] |$arg: $arg_typ| -> $ret_typ $body, $( [$($pars, )*] |$p_args: $p_arg_typ| -> $p_ret_typ $p_body, )* ~p f~ $(|$f_args: $f_arg_typ| -> $f_ret_typ $f_body, )* ~f $($rest)*
263 )};
264 (p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty $p_body: block, )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty $f_body: block, )* ~f |$arg: ident : $arg_typ: ty| -> $ret_typ: ty $body: block, $($rest: tt)*)
266 => { $crate::poly_fn!(
267 p~ $( [$($pars, )*] |$p_args: $p_arg_typ| -> $p_ret_typ $p_body, )* ~p f~ |$arg: $arg_typ| -> $ret_typ $body, $(|$f_args: $f_arg_typ| -> $f_ret_typ $f_body, )* ~f $($rest)*
268 )};
269
270 (p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty $p_body: block, )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty $f_body: block, )* ~f [$($tparams: tt),*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty $body: block)
272 => { $crate::poly_fn!(
273 p~ [$($tparams, )*] |$arg: $arg_typ| -> $ret_typ $body, $( [$($pars, )*] |$p_args: $p_arg_typ| -> $p_ret_typ $p_body, )* ~p f~ $(|$f_args: $f_arg_typ| -> $f_ret_typ $f_body, )* ~f
274 )};
275 (p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty $p_body: block, )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty $f_body: block, )* ~f [$($tparams: tt, )*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty $body: block)
277 => { $crate::poly_fn!(
278 p~ [$($tparams, )*] |$arg: $arg_typ| -> $ret_typ $body, $( [$($pars, )*] |$p_args: $p_arg_typ| -> $p_ret_typ $p_body, )* ~p f~ $(|$f_args: $f_arg_typ| -> $f_ret_typ $f_body, )* ~f
279 )};
280 (p~ $([$($pars: tt)*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty $p_body: block, )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty $f_body: block, )* ~f |$arg: ident : $arg_typ: ty| -> $ret_typ: ty $body: block)
282 => { $crate::poly_fn!(
283 p~ $( [$($pars, )*] |$p_args: $p_arg_typ| -> $p_ret_typ $p_body, )* ~p f~ |$arg: $arg_typ| -> $ret_typ $body, $(|$f_args: $f_arg_typ| -> $f_ret_typ $f_body, )* ~f
284 )};
285
286 (p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty $p_body: block, )* ~p f~ $(|$args: ident : $arg_typ: ty| -> $ret_typ: ty $body: block, )* ~f) => {{
288 struct F;
289 $(
290 impl<$($pars,)*> $crate::traits::Func<$p_arg_typ> for F {
291 type Output = $p_ret_typ;
292
293 fn call($p_args: $p_arg_typ) -> Self::Output { $p_body }
294 }
295 )*
296 $(
297 impl $crate::traits::Func<$arg_typ> for F {
298 type Output = $ret_typ;
299
300 fn call($args: $arg_typ) -> Self::Output { $body }
301 }
302 )*
303 $crate::traits::Poly(F)
304 }}
305}
306
307#[cfg(test)]
308mod tests {
309 #[allow(clippy::diverging_sub_expression)]
310 #[test]
311 fn trailing_commas() {
312 use crate::test_structs::unit_copy::{A, B};
313
314 let hlist_pat![]: HList![] = hlist![];
315 let hlist_pat![A]: HList![A] = hlist![A];
316 let hlist_pat![A,]: HList![A,] = hlist![A,];
317 let hlist_pat![A, B]: HList![A, B] = hlist![A, B];
318 let hlist_pat![A, B,]: HList![A, B,] = hlist![A, B,];
319
320 let falsum = || false;
321 if falsum() {
322 let _: Coprod![] = panic!();
323 }
324 if falsum() {
325 let _: Coprod![A] = panic!();
326 }
327 if falsum() {
328 let _: Coprod![A,] = panic!();
329 }
330 if falsum() {
331 let _: Coprod![A, B] = panic!();
332 }
333 if falsum() {
334 let _: Coprod![A, B,] = panic!();
335 }
336 }
337
338 #[test]
339 fn ellipsis_tail() {
340 use crate::coproduct::Coproduct;
341 use crate::test_structs::unit_copy::{A, B, C};
342
343 let hlist_pat![...hlist_pat![C]]: HList![...HList![C]] = { hlist![...hlist![C]] };
345 let hlist_pat![A, ...hlist_pat![C]]: HList![A, ...HList![C]] = { hlist![A, ...hlist![C]] };
346 let hlist_pat![A, B, ...hlist_pat![C]]: HList![A, B, ...HList![C]] =
347 { hlist![A, B, ...hlist![C]] };
348
349 let hlist_pat![A, B, C] = hlist![A, ...hlist![B, C]];
352 let hlist_pat![A, ...hlist_pat![B, C]] = hlist![A, B, C];
353
354 let choice: Coprod![A, B, C] = Coproduct::inject(A);
356 let _: Coprod![...Coprod![A, B, C]] = choice;
357 let _: Coprod![A, ...Coprod![B, C]] = choice;
358 let _: Coprod![A, B, ...Coprod![C]] = choice;
359 }
360
361 #[test]
362 fn ellipsis_ignore() {
363 use crate::test_structs::unit_copy::{A, B, C, D, E};
364
365 let hlist_pat![...] = hlist![A, B, C, D, E];
367 let hlist_pat![A, ...] = hlist![A, B, C, D, E];
368 let hlist_pat![A, B, ...] = hlist![A, B, C, D, E];
369 }
370
371 #[test]
372 fn poly_fn_macro_test() {
373 let h = hlist![9000, "joe", 41f32, "schmoe", 50];
374 let h2 = h.map(poly_fn!(
375 |x: i32| -> bool { x > 100 },
376 |_x: f32| -> &'static str { "dummy" },
377 ['a] |x: &'a str| -> usize { x.len() }
378 ));
379 assert_eq!(h2, hlist![true, 3, "dummy", 6, false]);
380 }
381
382 #[test]
383 fn poly_fn_macro_coproduct_test() {
384 type I32F32StrBool<'a> = Coprod!(i32, f32, &'a str);
385
386 let co1 = I32F32StrBool::inject("lollerskates");
387 let folded = co1.fold(poly_fn!(
388 ['a] |_x: &'a str| -> i8 { 1 },
389 |_x: i32| -> i8 { 2 },
390 |_f: f32| -> i8 { 3 },
391 ));
392 assert_eq!(folded, 1);
393 }
394
395 #[test]
396 fn poly_fn_macro_trailing_commas_test() {
397 let h = hlist![9000, "joe", 41f32, "schmoe", 50];
398 let h2 = h.map(poly_fn!(
399 |x: i32| -> bool { x > 100 },
400 |_x: f32| -> &'static str { "dummy" },
401 ['a,] |x: &'a str| -> usize { x.len() },
402 ));
403 assert_eq!(h2, hlist![true, 3, "dummy", 6, false]);
404 }
405
406 #[test]
407 fn poly_fn_macro_multiline_bodies_test() {
408 let h = hlist![9000, 1, -1];
409 let h2 = h.map(poly_fn!(|x: i32| -> bool {
410 let a = if x > 100 { 1 } else { -1 };
411 a > 0
412 },));
413 assert_eq!(h2, hlist![true, false, false]);
414 }
415
416 #[test]
417 #[deny(clippy::unneeded_field_pattern)]
418 fn unneeded_field_pattern() {
419 let hlist_pat![_, _] = hlist![1, 2];
420 let hlist_pat![foo, _, baz] = hlist!["foo", "bar", "baz"];
421 assert_eq!(foo, "foo");
422 assert_eq!(baz, "baz");
423 }
424}