#[macro_export]
macro_rules! hlist {
() => { $crate::hlist::HNil };
(...$rest:expr) => { $rest };
($a:expr) => { $crate::hlist![$a,] };
($a:expr, $($tok:tt)*) => {
$crate::hlist::HCons {
head: $a,
tail: $crate::hlist![$($tok)*],
}
};
}
#[macro_export]
macro_rules! hlist_pat {
() => { $crate::hlist::HNil };
(...) => { _ };
(...$rest:pat) => { $rest };
($a:pat) => { $crate::hlist_pat![$a,] };
($a:pat, $($tok:tt)*) => {
$crate::hlist::HCons {
head: $a,
tail: $crate::hlist_pat![$($tok)*],
}
};
}
#[macro_export]
macro_rules! Hlist {
() => { $crate::hlist::HNil };
(...$Rest:ty) => { $Rest };
($A:ty) => { $crate::Hlist![$A,] };
($A:ty, $($tok:tt)*) => {
$crate::hlist::HCons<$A, $crate::Hlist![$($tok)*]>
};
}
#[macro_export]
macro_rules! Coprod {
() => { $crate::coproduct::CNil };
(...$Rest:ty) => { $Rest };
($A:ty) => { $crate::Coprod![$A,] };
($A:ty, $($tok:tt)*) => {
$crate::coproduct::Coproduct<$A, $crate::Coprod![$($tok)*]>
};
}
#[macro_export]
macro_rules! field {
(($($repeated: ty),*), $value: expr) => {
$crate::field!( ($($repeated),*), $value, concat!( $(stringify!($repeated)),* ) )
};
(($($repeated: ty,)*), $value: expr) => {
$crate::field!( ($($repeated),*), $value )
};
($name_type: ty, $value: expr) => {
$crate::field!( $name_type, $value, stringify!($name_type) )
};
($name_type: ty, $value: expr, $name: expr) => {
$crate::labelled::field_with_name::<$name_type,_>($name, $value)
}
}
#[macro_export]
macro_rules! poly_fn {
([$($tparams: tt),*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty { $body: expr }, $($rest: tt)*)
=> { $crate::poly_fn!(
p~ [$($tparams, )*] |$arg: $arg_typ| -> $ret_typ {$body}, ~p f~ ~f $($rest)*
)};
([$($tparams: tt, )*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty { $body: expr }, $($rest: tt)*)
=> { $crate::poly_fn!(
p~ [$($tparams, )*] |$arg: $arg_typ| -> $ret_typ {$body}, ~p f~ ~f $($rest)*
)};
(|$arg: ident : $arg_typ: ty| -> $ret_typ: ty { $body: expr }, $($rest: tt)*)
=> { $crate::poly_fn!(
p~ ~p f~ |$arg: $arg_typ| -> $ret_typ {$body}, ~f $($rest)*
)};
(p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty { $p_body: expr }, )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty { $f_body: expr }, )* ~f [$($tparams: tt),*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty { $body: expr }, $($rest: tt)*)
=> { $crate::poly_fn!(
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)*
)};
(p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty { $p_body: expr }, )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty { $f_body: expr }, )* ~f [$($tparams: tt, )*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty { $body: expr }, $($rest: tt)*)
=> { $crate::poly_fn!(
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)*
)};
(p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty { $p_body: expr }, )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty { $f_body: expr }, )* ~f |$arg: ident : $arg_typ: ty| -> $ret_typ: ty { $body: expr }, $($rest: tt)*)
=> { $crate::poly_fn!(
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)*
)};
(p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty { $p_body: expr }, )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty { $f_body: expr }, )* ~f [$($tparams: tt),*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty { $body: expr })
=> { $crate::poly_fn!(
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
)};
(p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty { $p_body: expr }, )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty { $f_body: expr }, )* ~f [$($tparams: tt, )*] |$arg: ident : $arg_typ: ty| -> $ret_typ: ty { $body: expr })
=> { $crate::poly_fn!(
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
)};
(p~ $([$($pars: tt)*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty { $p_body: expr }, )* ~p f~ $(|$f_args: ident : $f_arg_typ: ty| -> $f_ret_typ: ty { $f_body: expr }, )* ~f |$arg: ident : $arg_typ: ty| -> $ret_typ: ty { $body: expr })
=> { $crate::poly_fn!(
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
)};
(p~ $([$($pars: tt, )*] |$p_args: ident : $p_arg_typ: ty| -> $p_ret_typ: ty { $p_body: expr }, )* ~p f~ $(|$args: ident : $arg_typ: ty| -> $ret_typ: ty { $body: expr }, )* ~f) => {{
struct F;
$(
impl<$($pars,)*> $crate::traits::Func<$p_arg_typ> for F {
type Output = $p_ret_typ;
fn call($p_args: $p_arg_typ) -> Self::Output { $p_body }
}
)*
$(
impl $crate::traits::Func<$arg_typ> for F {
type Output = $ret_typ;
fn call($args: $arg_typ) -> Self::Output { $body }
}
)*
$crate::traits::Poly(F)
}}
}
#[cfg(test)]
mod tests {
#[test]
fn trailing_commas() {
use test_structs::unit_copy::{A, B};
let hlist_pat![]: Hlist![] = hlist![];
let hlist_pat![A]: Hlist![A] = hlist![A];
let hlist_pat![A,]: Hlist![A,] = hlist![A,];
let hlist_pat![A, B]: Hlist![A, B] = hlist![A, B];
let hlist_pat![A, B,]: Hlist![A, B,] = hlist![A, B,];
let falsum = || false;
if falsum() {
let _: Coprod![] = panic!();
}
if falsum() {
let _: Coprod![A] = panic!();
}
if falsum() {
let _: Coprod![A,] = panic!();
}
if falsum() {
let _: Coprod![A, B] = panic!();
}
if falsum() {
let _: Coprod![A, B,] = panic!();
}
}
#[test]
fn ellipsis_tail() {
use coproduct::Coproduct;
use test_structs::unit_copy::{A, B, C};
let hlist_pat![...hlist_pat![C]]: Hlist![...Hlist![C]] = { hlist![...hlist![C]] };
let hlist_pat![A, ...hlist_pat![C]]: Hlist![A, ...Hlist![C]] = { hlist![A, ...hlist![C]] };
let hlist_pat![A, B, ...hlist_pat![C]]: Hlist![A, B, ...Hlist![C]] =
{ hlist![A, B, ...hlist![C]] };
let hlist_pat![A, B, C] = hlist![A, ...hlist![B, C]];
let hlist_pat![A, ...hlist_pat![B, C]] = hlist![A, B, C];
let choice: Coprod![A, B, C] = Coproduct::inject(A);
let _: Coprod![...Coprod![A, B, C]] = choice;
let _: Coprod![A, ...Coprod![B, C]] = choice;
let _: Coprod![A, B, ...Coprod![C]] = choice;
}
#[test]
fn ellipsis_ignore() {
use test_structs::unit_copy::{A, B, C, D, E};
let hlist_pat![...] = hlist![A, B, C, D, E];
let hlist_pat![A, ...] = hlist![A, B, C, D, E];
let hlist_pat![A, B, ...] = hlist![A, B, C, D, E];
}
#[test]
fn poly_fn_macro_test() {
let h = hlist![9000, "joe", 41f32, "schmoe", 50];
let h2 = h.map(poly_fn!(
|x: i32| -> bool { x > 100 },
|_x: f32| -> &'static str { "dummy" },
['a] |x: &'a str| -> usize { x.len() }
));
assert_eq!(h2, hlist![true, 3, "dummy", 6, false]);
}
#[test]
fn poly_fn_macro_coproduct_test() {
type I32F32StrBool<'a> = Coprod!(i32, f32, &'a str);
let co1 = I32F32StrBool::inject("lollerskates");
let folded = co1.fold(poly_fn!(
['a] |_x: &'a str| -> i8 { 1 },
|_x: i32| -> i8 { 2 },
|_f: f32| -> i8 { 3 },
));
assert_eq!(folded, 1);
}
#[test]
fn poly_fn_macro_trailing_commas_test() {
let h = hlist![9000, "joe", 41f32, "schmoe", 50];
let h2 = h.map(poly_fn!(
|x: i32| -> bool { x > 100 },
|_x: f32| -> &'static str { "dummy" },
['a,] |x: &'a str| -> usize { x.len() },
));
assert_eq!(h2, hlist![true, 3, "dummy", 6, false]);
}
}