func_wrap 0.1.3

Helper crate for procedural macro authors that wish to duplicate some received function inside its body, so as to be able to wrap with some prologue, epilogue, cache-ing, etc.
Documentation
use ::func_wrap::*;
use ::proc_macro2::TokenStream;
use ::quote::ToTokens;
use ::syn::*;

macro_rules! parse_macro_input_2 {( $input:expr ) => (
    match ::syn::parse2($input) {
        | Ok(it) => it,
        | Err(err) => panic!("{}", err),
    }
)}

#[cfg(any())]
macro_rules! dbg_parse_quote {( $($tt:tt)* ) => (
    {
        eprintln!("{}", ::quote::quote!( $($tt)* ));
        parse_quote!( $($tt)* )
    }
)}

macro_rules! ts {( $($code:tt)* ) => (
    stringify!( $($code)* )
        .parse::<TokenStream>()
        .unwrap()
)}

fn assert_token_stream_eq (
    ts1: TokenStream,
    ts2: TokenStream,
)
{
    fn assert_tt_eq (
        tt1: ::proc_macro2::TokenTree,
        tt2: ::proc_macro2::TokenTree,
    )
    {
        use ::proc_macro2::TokenTree::*;
        match (tt1, tt2) {
            | (Group(g1), Group(g2)) => assert_token_stream_eq(g1.stream(), g2.stream()),
            | (Ident(lhs), Ident(rhs)) => assert_eq!(lhs.to_string(), rhs.to_string()),
            | (Punct(lhs), Punct(rhs)) => assert_eq!(lhs.as_char(), rhs.as_char()),
            | (Literal(lhs), Literal(rhs)) => assert_eq!(lhs.to_string(), rhs.to_string()),
            | _ => panic!("Not equal!"),
        }
    }

    let mut ts1 = ts1.into_iter();
    let mut ts2 = ts2.into_iter();
    loop {
        match (ts1.next(), ts2.next()) {
            | (Some(tt1), Some(tt2)) => assert_tt_eq(tt1, tt2),
            | (None, None) => return,
            | _ => panic!("Not equal!"),
        }
    }
}

