macro_rules! impl_parse_generics {
    (
        $(:: $(@$leading:tt@)? )? $first:ident $(:: $trailing:ident)* ! $prefix:tt

        ($($tt:tt)*)
    ) => { ... };
}
Available on crate feature item_parsing only.
Expand description

For parsing impl blocks, transforming the generic parameters to a form easily parsable by the callback macro.

Example

Basic

Basic examples 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::impl_parse_generics;
 
assert_eq!(hello(), "world");
 
// impl_parse_generics invokes `bar` here
impl_parse_generics!{
    crate::bar!{
        // The first tokens passed to the `bar` macro
        hello "world" foo bar 
    }
    (
        #[foo]
        unsafe impl<'a: 'b, T: Foo, U, const X: usize> Trait<X, Y> for Type
        where U: Bar 
        {
            fn hello(){} 
        }
    )
}
 
#[macro_export]
macro_rules! bar {
    (
        $fn_name:ident $returns:literal foo bar 
        // the attributes
        (#[foo])
        // the qualifiers (if `const impl` becomes a thing, i'll be included here)
        (unsafe)
        // The generic parameters are classified by kind
        // Bounds always have a trailing `+``
        // Generic parameters always have a trailing `,`
        (
            ('a:('b +),)          // lifetimes
            (T:(Foo +), U:(),)  // types
            (X: $const_ty:ty,) // constants
        )
        // the imlpemented trait.
        // If this not a trait impl, then `trait(....)` is not passed
        trait(Trait<X, Y>)
        // the type that this is an impl for
        type(Type)
        // inside the where clause, this always has a trailing comma
        (U: Bar,)
        // the body of the impl
        ({ fn hello() {} })
    ) => {
        fn $fn_name() -> &'static str {
            $returns
        }
    };
}
 

More Realistic Example

This example demonstrates a macro to avoid having to repeat generic parameters and bounds.

use std::ops::Index;
 
fn main() {
    let foo = Foo([3, 5], vec![8, 13, 21]);
     
    assert_eq!(foo.get(), [3, 5]);
    assert_eq!(foo[0], 8);
    assert_eq!(foo[1], 13);
    assert_eq!(foo[2], 21);
}
 
struct Foo<T, U>(T, U);
 
repeat_generics!{
    impl<T: Clone, U> Foo<T, U>
    where 
        U: IntoIterator<Item = u32>;
     
    impl Self {
        fn get(&self) -> T {
            self.0.clone()
        }
    }
     
    impl<V> Index<V> for Self 
    where
        U: Index<V>
    {
        type Output = U::Output;
         
        fn index(&self, index: V) -> &U::Output {
            &self.1[index]
        }
    }
}
 
 
 
#[macro_export]
macro_rules! repeat_generics {
    ($($tokens:tt)*)=>{
        $crate::__::impl_parse_generics!{
            $crate::__priv_inner_repeat_generics!{@process}
            ($($tokens)*)
        }
    }
}
 
#[doc(hidden)]
#[macro_export]
macro_rules! __priv_inner_repeat_generics {
    (
        @process
        $attrs:tt
        ()
        (
            ($($lt:lifetime :($($lt_bound:tt)*),)*)
            ($($ty:ident :($($ty_bound:tt)*),)*)
            ($($const:ident: $const_ty:ty,)*)
        )
        $(trait $trait:tt)?
        type $Self:tt
        $where_preds:tt
        ( ; $($items:tt)* )
    ) => {
        $(
            $crate::__::compile_error!{concat!(
                "cannot implement a trait in the impl without a body: ",
                stringify!($trait),
            )}
        )?
 
        $crate::__priv_inner_repeat_generics!{
            @iterate
            (
                $attrs
                (
                    ($($lt: $($lt_bound)*,)*) 
                    ($($ty: $($ty_bound)*,)*)
                    ($(const $const: $const_ty,)*)
                )
                $Self
                $where_preds
            )
            $($items)*
        }
    };
    ( @iterate $params:tt $($item:item)* )=>{
        $(
            $crate::__::impl_parse_generics!{
                $crate::__priv_inner_repeat_generics!{@inner $params}
                ($item)
            }
        )*
    };
    (
        @inner
        (
            ($($out_attrs:tt)*)
            ( ($($out_lt:tt)*) ($($out_ty:tt)*) ($($out_const:tt)*) )
            ($Self:ty)
            ($($outer_where:tt)*)
        )
 
        ($($in_attrs:tt)*)
        ($($qualifiers:tt)*)
        (
            ($($lt:lifetime :($($lt_bound:tt)*),)*)
            ($($ty:ident :($($ty_bound:tt)*),)*)
            ($($const:ident: $const_ty:ty,)*)
        )
        $(trait($trait:ty))?
        type(Self)
        ($($inner_where:tt)*)
        ({ $($items:tt)* })
    ) => {
        $($out_attrs)*
        $($in_attrs)*
        $($qualifiers)* 
        impl<
            $($out_lt)* $($lt: $($lt_bound)*,)*
            $($out_ty)* $($ty: $($ty_bound)*,)*
            $($out_const)* $(const $const: $const_ty,)*
        > $( $trait for )? $Self
        where
            $($outer_where)*
            $($inner_where)*
        {
            $($items)*
        }
    }
}
 
 
#[doc(hidden)]
pub mod __ {
    pub use std::compile_error;
 
    pub use core_extensions::impl_parse_generics;
}