Cannot pass variable from outer scope into proc macro attribute

In my proc macro I have options attribute and I want to use it to pass variables from outer scope into struct affected by macro:

#[derive(Packet, Debug)]
#[options(opcode=Opcode::SMSG_MESSAGECHAT)]
struct Test {
    #[dynamic_field]
    size: u8,
    #[dynamic_field]
    size1: u16,
    #[dynamic_field]
    size2: u8,
    #[dynamic_field]
    field2: u8,
    field3: String,
}

but as I can see, Opcode::SMSG_MESSAGECHAT not parsed as expression, it parsed as ident.

This is my proc macro code:

#[proc_macro_derive(Packet, attributes(options, dynamic_field))]
pub fn derive(input: TokenStream) -> TokenStream {
    let ItemStruct { ident, fields, attrs, .. } = parse_macro_input!(input);
    // ...

    let Cursor = quote!(std::io::Cursor);
    let BinaryConverter = quote!(crate::traits::BinaryConverter);

    let field_data = fields.iter().filter_map(|f| {
        let ident = f.ident.clone().unwrap().to_string();
        let field_type = f.ty.clone();
        let ident = format_ident!("{}", f.ident.as_ref().unwrap());

        if f.attrs.iter().any(|attr| attr.path.is_ident("dynamic_field")) {
            Some(quote! { Self::#ident(); })
        } else {
            None
        }
    }).collect::<Vec<_>>();

    let fields_names = fields.iter().map(|f| {
        f.ident.clone()
    }).collect::<Vec<_>>();

    let output = quote! {
        impl #ident {
            pub fn debug() {
                #(#field_data)*
            }

            pub fn from_binary(buffer: &Vec<u8>) -> Self {
                let mut reader = #Cursor::new(buffer);

                Self {
                    #(#fields_names: #BinaryConverter::read_from(&mut reader).unwrap()),*
                }
            }
        }
    };

    TokenStream::from(output)
}

Could somebody explain if it possible to let proc macro receive variables into attributes ?

No, it isn't. Macros are purely syntactic constructs. They are invoked and expanded way before even type checking starts, let alone any sort of value-level evaluation. There is no way a macro can know that foo::bar is an enum variant, or a type, or a function, or whatever.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.