1use crate::utils::{
2 field_idents, get_field_types, named_to_vec, numbered_vars, unnamed_to_vec,
3};
4use proc_macro2::TokenStream;
5use quote::quote;
6use syn::{Data, DeriveInput, Field, Fields, Ident};
7
8/// Provides the hook to expand `#[derive(Constructor)]` into an implementation of `Constructor`
9pub 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
38fn 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
43fn 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