1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use field::{make_field_configs, FieldConfig};
use proc_macro::TokenStream;
use proc_macro_error::{abort, proc_macro_error};
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
mod attributes;
mod config;
mod field;
#[proc_macro_error]
#[proc_macro_derive(GenericNew, attributes(generic_new))]
pub fn derive_generic_new(input: TokenStream) -> TokenStream {
pretty_env_logger::try_init().ok();
let derive_input = parse_macro_input!(input as DeriveInput);
let user_ident = derive_input.ident.clone();
match derive_input.data {
syn::Data::Struct(ref user_struct) => {
let field_infos = make_field_configs(user_struct);
let inputs = field_infos.iter().map(FieldConfig::input);
let transforms = field_infos.iter().map(FieldConfig::transform);
let outputs = field_infos.iter().map(FieldConfig::output);
let constructor = match user_struct.fields {
syn::Fields::Named(_) => quote!(Self {#(#outputs,)*}),
syn::Fields::Unnamed(_) => quote!(Self(#(#outputs,)*)),
syn::Fields::Unit => abort!(derive_input, "Unit fields are not supported"),
};
let appended = quote! {
impl #user_ident {
pub fn new(
#(#inputs,)*
) -> Self {
#(#transforms;)*
#constructor
}
}
};
appended.into()
}
syn::Data::Enum(_) => abort!(derive_input, "Enums are not yet supported"),
syn::Data::Union(_) => abort!(derive_input, "Unions are not supported"),
}
}
#[cfg(test)]
mod tests {
#[test]
fn ui() {
let t = trybuild::TestCases::new();
t.pass("trybuild/*.rs")
}
}