syn
syn copied to clipboard
Should syn have convenience functions for (derive) macros?
There's a few things I often need while writing a derive macro, which I keep writing small helper functions for. I'm wondering if these should be part of syn, or if they should go in a separate crate.
An example:
I often want to iterate over the Members of a list of Fields, such that Unit results in an empty iterator, Tuple results in Unnamed(0), Unnamed(1), etc., and Struct results in Named("field1"), Named("field2") etc. This makes it easy to use e.g. quote!{ #structname { #( #member: Trait::thing(), )* } } and have it work for all three kinds of structs.
(Concrete use case example: It'd reduce this match to just a single case.)
This doesn't seem to exactly fit with the rest of syn, because the tuple indexes (0, 1, ..) don't occur in the source code, but are generated for the convenience of proc macros.
A second example:
An .expect_struct() on Data that would return a Result<DataStruct>, containing a nice error in case of an enum or union (with the span set to the enum or union token). (Or a .expect_unit() on Fields, etc.)
I have a few more examples like this. But I first wanted to ask the general question: Would syn be the right place for functions like this, or should syn only focus on parsing and keep other functionality to a minimum?
One that I had to use recently was on Data to get the span of the token, such as
pub trait ToSpan {
fn to_span(self) -> Span;
}
impl ToSpan for Data {
fn to_span(self) -> Span {
match self {
Data::Struct(d) => d.struct_token.span(),
Data::Enum(d) => d.enum_token.span(),
Data::Union(d) => d.union_token.span(),
}
}
}
Now I realize that implementing syn::spanned::Spanned on Data is quite complex and should give the entire definition, a helper method Data.token_span() or something like that would be really great.
I found myself reaching for a number of conveniences that were outside syn's stated scope, which led me to create darling. In this particular case, you may find darling::ast::Data helpful.
They need to go in a separate crate. The suggestion of adding various conveniences would make this crate effectively unbounded in scope which is not appealing to me or the users who rely on it to compile fast.