Derive Macro structmeta::Parse[][src]

#[derive(Parse)]
{
    // Attributes available to this derive:
    #[to_tokens]
    #[parse]
}

Derive syn::parse::Parse for syntax tree node.

Example

#[derive(Parse)] generates an implementation of Parse that calls Parse::parse for each field.

use syn::{LitInt, LitStr};

#[derive(structmeta::Parse)]
struct Example(LitInt, LitStr);

Code like this will be generated:

impl syn::parse::Parse for Example {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let _0 = input.parse()?;
        let _1 = input.parse()?;
        return Ok(Example(_0, _1));
    }
}

#[derive(Parse)] can also be specified for enum.

use syn::{LitInt, LitStr};

#[derive(structmeta::Parse)]
enum Example {
    A(LitInt, LitInt),
    B(LitStr),
}

Code like this will be generated:

use syn::parse::discouraged::Speculative;
impl syn::parse::Parse for Example {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let fork = input.fork();
        if let Ok(value) = fork.call(|input| Ok(Example::A(input.parse()?, input.parse()?))) {
            input.advance_to(&fork);
            return Ok(value);
        }

        let fork = input.fork();
        if let Ok(value) = fork.call(|input| Ok(Example::B(input.parse()?))) {
            input.advance_to(&fork);
            return Ok(value);
        }

        Err(input.error("parse failed."))
    }
}

Helper attributes

structenumvaraintfield
#[to_tokens("[")], #[to_tokens("]")]
#[to_tokens("(")], #[to_tokens(")")]
#[to_tokens("{")], #[to_tokens("}")]
#[parse(peek)]
#[parse(any)]
#[parse(terminated)]
#[parse(dump)]

#[to_tokens("[")], #[to_tokens("]")]

By specifying #[to_tokens("[")] for a field of type syn::token::Bracket, subsequent tokens will be enclosed in [].

By default, all subsequent fields are enclosed. To restrict the enclosing fields, specify #[to_tokens("]")] for the field after the end of the enclosure.

use syn::{token, LitInt};

#[derive(structmeta::Parse)]
struct Example {
    x: LitInt,
    #[to_tokens("[")]
    bracket_token: token::Bracket,
    y: LitInt,
    #[to_tokens("]")]
    z: LitInt,
}

Code like this will be generated:

impl syn::parse::Parse for Example {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let x = input.parse()?;
        let content;
        let bracket_token = syn::bracketed!(content in input);
        let y = content.parse()?;
        let z = input.parse()?;
        Ok(Self {
            x,
            bracket_token,
            y,
            z,
        })
    }
}

#[to_tokens("(")], #[to_tokens(")")]

By specifying #[to_tokens("(")] for a field of type syn::token::Paren, subsequent tokens will be enclosed in ().

By default, all subsequent fields are enclosed. To restrict the enclosing fields, specify #[to_tokens(")")] for the field after the end of the enclosure.

#[to_tokens("{")], #[to_tokens("}")]

By specifying #[to_tokens("{")] for a field of type syn::token::Brace, subsequent tokens will be enclosed in {}.

By default, all subsequent fields are enclosed. To restrict the enclosing fields, specify #[to_tokens("}")] for the field after the end of the enclosure.

#[parse(peek)]

When parsing an enum, it will peek the field with this attribute set, and if successful, will parse the variant containing the field. If the peek succeeds, the subsequent variant will not be parsed even if the parse failed.

Variant where #[parse(peek)] is not specified will fork input and parse.

If the peek fails or the parsing of the forked input fails, the subsequent variant will be parsed.

use syn::{LitInt, LitStr};
#[derive(structmeta::Parse)]
enum Example {
    A(#[parse(peek)] LitInt, LitInt),
    B(LitStr),
}

Code like this will be generated:

impl syn::parse::Parse for Example {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        if input.peek(LitInt) {
            let a_0 = input.parse()?;
            let a_1 = input.parse()?;
            return Ok(Example::A(a_0, a_1));
        }
        let b_0 = input.parse()?;
        Ok(Example::B(b_0))
    }
}

#[parse(peek)] can be specified on the first three TokenTree for each variant.

use syn::{LitInt, LitStr};
#[derive(structmeta::Parse)]
enum Example {
    A(#[parse(peek)] LitInt, #[parse(peek)]LitInt, #[parse(peek)]LitInt),
    B(#[parse(peek)] LitStr),
}

Since the tokens enclosed by the delimiter is treated as a single token tree, you can also specify #[parse(peek)] to the field with #[to_tokens("]")], #[to_tokens("}")], #[to_tokens(")")].

use syn::{token, LitInt, LitStr};
#[derive(structmeta::Parse)]
enum Example {
    A {
        #[parse(peek)]
        #[to_tokens("{")]
        a: token::Brace,
        b: LitInt,
        c: LitInt,
        #[to_tokens("}")]
        #[parse(peek)]
        d: LitInt,
    },
}

To use #[parse(peek)] for a field that type is Ident, use syn::Ident insted of proc_macro2::Ident.

#[derive(structmeta::Parse)]
enum ExampleNg {
    A(#[parse(peek)] proc_macro2::Ident),
}
#[derive(structmeta::Parse)]
enum ExampleOk {
    A(#[parse(peek)] syn::Ident),
}

#[parse(any)]

When parsing Ident, allow values that cannot be used as identifiers, such as keywords.

In other words, Ident::parse_any and Ident::peek_any was generated instead of Ident::parse and Ident::peek.

use quote::quote;
use structmeta::Parse;
use syn::{parse2, Ident};

#[derive(Parse)]
struct WithAny(#[parse(any)] Ident);

#[derive(Parse)]
struct WithoutAny(Ident);

assert_eq!(parse2::<WithAny>(quote!(self)).is_ok(), true);
assert_eq!(parse2::<WithoutAny>(quote!(self)).is_ok(), false);

#[parse(terminated)]

Use Punctuated::parse_terminated to parse.

use quote::quote;
use structmeta::Parse;
use syn::{parse2, punctuated::Punctuated, Ident, Token};
#[derive(Parse)]
struct Example(#[parse(terminated)] Punctuated<Ident, Token![,]>);
assert_eq!(parse2::<Example>(quote!(a, b, c)).is_ok(), true);

terminated can also be used with any.

use quote::quote;
use structmeta::Parse;
use syn::{parse2, punctuated::Punctuated, Ident, Token};

#[derive(Parse)]
struct WithAny(#[parse(terminated, any)] Punctuated<Ident, Token![,]>);

#[derive(Parse)]
struct WithoutAny(#[parse(terminated)] Punctuated<Ident, Token![,]>);

assert_eq!(parse2::<WithAny>(quote!(self, self)).is_ok(), true);
assert_eq!(parse2::<WithoutAny>(quote!(self, self)).is_ok(), false);

#[parse(dump)]

Causes a compile error and outputs the code generated by #[derive(Parse)] as an error message.