#[macro_export]
macro_rules! define {
(
$(
$(#[$meta: meta])*
$(@[$modmeta: meta])*
$vis: vis fn $identifier: ident
$(< $($typearg: ident),+ >)?
::= { $($definition: tt)+ }
$(where $($lhs: tt : $rhs: tt),+ $(,)?)?
;
)*
) => {::paste::paste! {
$(
#[allow(non_snake_case)]
$(#[$modmeta])*
mod [< __$identifier >] {
#![allow(unused_parens, non_camel_case_types, unused_imports)]
use super::*;
$crate::define!{ @item $(#[$meta])* $identifier ; $($($typearg)+)? }
$crate::define!{
@impl $identifier; $($($typearg)+)? ;
{ $($definition)+ }
$(where $($lhs: $rhs),+)?
}
}
$(#[$modmeta])*
$vis use [< __$identifier >]::$identifier;
)*
}};
(
@item $(#[$meta: meta])* $name: ident ; $($($typearg: ident)+)?
) => {
$(#[$meta])*
#[allow(unused_parens)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
pub struct $name $( < $($typearg),+ > )? {
_p: ::core::marker::PhantomData<($($($typearg,)+)?)>
}
};
(
@impl $ident: ident ; $($arg: ident)*;
{ $name: ident . $name2: ident . $($definition: tt)+ } $(where $($lhs: tt:$rhs: tt),+)?
) => { ::paste::paste! {
#[allow(non_camel_case_types)]
impl<$($arg, )* $name> $crate::Function<$name> for $ident < $($arg,)* > {
type Output = [< $ident __ $name >] <$($arg,)* $name>;
}
$crate::define! {
@item #[doc(hidden)] [< $ident __ $name >] ; $($arg)* $name
}
$crate::define! {
@impl [<$ident __ $name>] ; $($arg)* $name;
{ $name2 . $($definition)+ } $(where $($lhs : $rhs),+)?
}
} };
(
@impl $ident: ident ; $($args: ident)*;
{ $name: ident . $definition: tt } $(where $($lhs: tt:$rhs: tt),+)?
) => {
#[allow(non_camel_case_types)]
impl<$($args, )* $name> $crate::Function<$name> for $ident <$($args, )*>
$(
where
$(
$crate::call!($lhs) : $crate::Function<$crate::call!($rhs)>
),+
)?
{
type Output = $crate::call!{ $definition };
}
};
}
#[macro_export]
macro_rules! call {
({$($wrapped: tt)+}) => { $crate::call!($($wrapped)+) };
($name: ty) => { $name };
($name: ty , $arg: ty) => {
<$name as $crate::Function<$arg>>::Output
};
($name: ty , { $($arg: tt)+ } $($arg2: tt)*) => {
$crate::call!( $crate::call!($name , $crate::call!($($arg)+) ) $($arg2)* )
};
($name: ty , $arg: ty , $($arg2: tt)+) => {
$crate::call!( $crate::call!($name , $arg), $($arg2)+ )
};
}
#[macro_export]
macro_rules! chained {
($name: ident with $lhs: ty, $rhs: ty $(, $extra: ty)+) => {
$name<$lhs, $crate::chained!($name with $rhs $(, $extra)+)>
};
($name: ident with $lhs: ty, $rhs: ty) => {
$name<$lhs, $rhs>
}
}