1use quote::quote;
2
3struct Struct {
4 name: String,
5 parameters: String,
6 generic: String,
7}
8
9impl Struct {
10 fn parse(input: String) -> Self {
11 let tmp: Vec<&str> = input.split_ascii_whitespace().collect();
12 let name = tmp[1].into();
13 let parameters = Struct::get_inner(&input);
14 let generic = Struct::get_generic(&tmp);
15
16 Self {
17 name,
18 parameters,
19 generic,
20 }
21 }
22
23 fn get_generic(tokens: &[&str]) -> String {
24 let mut generic: String = "".into();
25 for i in 2..tokens.len() {
26 if tokens[i] == "{" {
27 break;
28 }
29 generic.push_str(tokens[i]);
30 }
31
32 generic
33 }
34
35 fn get_inner(input: &str) -> String {
36 let l = input.find('{').unwrap() + 1;
37 let r = {
38 let mut r = 0;
39 for i in (0..input.len()).rev() {
40 if &input[i..i + 1] == "}" {
41 r = i;
42 break;
43 }
44 }
45 r
46 };
47 input[l..r].into()
48 }
49
50 fn get_fields(&self) -> String {
51 let mut ret = String::new();
52 let params = self.parameters.replace("::", "");
53 let tmp: Vec<&str> = params.split(':').collect();
54 if tmp.is_empty() {
55 return "".into();
56 }
57 ret.push_str(tmp[0]);
58 for i in 1..tmp.len() - 1 {
59 ret.push_str(", ");
60 if tmp[i].contains(',') {
61 let tmp2: Vec<&str> = tmp[i].split(',').collect();
62 ret.push_str(tmp2.last().unwrap());
63 } else {
64 ret.push_str(tmp[i]);
65 }
66 }
67
68 ret
69 }
70}
71
72#[proc_macro_derive(New)]
73pub fn derive_new(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
74 let s = Struct::parse(input.to_string());
75 let name: proc_macro2::TokenStream = s.name.parse().unwrap();
76 let params: proc_macro2::TokenStream = s.parameters.parse().unwrap();
77 let fields: proc_macro2::TokenStream = s.get_fields().parse().unwrap();
78 let generic: proc_macro2::TokenStream = s.generic.parse().unwrap();
79
80 let expanded = quote! {
81 impl #generic #name #generic {
83 const fn new(#params) -> Self {
84 Self {
85 #fields
86 }
87 }
88 }
89 };
90
91 proc_macro::TokenStream::from(expanded)
93}