Skip to content

Commit

Permalink
add documentation for enum parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
sharnoff committed Dec 8, 2020
1 parent 3834937 commit 5fa14ec
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 27 deletions.
73 changes: 57 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ struct CustomParsable {
```

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](#enum-parsing).

This crate is intended for users who are already making heavy use of `syn`.

Expand Down Expand Up @@ -62,7 +64,7 @@ impl Parse for MyField {
}
}
```
This is really repetetive! Ideally, we'd like to just `#[derive(Parse)]` and have it work. And
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`:
```rust
Expand All @@ -77,15 +79,59 @@ struct MyField {
}
```

Of course, there are more complicated cases. This is mainly covered immediately below in the
'Advanced usage' section.
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:
```rust
if input.peek($TYPE) {
// parse variant
} else {
// parse other variants
}
```
and
```rust
if ($EXPR)(input) {
// parse variant
} else {
// parse other variants
}
```
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.
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
Expand All @@ -99,6 +145,8 @@ it here!)
- [`#[inside]`](#inside)
- [`#[call]`](#call)
- [`#[parse_terminated]`](#parse_terminated)
- [`#[peek]`](#enum-parsing)
- [`#[peek_with]`](#enum-parsing)

### `#[paren]` / `#[bracket]` / `#[brace]`

Expand Down Expand Up @@ -168,7 +216,7 @@ impl Parse for KnownLengthArrayType {
fn parse(input: ParseStream) -> syn::Result<Self> {
let bracket;
Ok(KnownLengthArrayType {
bracket_token: syn::braced!(bracket in input),
bracket_token: syn::bracketed!(bracket in input),
ty: bracket.parse()?,
semi_token: bracket.parse()?,
expr: bracket.parse()?,
Expand Down Expand Up @@ -238,7 +286,7 @@ struct TupleStruct {
produces
```rust
impl Parse for TupleStruct {
fn parse(input: ParseStream) -> Result<Self> {
fn parse(input: ParseStream) -> syn::Result<Self> {
let content;
Ok(TupleStruct {
struct_token: input.parse()?,
Expand All @@ -251,10 +299,3 @@ impl Parse for TupleStruct {
}

```

## Known limitations

The derive macro is only available for structs. While actually possible, it's currently
considered outside of the scope of this crate to generate implementations of `Parse` for enums.
This is because they will always require some kind of lookahead (either via
`ParseStream::peek` or `ParseStream::fork`).
62 changes: 51 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
//! ```
//!
//! 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](#enum-parsing).
//!
//! This crate is intended for users who are already making heavy use of `syn`.
//!
Expand Down Expand Up @@ -56,7 +58,7 @@
//! }
//! }
//! ```
//! This is really repetetive! Ideally, we'd like to just `#[derive(Parse)]` and have it work. And
//! 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`:
//! ```
Expand All @@ -71,8 +73,52 @@
//! }
//! ```
//!
//! Of course, there are more complicated cases. This is mainly covered immediately below in the
//! 'Advanced usage' section.
//! 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:
//!
//! ```text
//! #[peek($TYPE, name = $NAME)]
//! ```
//! and
//! ```text
//! #[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:
//! ```ignore
//! if input.peek($TYPE) {
//! // parse variant
//! } else {
//! // parse other variants
//! }
//! ```
//! and
//! ```ignore
//! if ($EXPR)(input) {
//! // parse variant
//! } else {
//! // parse other variants
//! }
//! ```
//! respectively. If no variant matches, we produce an error message, using the names that were
//! provided for each type.
//!
//! ## Advanced usage
//!
Expand All @@ -93,7 +139,8 @@
//! - [`#[inside]`](#inside)
//! - [`#[call]`](#call)
//! - [`#[parse_terminated]`](#parse_terminated)
//! - [`#[no_parse_bound]`](#no_parse_bound)
//! - [`#[peek]`](#enum-parsing)
//! - [`#[peek_with]`](#enum-parsing)
//!
//! ### `#[paren]` / `#[bracket]` / `#[brace]`
//!
Expand Down Expand Up @@ -276,13 +323,6 @@
//!
//! [`Punctuated`]: syn::punctuated::Punctuated
//!
//! ## Known limitations
//!
//! The derive macro is only available for structs. While actually possible, it's currently
//! considered outside of the scope of this crate to generate implementations of `Parse` for enums.
//! This is because they will always require some kind of lookahead (either via
//! [`ParseStream::peek`] or [`ParseStream::fork`]).
//!
//! [`ParseStream::call`]: syn::parse::ParseBuffer::call
//! [`ParseStream::parse_terminated`]: syn::parse::ParseBuffer::parse_terminated
//! [`ParseStream::peek`]: syn::parse::ParseBuffer::peek
Expand Down

0 comments on commit 5fa14ec

Please sign in to comment.