derive_more_impl/
constructor.rs

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        #[allow(unreachable_code)] // omit warnings for `!` and other unreachable types
30        #[automatically_derived]
31        impl #impl_generics #input_type #ty_generics #where_clause {
32            #[inline]
33            pub const fn new(#(#vars: #original_types),*) -> #input_type #ty_generics {
34                #body
35            }
36        }
37    }
38}
39
40fn tuple_body(return_type: &Ident, fields: &[&Field]) -> (TokenStream, Vec<Ident>) {
41    let vars = &numbered_vars(fields.len(), "");
42    (quote! { #return_type(#(#vars),*) }, vars.clone())
43}
44
45fn struct_body(return_type: &Ident, fields: &[&Field]) -> (TokenStream, Vec<Ident>) {
46    let field_names: &Vec<Ident> =
47        &field_idents(fields).iter().map(|f| (**f).clone()).collect();
48    let vars = field_names;
49    let ret_vars = field_names.clone();
50    (quote! { #return_type{#(#field_names: #vars),*} }, ret_vars)
51}