macro_rules! parse_split_generics_and_where {
    (
        $(:: $(@$leading:tt@)? )? $first:ident $(:: $trailing:ident)* ! $prefix:tt
        ($($generics:tt)*)
    ) => { ... };
}
Available on crate feature generics_parsing only.
Expand description

For parsing item definitions, transforming generics to a form easily parsable by a callback macro.

Examples

Basic

Basic example of using this macro, and what it passes to a callback macro.

For a more realistic example you can look at the one below

use core_extensions::parse_split_generics_and_where;
 
{
    assert_eq!(hello(), "world")
}
 
// `parse_split_generics_and_where` calls `crate::foo` here
parse_split_generics_and_where! {
    foo!{ 
        // The first tokens passed to the `crate::foo` macro
        hello "world" foo bar 
    }
     
    (
        // The parsed tokens
        <'a: 'b, 'b, T: 'a + Foo = Bar, const X: u32 = 10, U = Baz, V> (param: Type) -> u32 
        where
            T: Bar
        { println }
    )
}
 
#[macro_export]
macro_rules! foo {
    (
        $fn_name:ident $string:literal foo bar

        // The generic paremeters in the order they came in
        // Bounds always have a trailing `+``
        (
            ('a:('b +))
            ('b:()) 
            (type T:('a + Foo +) = $def_t:ty,)
            (const X: $ty_x:ty = $def_x:expr,)
            (type U:() = $def_u:ty,)
            (type V:(),)
        )
        // The generic parameters are classified by kind
        // Bounds always have a trailing `+``
        // Generic parameters always have a trailing `,`
        (
            ('a:('b +), 'b:(),)                                      // lifetimes
            (T:('a + Foo +) = $defb_t:ty, U:() = $defb_u:ty, V:(),)  // types
            (X: $tyb_x:ty = $defb_x:expr,)                           // constants
        )

        // before the where clause
        ((param: Type) -> u32 )

        // inside the where clause
        (T: Bar,)

        // after the where clause
        ( { println } )
    ) => {
        fn $fn_name() -> &'static str {
            $string
        }
    };
    ($($tt:tt)*) => { compile_error!{ stringify!($($tt)*) } }
}

Derive macro

This demonstrates how you can implement a derive through a macro_rules! macro.

use core_extensions::parse_split_generics_and_where;
 
fn main() {
    assert_eq!(Foo{bar: "hi", baz: vec![0]}.add_up(), 2);
    assert_eq!(Foo{bar: "hello", baz: vec![0]}.add_up(), 5);
    assert_eq!(Foo{bar: "hello", baz: vec![3]}.add_up(), 8);
    assert_eq!(Foo{bar: "hello", baz: vec![3, 5]}.add_up(), 13);
}
 
crate::derives!{
    #[derive(crate::derive_AddUp)]
     
    struct Foo<T> {
        bar: &'static str,
        baz: T,
    }
}
 
pub trait AddUp {
    fn add_up(&self) -> u128;
}
 
impl AddUp for u8 {
    fn add_up(&self) -> u128 {
        *self as u128
    }
}
 
impl AddUp for &str {
    fn add_up(&self) -> u128 {
        self.len() as u128
    }
}
 
impl<T: AddUp> AddUp for &[T] {
    fn add_up(&self) -> u128 {
        self.iter().map(AddUp::add_up).sum()
    }
}

impl<T: AddUp> AddUp for Vec<T> {
    fn add_up(&self) -> u128 {
        self.iter().map(AddUp::add_up).sum()
    }
}
 
 
 
#[macro_export]
macro_rules! derives {
    (#[derive $derives:tt]  $($type:tt)*) => {
        $($type)*
         
        $crate::derives!{@inner $derives {$($type)*} }
    };
    (@inner ($($derive:path),*) $type:tt ) => {
        $( $derive! $type )*
    }
}
 
#[macro_export]
macro_rules! derive_AddUp {
    (
        $(#[$attr:meta])*
        $vis:vis 
        struct $name:ident $($generics:tt)*
    ) => {
        parse_split_generics_and_where!{
            $crate::__priv_derive_AddUp! {
                $name,
            }
            ($($generics)*)
        }
    }
}
 
#[doc(hidden)]
#[macro_export]
macro_rules! __priv_derive_AddUp{
    (
        $name:ident,
        (
            $( ($lt:lifetime :( $($lt_bounds:tt)* )) )*
            $((
                $( type $typ:ident :($($ty_bound:tt)*) $(= $ty_default:ty )? , )?
                $( const $const:ident :($($const_bound:tt)*) $(= $const_default:expr )? , )?
            ))*
        )
        $generic_in_order:tt
        $__between_generics_and_where:tt
        ( $($where_preds:tt)* )
        ({
            $(
                $(#[$fattr:meta])* $fvis:vis $fname:ident : $fty:ty 
            ),* $(,)?
        })
    ) => {
        impl<
            $($lt: $($lt_bounds)* ,)*
            $(
                $($typ: $($ty_bound)* $crate::AddUp + )?
                $(const $const: $($const_bound)* )?,
            )*
        > $name<$($lt,)* $($($typ)? $($const)? ,)*>
        where
            $($where_preds)*
        {
            fn add_up(&self) -> u128 {
                0
                $( + self.$fname.add_up() )*
            }
        }
    };
}