Crates.io | serde_syn |
lib.rs | serde_syn |
version | 0.1.0 |
source | src |
created_at | 2019-08-25 03:30:05.70624 |
updated_at | 2019-08-25 03:30:05.70624 |
description | Use serde to parse Rust source code. |
homepage | https://gitlab.com/samsartor/serde_syn |
repository | https://gitlab.com/samsartor/serde_syn |
max_upload_size | |
id | 159474 |
size | 68,140 |
serde_syn is a serde backend for parsing Rust syntax inside procedural macros. For example, you can deserialize parameters for a custom derive out of attributes and directly into structs. The goal is to eliminate the parsing boilerplate that goes into writing procedural macros.
The interface to serde_syn is fairly minimal. Here are a few ways to use it:
Parser
implementation to process syntax inside already parsed/visited
attributes.
The [parser
] function creates exactly that!proc_macro
/proc_macro2
token streams
or strings, you should also use [parser
].Parse
trait yourself, you should
use the [from_stream
] function which takes in a
ParseStream
.Lots of pre-made configurations exist inside the [config
] module for
common syntaxes (JSON-like, attribute-like, expression-like, etc) or you can
combine flags to build your own.
Here you can see a simple derive macro implementation. For more examples, see the examples directory.
#
#
/// The format of `named` attributes.
#[derive(Deserialize)]
struct Props {
rename: Option<String>, // #[named(rename="hello")]
lowercase: Option<()>, // #[named(lowercase)]
}
#[proc_macro_derive(NamedType, attributes(named))]
pub fn my_macro(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let mut name = input.ident.to_string();
for attr in input.attrs.iter().filter(|a| a.path.is_ident("named")) {
let parser = parser::<Props>(config::RUSTY_META);
let props = match attr.parse_args_with(parser) {
Ok(props) => props,
Err(err) => return err.to_compile_error().into(),
};
if let Some(rename) = props.rename { name = rename; }
if props.lowercase.is_some() { name = name.to_lowercase(); }
}
let ident = &input.ident;
(quote! {
impl NamedType for #ident {
fn name() -> &'static str { #name }
}
}).into()
}
Deserialization errors are automatically assigned a "span" (the area of the
source code that could not be parsed) before being returned from [parser
]
and [from_stream
] as ordinary
syn::Error
s. When that
error is reported to the Rust compiler, the correct regions of code will be
highlighted:
error: unknown field `lowrcase`, expected `rename` or `lowercase`
--> named_type.rs:4:13
|
4 | #[named(lowrcase)]
| ^^^^^^^^
If you use [Deserializer
] directly, serde_syn will do its best to assign a
span but it is always possible to create an error with no span using serde's
required custom
function.
serde_syn is early in development and so still has some gotchyas. For
example, serde_syn will throw an error if you try to deserialize into a
serde_json Value
since it doesn't yet support self-description.
If you find any bugs, have any ideas, or wind up with free time to help random open source projects, please drop by the repository.