Struct ParseNestedMeta

Source
#[non_exhaustive]
pub struct ParseNestedMeta<'a> { pub path: Path, pub input: &'a ParseBuffer<'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: &'a ParseBuffer<'a>

Implementations§

Source§

impl<'a> ParseNestedMeta<'a>

Source

pub fn value(&self) -> Result<&'a ParseBuffer<'a>, Error>

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<(), Error>, ) -> Result<(), Error>

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> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

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

Source§

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>,

Source§

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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,