Struct ParseNestedMeta

struct ParseNestedMeta<'a> { ... }

Context for parsing a single property in the conventional syntax for structured attributes.

Examples

Refer to usage examples on the following two entry-points:

Fields

path: crate::path::Path
input: crate::parse::ParseStream<'a>

Implementations

impl<'a> ParseNestedMeta<'a>

fn value(self: &Self) -> Result<ParseStream<'a>>

Used when parsing key = "value" syntax.

All it does is advance meta.input past the = sign in the input. You could accomplish the same effect by writing meta.parse::<Token![=]>()?, so at most it is a minor convenience to use meta.value()?.

Example

use syn::{parse_quote, Attribute, LitStr};

let attr: Attribute = parse_quote! {
    #[tea(kind = "EarlGrey")]
};
                                         // conceptually:
if attr.path().is_ident("tea") {         // this parses the `tea`
    attr.parse_nested_meta(|meta| {      // this parses the `(`
        if meta.path.is_ident("kind") {  // this parses the `kind`
            let value = meta.value()?;   // this parses the `=`
            let s: LitStr = value.parse()?;  // this parses `"EarlGrey"`
            if s.value() == "EarlGrey" {
                // ...
            }
            Ok(())
        } else {
            Err(meta.error("unsupported attribute"))
        }
    })?;
}
# anyhow::Ok(())
fn parse_nested_meta<impl FnMut(ParseNestedMeta) -> Result<()>: FnMut(ParseNestedMeta<'_>) -> Result<()>>(self: &Self, logic: impl FnMut(ParseNestedMeta<'_>) -> Result<()>) -> Result<()>

Used when parsing list(...) syntax if the content inside the nested parentheses is also expected to conform to Rust's structured attribute convention.

Example

use syn::{parse_quote, Attribute};

let attr: Attribute = parse_quote! {
    #[tea(with(sugar, milk))]
};

if attr.path().is_ident("tea") {
    attr.parse_nested_meta(|meta| {
        if meta.path.is_ident("with") {
            meta.parse_nested_meta(|meta| {  // <---
                if meta.path.is_ident("sugar") {
                    // Here we can go even deeper if needed.
                    Ok(())
                } else if meta.path.is_ident("milk") {
                    Ok(())
                } else {
                    Err(meta.error("unsupported ingredient"))
                }
            })
        } else {
            Err(meta.error("unsupported tea property"))
        }
    })?;
}
# anyhow::Ok(())

Counterexample

If you don't need parse_nested_meta's help in parsing the content written within the nested parentheses, keep in mind that you can always just parse it yourself from the exposed ParseStream. Rust syntax permits arbitrary tokens within those parentheses so for the crazier stuff, parse_nested_meta is not what you want.

use syn::{parenthesized, parse_quote, Attribute, LitInt};

let attr: Attribute = parse_quote! {
    #[repr(align(32))]
};

let mut align: Option<LitInt> = None;
if attr.path().is_ident("repr") {
    attr.parse_nested_meta(|meta| {
        if meta.path.is_ident("align") {
            let content;
            parenthesized!(content in meta.input);
            align = Some(content.parse()?);
            Ok(())
        } else {
            Err(meta.error("unsupported repr"))
        }
    })?;
}
# anyhow::Ok(())
fn error<impl Display: Display>(self: &Self, msg: impl Display) -> Error

Report that the attribute's content did not conform to expectations.

The span of the resulting error will cover meta.path and everything that has been parsed so far since it.

There are 2 ways you might call this. First, if meta.path is not something you recognize:

# use syn::Attribute;
#
# fn example(attr: &Attribute) -> syn::Result<()> {
attr.parse_nested_meta(|meta| {
    if meta.path.is_ident("kind") {
        // ...
        Ok(())
    } else {
        Err(meta.error("unsupported tea property"))
    }
})?;
# Ok(())
# }

In this case, it behaves exactly like syn::Error::new_spanned(&meta.path, "message...").

error: unsupported tea property
 --> src/main.rs:3:26
  |
3 | #[tea(kind = "EarlGrey", wat = "foo")]
  |                          ^^^

More usefully, the second place is if you've already parsed a value but have decided not to accept the value:

# use syn::Attribute;
#
# fn example(attr: &Attribute) -> syn::Result<()> {
use syn::Expr;

attr.parse_nested_meta(|meta| {
    if meta.path.is_ident("kind") {
        let expr: Expr = meta.value()?.parse()?;
        match expr {
            Expr::Lit(expr) => /* ... */
#               unimplemented!(),
            Expr::Path(expr) => /* ... */
#               unimplemented!(),
            Expr::Macro(expr) => /* ... */
#               unimplemented!(),
            _ => Err(meta.error("tea kind must be a string literal, path, or macro")),
        }
    } else /* as above */
#       { unimplemented!() }

})?;
# Ok(())
# }
error: tea kind must be a string literal, path, or macro
 --> src/main.rs:3:7
  |
3 | #[tea(kind = async { replicator.await })]
  |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Often you may want to use syn::Error::new_spanned even in this situation. In the above code, that would be:

# use syn::{Error, Expr};
#
# fn example(expr: Expr) -> syn::Result<()> {
    match expr {
        Expr::Lit(expr) => /* ... */
#           unimplemented!(),
        Expr::Path(expr) => /* ... */
#           unimplemented!(),
        Expr::Macro(expr) => /* ... */
#           unimplemented!(),
        _ => Err(Error::new_spanned(expr, "unsupported expression type for `kind`")),
    }
# }
error: unsupported expression type for `kind`
 --> src/main.rs:3:14
  |
3 | #[tea(kind = async { replicator.await })]
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^

impl<'a> Freeze for ParseNestedMeta<'a>

impl<'a> RefUnwindSafe for ParseNestedMeta<'a>

impl<'a> Send for ParseNestedMeta<'a>

impl<'a> Sync for ParseNestedMeta<'a>

impl<'a> Unpin for ParseNestedMeta<'a>

impl<'a> UnwindSafe for ParseNestedMeta<'a>

impl<T> Any for ParseNestedMeta<'a>

fn type_id(self: &Self) -> TypeId

impl<T> Borrow for ParseNestedMeta<'a>

fn borrow(self: &Self) -> &T

impl<T> BorrowMut for ParseNestedMeta<'a>

fn borrow_mut(self: &mut Self) -> &mut T

impl<T> From for ParseNestedMeta<'a>

fn from(t: T) -> T

Returns the argument unchanged.

impl<T, U> Into for ParseNestedMeta<'a>

fn into(self: Self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

impl<T, U> TryFrom for ParseNestedMeta<'a>

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

impl<T, U> TryInto for ParseNestedMeta<'a>

fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>