from_nested_tuple_derive/
lib.rs1use 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}