Is proc_macro_attribute only working on functions?

I had something like this:

// in derive crate
#[proc_macro_attribute]
pub fn iter_object(arg: TokenStream, input: TokenStream) -> TokenStream {
    let arg = parse_macro_input!(arg as Ident);

    let ast = parse_macro_input!(input as DeriveInput);
    impl_iter_object_macro(&ast)
}

fn impl_iter_object_macro(ast: &DeriveInput) -> TokenStream {
    let name = &ast.ident;
    let gen = quote! {
       impl iter_object::IterObject for #name {
           fn to_params(&self) -> Vec<()> {
                vec![]
           }
       }
    };
    gen.into()
}

// in main crate
mod bar {}

#[iter_object(bar)]
struct Foo {
    str: Option<String>,
    n: Option<i32>,
}

It returns error cannot find type Foo in this scope, which is confusing, what I want to do is flatten the fields of the struct, if the field contains a value, map a function on it(self defined module), then collect them in a Vec, I have looked synstructure crate but it seems to be outdated and lacks of example.

Proc macro attributes replace their input with their output. If you want the original item to be included in the output, you need to do so explicitly.

Note that, since you're parsing the structure into DeriveInput, you might want to create a derive macro and not an attribute macro. Derive macros append their output to input, not replace them, and they can get additional input (like the argument to attribute macro) by placing an additional attribute on the struct to be consumed by derive.

2 Likes

Oh okay, I'll try it.

Actually I want to create attribute macro, the code was based on a derive macro then I edited it, is there any good introduction on rust attribute macros?

I wonder if there is a way, that macro can get function type by its name?

fn hello(s: String) {}
my_macro!(hello)

macro_rules! my_macro{
    () => {
        // somehow I got the whole hello fn type info here, ident is hello, args is String...etc.
    };
}

No, there isn't. Macros run before any type checking is done.

ah then I guess I can't finish my macro, thanks for all help.

Why don't you invoke the macro on the whole function? You could as well do

my_macro! {
    fn hello(s: String) {
    }
}

You can then match its parameters and return type.

Because the function is generated by a third party library, which is out of my control.