new_derive/
lib.rs

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        // The generated impl.
82        impl #generic #name #generic {
83            const fn new(#params) -> Self {
84                Self {
85                    #fields
86                }
87            }
88        }
89    };
90
91    // Hand the output tokens back to the compiler.
92    proc_macro::TokenStream::from(expanded)
93}