1 | use crate::utils::{ |
2 | field_idents, get_field_types, named_to_vec, numbered_vars, unnamed_to_vec, |
3 | }; |
4 | use proc_macro2::TokenStream; |
5 | use quote::quote; |
6 | use syn::{Data, DeriveInput, Field, Fields, Ident}; |
7 | |
8 | /// Provides the hook to expand `#[derive(Constructor)]` into an implementation of `Constructor` |
9 | pub fn expand(input: &DeriveInput, _: &str) -> TokenStream { |
10 | let input_type = &input.ident; |
11 | let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); |
12 | let ((body, vars), fields) = match input.data { |
13 | Data::Struct(ref data_struct) => match data_struct.fields { |
14 | Fields::Unnamed(ref fields) => { |
15 | let field_vec = unnamed_to_vec(fields); |
16 | (tuple_body(input_type, &field_vec), field_vec) |
17 | } |
18 | Fields::Named(ref fields) => { |
19 | let field_vec = named_to_vec(fields); |
20 | (struct_body(input_type, &field_vec), field_vec) |
21 | } |
22 | Fields::Unit => (struct_body(input_type, &[]), vec![]), |
23 | }, |
24 | _ => panic!("Only structs can derive a constructor" ), |
25 | }; |
26 | let original_types = &get_field_types(&fields); |
27 | quote! { |
28 | #[allow(missing_docs)] |
29 | impl#impl_generics #input_type#ty_generics #where_clause { |
30 | #[inline] |
31 | pub fn new(#(#vars: #original_types),*) -> #input_type#ty_generics { |
32 | #body |
33 | } |
34 | } |
35 | } |
36 | } |
37 | |
38 | fn tuple_body(return_type: &Ident, fields: &[&Field]) -> (TokenStream, Vec<Ident>) { |
39 | let vars: &Vec = &numbered_vars(count:fields.len(), prefix:"" ); |
40 | (quote!(#return_type(#(#vars),*)), vars.clone()) |
41 | } |
42 | |
43 | fn struct_body(return_type: &Ident, fields: &[&Field]) -> (TokenStream, Vec<Ident>) { |
44 | let field_names: &Vec<Ident> = |
45 | &field_idents(fields).iter().map(|f: &&Ident| (**f).clone()).collect(); |
46 | let vars: &Vec = field_names; |
47 | let ret_vars: Vec = field_names.clone(); |
48 | (quote!(#return_type{#(#field_names: #vars),*}), ret_vars) |
49 | } |
50 | |