Struct syn::meta::ParseNestedMeta

source ·
#[non_exhaustive]
pub struct ParseNestedMeta<'a> { pub path: Path, pub input: ParseStream<'a>, }
Expand description

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

§Examples

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

  • Attribute::parse_nested_meta if you have an entire Attribute to parse. Always use this if possible. Generally this is able to produce better error messages because Attribute holds span information for all of the delimiters therein.

  • syn::meta::parser if you are implementing a proc_macro_attribute macro and parsing the arguments to the attribute macro, i.e. the ones written in the same attribute that dispatched the macro invocation. Rustc does not pass span information for the surrounding delimiters into the attribute macro invocation in this situation, so error messages might be less precise.

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§path: Path§input: ParseStream<'a>

Implementations§

source§

impl<'a> ParseNestedMeta<'a>

source

pub fn value(&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"))
        }
    })?;
}
source

pub fn parse_nested_meta( &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"))
        }
    })?;
}
§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"))
        }
    })?;
}
source

pub fn error(&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:

attr.parse_nested_meta(|meta| {
    if meta.path.is_ident("kind") {
        // ...
        Ok(())
    } else {
        Err(meta.error("unsupported tea property"))
    }
})?;

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::Expr;

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

})?;
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:

    match expr {
        Expr::Lit(expr) => /* ... */
        Expr::Path(expr) => /* ... */
        Expr::Macro(expr) => /* ... */
        _ => 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 })]
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^

Auto Trait Implementations§

§

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>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

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

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

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

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

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

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

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

Performs the conversion.