derive_syn_parse/
lib.rs

1//! Derive macro for [`syn::parse::Parse`]
2//!
3//! A common pattern when writing custom `syn` parsers is repeating `<name>: input.parse()?` for
4//! each field in the output. `#[derive(Parse)]` handles that for you, with some extra helpful
5//! customization.
6//!
7//! ## Usage
8//!
9//! Using this crate is as simple as adding it to your 'Cargo.toml' and importing the derive macro:
10//!
11//! ```toml
12//! # Cargo.toml
13//!
14//! [dependencies]
15//! derive-syn-parse = "0.2.0"
16//! ```
17//!
18//! ```
19//! // your_file.rs
20//! use derive_syn_parse::Parse;
21//!
22//! #[derive(Parse)]
23//! struct CustomParsable {
24//!     // ...
25//! }
26//! ```
27//!
28//! The derived implementation of `Parse` always parses in the order that the fields are given.
29//! **Note that deriving `Parse` is also available on enums.** For more information, see the
30//! [dedicated section](#enum-parsing).
31//!
32//! This crate is intended for users who are already making heavy use of `syn`.
33//!
34//! ## Motivation
35//!
36//! When writing rust code that makes heavy use of `syn`'s parsing functionality, we often end up
37//! writing things like:
38//! ```
39//! use syn::parse::{Parse, ParseStream};
40//! use syn::{Ident, Token, Type};
41//!
42//! // A simplified struct field
43//! //
44//! //     x: i32
45//! struct MyField {
46//!     ident: Ident,
47//!     colon_token: Token![:],
48//!     ty: Type,
49//! }
50//!
51//! impl Parse for MyField {
52//!     fn parse(input: ParseStream) -> syn::Result<Self> {
53//!         Ok(MyField {
54//!             ident: input.parse()?,
55//!             colon_token: input.parse()?,
56//!             ty: input.parse()?,
57//!         })
58//!     }
59//! }
60//! ```
61//! This is really repetitive! Ideally, we'd like to just `#[derive(Parse)]` and have it work. And
62//! so we can! (for the most part) Adding `#[derive(Parse)]` to the previous struct produces an
63//! equivalent implementation of `Parse`:
64//! ```
65//! use syn::{Ident, Token, Type};
66//! use derive_syn_parse::Parse;
67//!
68//! #[derive(Parse)]
69//! struct MyField {
70//!     ident: Ident,
71//!     colon_token: Token![:],
72//!     ty: Type,
73//! }
74//! ```
75//!
76//! Of course, there are more complicated cases. This is mainly covered below in the 'Advanced
77//! Usage' section.
78//!
79//! ## Advanced Usage
80//!
81//! There are a few different facilities provided here, including:
82//! * Enum variant parsing,
83//! * Conditional field parsing,
84//! * Parsing within token trees (parens, brackets, etc.),
85//! * And much more!
86//!
87//! Each of the below sections can be expanded to view detailed information about how to use a
88//! particular component. Be warned - each section assumes a fair amount of knowledge about the relevant
89//! `syn` features.
90//
91//
92// ---------- SECTION: Enum Parsing ----------
93//
94//! <details><summary><b>Enum parsing</b></summary>
95//!
96//! Parsing enums is a complex feature. When writing manual implementations of
97//! `Parse`, it doesn't come up as often, but there are also typically *many* ways to do it:
98//! `syn` provides both forking the `ParseBuffer` *and* peeking to handle this, with the suggestion that
99//! peeking be preferred.
100//!
101//! This library does not support forking; it tends to suffer from poor error messages and general
102//! inefficiency. That being said, manual implementations of `Parse` can and should be written in the
103//! rare cases when this library is insufficient.
104//!
105//! We support peeking in a couple differnet ways - with the `#[peek]` and `#[peek_with]` attributes.
106//! One peeking attribute is required for each `enum` variant. The general syntax tends to look like:
107//!
108//! ```text
109//! #[peek($TYPE, name = $NAME)]
110//! ```
111//! and
112//! ```text
113//! #[peek_with($EXPR, name = $NAME)]
114//! ```
115//! The name is provided in order to construct useful error messages when input doesn't match any of the
116//! variants.
117//!
118//! These essentially translate to:
119//! ```
120//! if input.peek($TYPE) {
121//!     // parse variant
122//! } else {
123//!     // parse other variants
124//! }
125//! ```
126//! and
127//! ```
128//! if ($EXPR)(input) {
129//!     // parse variant
130//! } else {
131//!     // parse other variants
132//! }
133//! ```
134//! </details>
135//
136//
137// ---------- SECTION: Token Trees ----------
138//
139//! <details><summary><b>Token Trees (parens, brackets, braces)</b></summary>
140//!
141//! If derive macros had access to type information, we could auto-detect when a field contains any
142//! of `syn::token::{Paren, Bracket, Brace}`. Unfortunately, we can't - and these don't implement
143//! `Parse`, so they each have their own special attribute to mark them: `#[paren]`, `#[bracket]`,
144//! and `#[brace]`, respectively.
145//!
146//! These are typically used with the `#[inside]` attribute, which indicates that a field should be
147//! parsed inside a particular named token tree. This might look like:
148//!
149//! ```
150//! use derive_syn_parse::Parse;
151//! use syn::{Ident, token, Expr};
152//!
153//! // Parses a simple function call - something like
154//! //
155//! //   so_long(and_thanks + for_all * the_fish)
156//! #[derive(Parse)]
157//! struct SingleArgFn {
158//!     name: Ident,
159//!     #[paren]
160//!     arg_paren: token::Paren,
161//!     #[inside(arg_paren)]
162//!     arg: Expr,
163//! }
164//! ```
165//!
166//! The `#[inside]` attribute can - of course - be repeated with multiple token trees, though this
167//! may not necessarily produce the most readable type definitions.
168//!
169//! For reference, the above code produces an implementation equivalent to:
170//! ```
171//! # use syn::{Ident, token, Expr};
172//! # struct SingleArgFn { name: Ident, arg_paren: token::Paren, arg: Expr }
173//!
174//! use syn::parse::{Parse, ParseStream};
175//!
176//! impl Parse for SingleArgFn {
177//!     fn parse(input: ParseStream) -> syn::Result<Self> {
178//!         let paren;
179//!         Ok(SingleArgFn {
180//!             name: input.parse()?,
181//!             arg_paren: syn::parenthesized!(paren in input),
182//!             arg: paren.parse()?,
183//!         })
184//!     }
185//! }
186//! ```
187//!
188//! </details>
189//
190//
191// ---------- SECTION: Custom parsing (call, parse_terminated) ----------
192//
193//! <details><summary><b>Custom parse functions (<code>#[call]</code>, <code>#[parse_terminated]</code>)</b></summary>
194//!
195//! Not every type worth parsing implements `Parse`, but we still might want to parse them - things
196//! like [`Vec<Attribute>`] or any [`Punctuated<_, _>`] type. In these cases, the available
197//! attributes mirror the methods on [`ParseBuffer`].
198//!
199//! [`ParseBuffer`]: syn::parse::ParseBuffer
200//!
201//! For `#[parse_terminated]`, there aren't any parameters that can be specified - it's common
202//! enough that it's provided for those `Punctuated` fields.
203//!
204//! Alternatively, `#[call]` has the syntax `#[call( EXPR )]`, where `EXPR` is *any expression*
205//! implementing `FnOnce(ParseBuffer) -> syn::Result<T>`. Typically, this might be something like:
206//! ```
207//! use syn::{Attribute, Ident, Token};
208//!
209//! // Parses a unit struct with attributes.
210//! //
211//! //     #[derive(Copy, Clone)]
212//! //     struct S;
213//! #[derive(Parse)]
214//! struct UnitStruct {
215//!     #[call(Attribute::parse_outer)]
216//!     attrs: Vec<Attribute>,
217//!     struct_token: Token![struct],
218//!     name: Ident,
219//!     semi_token: Token![;],
220//! }
221//! ```
222//!
223//! Unlike with [`ParseBuffer::call`], which only accepts functions that are
224//! `fn(ParseStream) -> syn::Result<T>`, `#[call]` allows any expression that we can call with the
225//! `ParseBuffer`. So one could - hypothetically - implement `#[parse_if]` with this:
226//! ```
227//! struct Foo {
228//!     a: Option<Token![=>]>,
229//!     #[call(|inp| match &a { Some(_) => Ok(Some(inp.parse()?)), None => Ok(None) })]
230//!     b: Option<Bar>,
231//! }
232//! ```
233//! Though it's probably best to just use `#[parse_if]` :)
234//!
235//! [`Vec<Attribute>`]: syn::Attribute
236//! [`Punctuated<_, _>`]: syn::punctuated::Punctuated
237//! [`ParseBuffer::call`]: syn::parse::ParseBuffer
238//!
239//! </details>
240//
241//
242// ---------- SECTION: Conditional field parsing ----------
243//
244//! <details><summary><b>Conditional field parsing (<code>#[parse_if]</code>, <code>#[peek]</code>)</b></summary>
245//!
246//! When implementing `Parse` for structs, it is occasionally the case that certain fields are
247//! optional - or should only be parsed under certain circumstances. There are attributes for that!
248//!
249//! Say we want to parse enums with the following, different syntax:
250//!
251//! ```
252//! enum Foo {
253//!     Bar: Baz,
254//!     Qux,
255//! }
256//! ```
257//! where the equivalent Rust code would be:
258//!
259//! ```
260//! enum Foo {
261//!     Bar(Baz),
262//!     Qux,
263//! }
264//! ```
265//! There’s two ways we could parse the variants here – either with a colon and following type or
266//! with no colon or type. To handle this, we can write:
267//!
268//! ```
269//! #[derive(Parse)]
270//! struct Variant {
271//!     name: Ident,
272//!     // `syn` already supports optional parsing of simple tokens
273//!     colon: Option<Token![:]>,
274//!     // We only want to parse the trailing type if there's a colon:
275//!     #[parse_if(colon.is_some())]
276//!     ty: Option<Type>,
277//! }
278//! ```
279//! Note that in this case, `ty` must be an `Option`. In addition to conditional parsing based on
280//! the values of what’s already been parsed, we can also peek - just as described above in the
281//! section on parsing enums. The only difference here is that we do not need to provide a name for
282//! the optional field. We could have equally implemented the above as:
283//!
284//! ```
285//! #[derive(Parse)]
286//! struct Variant {
287//!     name: Ident,
288//!     #[peek(Token![:])]
289//!     ty: Option<VariantType>,
290//! }
291//!
292//! #[derive(Parse)]
293//! struct VariantType {
294//!     colon: Token![:],
295//!     ty: Type,
296//! }
297//! ```
298//!
299//! </details>
300//
301//
302// ---------- SECTION: Prefix & postfix ----------
303//
304//! <details> <summary><b>Temporary parses: Prefix & postfix </b></summary>
305//!
306//! A common pattern that sometimes occurs when deriving `Parse` implementations is to have many
307//! unused punctuation fields - imagine a hypothetical implementation of field parsing with default
308//! values:
309//!
310//! ```
311//! // A field with default values, parsing something like:
312//! //
313//! //   foo: Bar = Bar::new()
314//! #[derive(Parse)]
315//! struct Field {
316//!     ident: Ident,
317//!     colon: Token![:],
318//!     ty: Type,
319//!     eq: Option<Token![=]>,
320//!     #[parse_if(eq.is_some())]
321//!     expr: Option<Expr>,
322//! }
323//! ```
324//!
325//! Here, there's a couple fields that probably won't be used later - both `colon` and `eq`. We can
326//! elimitate both of these with the `#[prefix]` attribute:
327//!
328//! ```
329//! // A field with default values, parsing something like:
330//! //
331//! //   foo: Bar = Bar::new()
332//! #[derive(Parse)]
333//! struct Field {
334//!     ident: Ident,
335//!     #[prefix(Token![:])]
336//!     ty: Type,
337//!     #[prefix(Option<Token![=]> as eq)]
338//!     #[parse_if(eq.is_some())]
339//!     expr: Option<Expr>,
340//! }
341//! ```
342//!
343//! We can use `"as <Ident>"` to give a temporary name to the value - including it as a parsed
344//! value that can be referenced in other parsing clauses, but without adding it as a struct field.
345//!
346//! There's *also* a `#[postfix]` attribute, which operates very similarly to `#[prefix]`, but
347//! exists to allow unused fields at the end of the struct. In general, `#[postfix]` tends to be
348//! pretty tricky to read, so it's generally preferable to use `#[prefix]` to keep the field
349//! ordering the same as the parse order.
350//!
351//! In some cases, we might want to have both a field and its prefix parsed inside some other token
352//! tree. Like the following contrived example:
353//!
354//! ```
355//! use syn::*;
356//!
357//! // Parses.... something. Who knows if this is useful... :P
358//! //
359//! //   (=> x + 2)
360//! #[derive(Parse)]
361//! struct Funky {
362//!     #[paren]
363//!     paren: token::Paren,
364//!     #[inside(paren)]
365//!     r_arrow: Token![=>],
366//!     #[inside(paren)]
367//!     expr: Expr,
368//! }
369//! ```
370//!
371//! To remove the unused `r_arrow` field here, we have an other extra piece we can add:
372//! `"in" <Ident>"`.
373//!
374//! ```
375//! #[derive(Parse)]
376//! struct Funky {
377//!     #[paren]
378//!     paren: token::Paren,
379//!     #[prefix(Token![=>] in paren)]
380//!     #[inside(paren)]
381//!     expr: Expr,
382//! }
383//! ```
384//!
385//! Note that attempting to write the `#[inside]` before `#[prefix]` is forbidden; it's less clear
386//! what the expected behavior there should be.
387//!
388//! Finally, when combining both `"as" <ident>` and `"in" <ident>`, they should come in that
389//! order - e.g. `#[prefix(Foo as bar in baz)]`.
390//!
391//! </details>
392
393use proc_macro2::{Span, TokenStream};
394use quote::{quote, quote_spanned, ToTokens};
395use syn::spanned::Spanned;
396use syn::{parse_macro_input, Data, DeriveInput, Ident, Result};
397
398#[macro_use]
399mod error_macros;
400
401mod fields;
402#[cfg(test)]
403mod tests;
404mod variants;
405
406#[rustfmt::skip]
407#[proc_macro_derive(
408    Parse,
409    attributes(
410        paren, bracket, brace,
411        inside,
412        call, parse_terminated,
413        peek, peek_with,
414        parse_if,
415        prefix, postfix,
416    )
417)]
418pub fn derive_parse(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
419    let input = parse_macro_input!(item as DeriveInput);
420    derive_parse_internal(input).into()
421}
422
423// Pulled into a separate function so we can test it
424pub(crate) fn derive_parse_internal(input: DeriveInput) -> TokenStream {
425    // The generic parameters following `impl`
426    let mut generics_intro = TokenStream::new();
427    // The generic arguments following the name of the type
428    let mut generics_args = TokenStream::new();
429
430    let where_clause = input.generics.where_clause;
431
432    let generic_params: Vec<_> = input.generics.params.into_iter().collect();
433    if !generic_params.is_empty() {
434        let generics_intros: Vec<_> = handle_syn_result! {
435            generic_params.iter()
436                .map(require_impl_parse_if_type)
437                .collect()
438        };
439        generics_intro = quote!( < #( #generics_intros ),* > );
440        let generics_args_list: Vec<_> = generic_params.into_iter().map(convert_to_arg).collect();
441        generics_args = quote!( < #( #generics_args_list ),* > );
442    }
443
444    let ident = input.ident;
445
446    let parse_impl = match input.data {
447        Data::Union(u) => invalid_input_kind!(u.union_token),
448        Data::Struct(s) => handle_syn_result! {
449            @default_impl_from(generics_intro, ident, generics_args, where_clause),
450            fields::generate_fn_body(&ident, s.fields, false)
451        },
452        Data::Enum(e) => handle_syn_result! {
453            @default_impl_from(generics_intro, ident, generics_args, where_clause),
454            variants::generate_impl(e.variants.into_iter())
455        },
456    };
457
458    let parse_input = parse_input();
459    quote!(
460        impl #generics_intro ::syn::parse::Parse for #ident #generics_args #where_clause {
461            fn parse(#parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
462                #parse_impl
463            }
464        }
465    )
466}
467
468// Produces the tokens for the generic parameter, adding `+ syn::parse::Parse`
469fn require_impl_parse_if_type(param: &syn::GenericParam) -> Result<TokenStream> {
470    use syn::GenericParam::Type;
471    use syn::TypeParam;
472
473    let TypeParam {
474        attrs,
475        ident,
476        colon_token,
477        bounds,
478        eq_token,
479        default,
480    } = match param {
481        Type(t) => t,
482        param => return Ok(param.to_token_stream()),
483    };
484
485    // If we have `struct Foo<T>`,      we need to add `: Parse`, but
486    // if we have `struct Foo<T: Bar>`, we need to add `+ Parse`
487    let parse_bound = if colon_token.is_some() {
488        quote_spanned! {
489            ident.span()=>
490            + ::syn::parse::Parse
491        }
492    } else {
493        quote_spanned! {
494            ident.span()=>
495            : ::syn::parse::Parse
496        }
497    };
498
499    Ok(quote! {
500        #( #attrs )*
501        #ident #colon_token #bounds #parse_bound #eq_token #default
502    })
503}
504
505fn convert_to_arg(param: syn::GenericParam) -> TokenStream {
506    use syn::GenericParam::{Const, Lifetime, Type};
507
508    match param {
509        Type(ty) => ty.ident.to_token_stream(),
510        Lifetime(lifetime) => lifetime.to_token_stream(),
511        Const(con) => {
512            let ident = &con.ident;
513            quote_spanned!(con.span()=> { #ident })
514        }
515    }
516}
517
518// A helper macro to give the identifier used to represent the ParseStream used as input to the
519// macro
520fn parse_input() -> Ident {
521    Ident::new("__parse_input", Span::call_site())
522}