serde_tokenstream
This Rust crate is intended for use with macros that need bespoke configuration.
It's implemented as a serde::Deserializer
that operates on a
proc_macro2::TokenSteam
(easily converted from the standard
proc_macro::TokenStream
).
Say we're building a custom proc macro that you want consumers to use like this:
```rust
name = "SNPP",
owner = "Canary M Burns",
details = {
kind = Fission,
year_of_opening = 1968,
}
}] fn some_func() { ... } ```
The function that implements the proc macro must have two parameters (both of
type proc_macro::TokenStream
): attributes (the tokens with the braces that
follow the name of the macro), and the item (the function, type, etc. to
which the macro is applied):
```rust
pub fn MyMacro( attr: procmacro::TokenStream, item: procmacro::TokenStream, ) -> proc_macro::TokenStream { ... } ```
We'll first define the struct
type that represents the configuration and
derive
a serde::Deserialize
:
```rust
struct Config { name: String, owner: String, details: ConfigDetails, }
struct ConfigDetails { kind: ConfigDetailsType, yearofopening: usize, }
enum ConfigDetailsType { Coal, Fission, Hydroelectric, } ```
Now we can parse attr
into the Config
struct with serde_tokenstream::from_tokenstream
:
```rust use procmacro2::TokenStream; use serdetokenstream::from_tokenstream;
pub fn MyMacro(
attr: procmacro::TokenStream,
item: procmacro::TokenStream,
) -> procmacro::TokenStream {
let config = match fromtokenstream::
...
} ```
See the serde
documentation for the full range of controls that can be
applied to types and their members.
Note that errors will highlight the problematic portion of consuming code:
```rust
name = "Rocinante",
owner = "Rocicorp",
details = {
kind = Fusion,
year_of_opening = 2347
}
}] fn deploy() { ... } ```
error: unknown variant `Fusion`, expected one of `Coal`, `Fission`, `Hydroelectric`
--> tests/test_err1.rs:7:16
|
7 | kind = Fusion,
| ^^^^^^