parse_nested_meta iterates through nested metadata inside an attribute and passes each entry to a callback. In an attribute such as #[public(exclude(fourth, third))], the callback recognizes exclude, descends into its parentheses, and records each identifier. section 8.7
Parsing excluded fields
A syn version 2 parser can keep the state in a custom struct: impl AlternativeExcludedFields { fn parse(&mut self, meta: ParseNestedMeta) -> Result<(), syn::Error> { if meta.path.is_ident("exclude") { meta.parse_nested_meta(|meta| { let ident = &meta.path.segments.first().unwrap().ident; self.fields.push(ident.to_string()); Ok(()) }) } else { Err(meta.error("unsupported property")) } } } The outer callback validates the property name; the inner callback receives fourth and third and stores them. Unsupported properties produce a syn error. section 8.7
The operation is useful when an attribute parser must:
- Inspect one level of nested metadata without manually matching MetaList structures. section 8.7
- Delegate each nested entry to application-specific logic that updates parser state. section 8.7
- Reject unknown properties through meta.error while accepting empty attribute streams through the parser framework. section 8.7
- Handle metadata patterns used by established procedural macros, including serde-style options inside parentheses. section 8.9
Listing 8.39 Meta parser
#[derive(Default)]
struct AlternativeExcludedFields {
fields: Vec<String>,
}
impl AlternativeExcludedFields {
fn matches_ident(&self, name: &Option<Ident>) -> bool {
// same as ExcludedFields
}
}
impl AlternativeExcludedFields {
fn parse(&mut self, meta: ParseNestedMeta) -> Result<(), syn::Error> {
if meta.path.is_ident(EXCLUDE_ATTRIBUTE_NAME) {
meta.parse_nested_meta(|meta| {
let ident = &meta.path.segments.first().unwrap().ident;
self.fields.push(ident.to_string());
Ok(())
})
} else {
Err(meta.error("unsupported property"))
}
}
}
#[proc_macro_attribute]
pub fn public(attr: TokenStream, item: TokenStream) -> TokenStream {
let ast = parse_macro_input!(item as DeriveInput);
let mut excluded_fields = AlternativeExcludedFields::default();
let attr_parser = syn::meta::parser(|meta| excluded_fields.parse(meta));
parse_macro_input!(attr with attr_parser);
// everything else is the same
}
View the complete parser shape, including state storage, property validation, nested traversal, and error creation. section 8.7