#[test]
fn simple_fn ()
{
    fn proc_macro (input: TokenStream) -> TokenStream
    {
        let mut input: ItemFn = parse_macro_input_2!(input);
        let wrapped_func_call = func_wrap(
            &mut input.sig,
            ::core::mem::replace(&mut input.block, parse_quote!( {} )),
            None,
        ).unwrap();
        input.block = parse_quote!(
            { #wrapped_func_call }
        );
        input.into_token_stream()
    }

    let input = ts! {
        fn foo (_: (), second: (), arg_0: (), (x, ): (i32, ))
        {
            println!("foo")
        }
    };
    assert_token_stream_eq(proc_macro(input), ts! {
        fn foo (arg_0: (), second: (), arg_2: (), arg_3: (i32, ))
        {
            ({
                #[inline(always)]
                fn foo (_: (), second: (), arg_0: (), (x, ): (i32, ))
                {
                    println!("foo")
                }

                foo ::<>
            })(arg_0, second, arg_2, arg_3)
        }
    });
}

#[test]
fn default_method ()
{
    fn proc_macro (input: TokenStream) -> TokenStream
    {
        let mut input: ItemTrait = parse_macro_input_2!(input);
        let method =
            if let TraitItem::Method(ref mut it) = input.items[0] {
                it
            } else {
                panic!()
            }
        ;
        let method_block = if let Some(ref mut it) = method.default { it } else {
            panic!()
        };
        let outer_scope = (
            &input.generics,
            ImplOrTrait::DefaultMethod { trait_name: &input.ident },
        );
        let wrapped_func_call = func_wrap(
            &mut method.sig,
            ::core::mem::replace(method_block, parse_quote!( {} )),
            Some(outer_scope),
        ).unwrap();
        *method_block = parse_quote!(
            { #wrapped_func_call }
        );
        input.into_token_stream()
    }

    let input = ts! {
        trait Foo<T>
        where
            () : Copy,
        {
            fn foo (self, second: (), arg_0: (), (x, ): (i32, ))
            {
                println!("foo")
            }
        }
    };
    assert_token_stream_eq(proc_macro(input), ts! {
        trait Foo<T>
        where
            () : Copy,
        {
            fn foo (self, second: (), arg_2: (), arg_3: (i32, ))
            {
                ({
                    trait __FuncWrap<T> : Foo<T>
                    where
                        () : Copy,
                    {
                        #[inline(always)]
                        fn foo (self, second: (), arg_0: (), (x, ): (i32, ))
                        {
                            println!("foo")
                        }
                    }

                    impl<T, __Self : ?Sized + Foo<T>> __FuncWrap<T>
                        for __Self
                    where
                        () : Copy,
                    {}

                    <Self as __FuncWrap<T>>::foo ::<>
                })(self, second, arg_2, arg_3)
            }
        }
    });
}

mod impls {
    use super::*;

    fn proc_macro (input: TokenStream) -> TokenStream
    {
        let mut input: ItemImpl = parse_macro_input_2!(input);
        let method =
            if let ImplItem::Method(ref mut it) = input.items[0] {
                it
            } else {
                panic!()
            }
        ;
        let outer_scope = (
            &input.generics,
            ImplOrTrait::ImplMethod {
                implementor: &input.self_ty,
                trait_name: input.trait_.as_ref().map(|(_, it, _)| it)
            },
        );
        let wrapped_func_call = func_wrap(
            &mut method.sig,
            ::core::mem::replace(&mut method.block, parse_quote!( {} )),
            Some(outer_scope),
        ).unwrap();
        method.block = parse_quote!(
            { #wrapped_func_call }
        );
        input.into_token_stream()
    }

    #[test]
    fn inherent ()
    {
        let input = ts! {
            impl<T> Foo<T>
            where
                () : Copy,
            {
                fn foo (self: Self, second: (), arg_0: (), (x, ): (i32, ))
                {
                    println!("foo")
                }
            }
        };
        assert_token_stream_eq(proc_macro(input), ts! {
            impl<T> Foo<T>
            where
                () : Copy,
            {
                fn foo (self: Self, second: (), arg_2: (), arg_3: (i32, ))
                {
                    ({
                        trait __FuncWrap<T>
                        where
                            () : Copy,
                        {
                            fn foo (self: Self, _: (), _: (), _: (i32, ))
                            ;
                        }

                        impl<T> __FuncWrap<T>
                            for Foo<T>
                        where
                            () : Copy,
                        {
                            #[inline(always)]
                            fn foo (self: Self, second: (), arg_0: (), (x, ): (i32, ))
                            {
                                println!("foo")
                            }
                        }

                        <Self as __FuncWrap<T>>::foo ::<>
                    })(self, second, arg_2, arg_3)
                }
            }
        });
    }

    #[test]
    fn trait_for ()
    {
        let input = ts! {
            impl<T, U> Trait<U> for Foo<T>
            where
                () : Copy,
            {
                fn foo (self, second: (), arg_0: (), (x, ): (i32, ))
                {
                    println!("foo")
                }
            }
        };
        assert_token_stream_eq(proc_macro(input), ts! {
            impl<T, U> Trait<U> for Foo<T>
            where
                () : Copy,
            {
                fn foo (self, second: (), arg_2: (), arg_3: (i32, ))
                {
                    ({
                        trait __FuncWrap<T, U> : Trait<U>
                        where
                            () : Copy,
                        {
                            fn foo (self, _: (), _: (), _: (i32, ))
                            ;
                        }

                        impl<T, U> __FuncWrap<T, U>
                            for Foo<T>
                        where
                            () : Copy,
                        {
                            #[inline(always)]
                            fn foo (self, second: (), arg_0: (), (x, ): (i32, ))
                            {
                                println!("foo")
                            }
                        }

                        <Self as __FuncWrap<T, U>>::foo ::<>
                    })(self, second, arg_2, arg_3)
                }
            }
        });
    }
}