Skip to main content

from_nested_tuple_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{Data, DeriveInput, Fields, Ident, parse_macro_input};
4
5struct FieldEntry<'a> {
6    ident: &'a syn::Ident,
7    ty: &'a syn::Type,
8}
9
10#[proc_macro_derive(FromTuple)]
11pub fn from_tuple_derive(input: TokenStream) -> TokenStream {
12    let input: DeriveInput = parse_macro_input!(input as DeriveInput);
13    let name = &input.ident;
14    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
15
16    let expanded = match &input.data {
17        Data::Struct(data_struct) => match &data_struct.fields {
18            Fields::Named(fields) => {
19                let mut iter = fields.named.iter().map(|f| FieldEntry {
20                    ident: f.ident.as_ref().unwrap(),
21                    ty: &f.ty,
22                });
23                let first = iter.next().expect("Struct should have at least 1 field");
24                let first_name = first.ident;
25                let first_ty = first.ty;
26
27                let mut unnested_names = quote! { #first_name };
28                let mut tuple_type = quote! { #first_ty };
29                let mut field_names = vec![first_name];
30
31                for this in iter {
32                    let this_name = this.ident;
33                    let this_ty = &this.ty;
34                    tuple_type = quote! { (#tuple_type, #this_ty) };
35                    unnested_names = quote! { (#unnested_names, #this_name) };
36                    field_names.push(this.ident);
37                }
38
39                quote! {
40                    impl #impl_generics from_nested_tuple::FromNestedTuple for #name #ty_generics #where_clause {
41                        type Tuple = #tuple_type;
42
43                        fn from_nested_tuple(tuple: Self::Tuple) -> Self {
44                            let #unnested_names = tuple;
45                            Self {
46                                #(#field_names,)*
47                            }
48                        }
49                    }
50                }
51            }
52            Fields::Unnamed(fields) => {
53                let mut iter = fields.unnamed.iter().map(|f| &f.ty);
54                let first_ty = iter.next().expect("Struct should have at least 1 field");
55                let first_name = format_ident!("field0");
56
57                let mut unnested_names = quote! { #first_name };
58                let mut tuple_type = quote! { #first_ty };
59                let mut field_names: Vec<Ident> = vec![first_name];
60
61                for (idx, this) in iter.enumerate() {
62                    let this_name = format_ident!("field{}", idx + 1);
63                    let this_ty = this;
64                    tuple_type = quote! { (#tuple_type, #this_ty) };
65                    unnested_names = quote! { (#unnested_names, #this_name) };
66                    field_names.push(this_name);
67                }
68
69                quote! {
70                    impl #impl_generics from_nested_tuple::FromNestedTuple for #name #ty_generics #where_clause {
71                        type Tuple = #tuple_type;
72
73                        fn from_nested_tuple(tuple: Self::Tuple) -> Self {
74                            let #unnested_names = tuple;
75                            Self(#(#field_names,)*)
76                        }
77                    }
78                }
79            }
80            _ => panic!("FromTuple cannot be derived from Unit Structs"),
81        },
82        _ => panic!("FromTuple can only be derived for structs"),
83    };
84
85    TokenStream::from(expanded)
86}