A derive macro for syn
's Parse
trait
This is a relatively simple derive macro that produces an implementation syn::parse::Parse
for the
type it's applied to.
A common pattern when writing custom syn
parsers is repeating <name>: input.parse()?
for
each field in the output. #[derive(Parse)]
handles that for you, with some extra helpful
customization.
Usage
Using this crate is as simple as adding it to your 'Cargo.toml' and importing the derive macro:
# Cargo.toml
[]
= "0.1"
// your_file.rs
use Parse;
The derived implementation of Parse
always parses in the order that the fields are given.
Note that deriving Parse
is also available on enums. For more information, see the
dedicated section.
This crate is intended for users who are already making heavy use of syn
.
Motivation
When writing rust code that makes heavy use of syn
's parsing functionality, we often end up
writing things like:
use ;
use ;
// A simplified struct field
//
// x: i32
This is really repetitive! Ideally, we'd like to just #[derive(Parse)]
and have it work. And
so we can! (for the most part) Adding #[derive(Parse)]
to the previous struct produces an
equivalent implementation of Parse
:
use ;
use Parse;
Of course, there are more complicated cases. This is mainly covered below in the 'Advanced usage' section.
Enum parsing
Parsing enum
s is a complex feature. When writing manual implementations of Parse
, it
doesn't come up as often, but there are also typically many ways to do it: syn
provides
both forking the ParseBuffer
and peeking in order to handle this, with peeking to be
preferred if possible.
This library does not support forking; it tends to suffer from poor error messages and general
inefficiency. That being said, manual implementations of Parse
can and should be written when
this library is insufficient.
We do support peeking - in two different ways. These are handled by the #[peek]
and
#[peek_with]
attributes, which are required on- and only available for enum
variants. The
general syntax can be thought of as:
#[peek($TYPE, name = $NAME)]
and
#[peek_with($EXPR, name = $NAME)]
where $TYPE
, $EXPR
, and $NAME
are meta-variables that correspond to the particular input
given to the attribute.
These can be thought of as translating literally to:
if input.peek else
and
if else
respectively. If no variant matches, we produce an error message, using the names that were provided for each type.
Advanced usage
There's a moderate collection of helper attributes that can be applied to fields to customize
the generated implementation of Parse
. Each of these are demonstrated with the
implementation that they produce. Please note that the produced implementation is typically
not identical to what's shown here.
All of the examples are fairly contrived, I know. The reality of the matter is that - if you would find this useful - it's probably true that your use-case is much more complicated than would make sense for a short example. (If it isn't, let me know! It would be great to include it here!)
List of helper attributes
#[paren]
/ #[bracket]
/ #[brace]
Because the derive macro has no fool-proof method for determining by itself whether a field type
is any of syn::token::{Paren, Bracket, Brace}
, these three serve to provide that information
instead.
These are typically used in conjunction with #[inside]
.
// A single-argument function call
//
// so_long(and_thanks + for_all * the_fish)
produces
#[inside(..)]
This is a companion to #[paren]
/#[bracket]
/#[brace]
- given a field name to use, this
attribute indicates that the field should be parsed using a previous field as the source.
use ;
use Bracket;
// An array type required to have a length
//
// [i32; 4]
produces
#[call(..)]
Given a path to a function, this attribute specifies that the value of the field should be
instead calculated by a call to input.parse(..)
with a given path. The best example is taken
straight from the syn
documentation itself:
use ;
// Parses a unit struct with attributes.
//
// #[path = "s.tmpl"]
// struct S;
produces
#[parse_terminated(..)]
Just as we have #[call(..)]
for ParseStream::call
, we have #[parse_terminated]
for ParseStream::parse_terminated
. Here's the same example that the ParseStream
method
uses:
// Parse a simplified tuple struct syntax like:
//
// struct S(A, B);
produces