family_derive/
lib.rs

1use proc_macro::{self, Span, TokenStream};
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput, Ident};
4
5/// Derive `Member` and generate `Family` for common cases.
6///
7/// Implements `Family` for the following cases:
8/// - Owned types, as `Type`
9/// - Borrowed types with one lifetime, as `TypeF`
10#[proc_macro_derive(Member)]
11pub fn derive_member(input: TokenStream) -> TokenStream {
12    let input = parse_macro_input!(input);
13    let DeriveInput {
14        vis,
15        ident,
16        generics,
17        ..
18    } = input;
19
20    let lifetimes = generics.lifetimes().count();
21    let (family_ident, generics_gat) = match lifetimes {
22        0 => (ident.clone(), quote! {}),
23        1 => (
24            Ident::new(&format!("{}F", ident), Span::call_site().into()),
25            quote! { <'a> },
26        ),
27        _ => panic!("derive macro only supports 0 or 1 lifetimes"),
28    };
29
30    // Create the family type if necessary
31    let family_type = if family_ident != ident {
32        quote! {
33            #vis enum #family_ident {}
34        }
35    } else {
36        quote! {}
37    };
38
39    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
40    let output = quote! {
41        #family_type
42
43        impl #impl_generics family::Member<#family_ident> for #ident #ty_generics #where_clause {}
44
45        impl family::Family for #family_ident {
46            type Member<'a> = #ident #generics_gat;
47        }
48    };
49    output.into()
50}