syn icon indicating copy to clipboard operation
syn copied to clipboard

Should syn have convenience functions for (derive) macros?

Open m-ou-se opened this issue 3 years ago • 2 comments

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?

m-ou-se avatar Jun 09 '21 08:06 m-ou-se

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.

Progdrasil avatar Aug 31 '21 14:08 Progdrasil

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.

TedDriggs avatar Apr 28 '22 13:04 TedDriggs

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.

dtolnay avatar Jan 23 '23 05:01 dtolnay