Need help with parsing proc-macro attribute value (list)

Hi folks,

I need a help with parsing attribute values. Currently it is how my struct looks like:

#[derive(Segment)]
struct Test {
    a: u8,
    b: u8,
    #[depends_on(a, b)]
    c: u8,
    #[depends_on(a, b, c)]
    d: u8,
    e: u8,
    f: u8,
}

what I can do for now is to get fields with depends_on attr, but it is not clear how to get values of each depends_on.

I implemented small repo for reproduce what I did already: reproduce-proc-macro2/src/macro at main · sergio-ivanuzzo/reproduce-proc-macro2 · GitHub.

I tried to use:

let args = attr.parse_args::<ExprArray>().ok();

but because of lack of examples it is not clear what to do next.

Could somebody please help me to get attribute values ? This should be list of fields (idents)

P.S. just in case I post the code of proc-macro also here:

#[proc_macro_derive(Segment, attributes(depends_on))]
pub fn derive_segment(input: TokenStream) -> TokenStream {
    let ItemStruct { ident, fields, .. } = parse_macro_input!(input);
    let binary_converter = quote! { BinaryConverter };
    let cursor = quote! { std::io::Cursor };

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

    let field_values = fields.iter().map(|f| {
        let field_name = f.ident.as_ref().unwrap();
        quote! { self.#field_name }
    }).collect::<Vec<_>>();

    let mut depends_on = vec![];

    for field in fields.iter() {
        let ident = field.ident.as_ref().unwrap().to_string();

        if field.attrs.iter().any(|attr| attr.path().is_ident("depends_on")) {
            depends_on.push(Some(ident));
        }
    }

    let initializers = fields.iter().map(|f| {
        quote! { #binary_converter::read_from(&mut reader, vec![]).unwrap() }
    });

    let output = quote! {
        impl #ident {
            pub fn from_binary(data: Vec<u8>) -> Self {
                let mut reader = #cursor::new(data);

                let mut instance = Self {
                    #(#field_names: #initializers),*
                };

                instance
            }

            pub fn test(&mut self) {
                println!("{:?}", vec![#(&#depends_on),*]);
            }
        }
    };

    TokenStream::from(output)
}

I did it:

struct MyAttr {
    pub name: Ident,
}

impl Parse for MyAttr {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let name: Ident = input.parse()?;

        Ok(Self { name })
    }
}

for field in fields.iter() {
        let ident = field.ident.as_ref().unwrap().to_string();

        if field.attrs.iter().any(|attr| attr.path().is_ident("depends_on")) {

            field.attrs.iter().for_each(|attr| {
                for a in attr.parse_args_with(Punctuated::<MyAttr, Token![,]>::parse_terminated).unwrap() {
                    attributes.push(a.name.to_string());
                }
            });

            depends_on.push(Some(ident));
        }
    }

Just use deluxe.

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.