1use darling::{FromDeriveInput, FromField};
8use proc_macro::TokenStream;
9use proc_macro::{self, LexError};
10use quote::quote;
11use std::str::FromStr;
12use syn::punctuated::Punctuated;
13use syn::token::Comma;
14use syn::{
15 parse_macro_input, DataEnum, DataUnion, DeriveInput, Field, FieldsNamed, FieldsUnnamed, Ident,
16 Type,
17};
18
19macro_rules! getter {
20 ($idn:expr, $typ:expr) => {
21 format!(
22 r##"pub fn {idn}(&self) -> &{ty} {{&self.{idn}}}"##,
23 idn = $idn,
24 ty = $typ
25 )
26 };
27}
28
29macro_rules! java_getter {
30 ($func:expr,$idn:expr, $typ:expr) => {
31 format!(
32 r##"pub fn get_{idn}(&self) -> &{ty} {{&self.{idn}}}"##,
33 idn = $idn,
34 ty = $typ
35 )
36 };
37}
38
39macro_rules! setter {
40 ($func:expr, $idn:expr, $typ:expr) => {
41 format!(
42 r##"pub fn {idn}_mut(&mut self) -> &mut {ty} {{&mut self.{idn}}}"##,
43 idn = $idn,
44 ty = $typ
45 )
46 };
47}
48
49macro_rules! java_setter {
50 ($idn:expr, $typ:expr) => {
51 format!(r##"pub fn set_{idn}(&mut self, value: {ty}) -> &mut Self {{self.{idn} = value; self}}"##,
52 idn = $idn,
53 ty = $typ
54 )
55};
56}
57
58enum SetterGetter {
59 Get {
60 func_name: String,
61 field_type: String,
62 field_name: String,
63 },
64 JavaGet {
65 func_name: String,
66 field_type: String,
67 field_name: String,
68 },
69 Set {
70 func_name: String,
71 field_type: String,
72 field_name: String,
73 },
74 JavaSet {
75 func_name: String,
76 field_type: String,
77 field_name: String,
78 },
79}
80
81impl From<SetterGetter> for String {
82 fn from(setget: SetterGetter) -> Self {
83 match setget {
84 SetterGetter::Get {
85 func_name,
86 field_type,
87 field_name,
88 } => format! (r##"
89
90pub fn {func_name}(&self) -> &{field_type} {{
91&self.{field_name}
92}}
93"##, func_name = func_name, field_type = field_type, field_name= field_name),
94 SetterGetter::JavaGet {
95 func_name,
96 field_type,
97 field_name,
98 } => format! ("pub fn {func_name}(&self) -> &{field_type} {{&self.{field_name}}}", func_name = func_name, field_type = field_type, field_name= field_name),
99 SetterGetter::Set {
100 func_name,
101 field_type,
102 field_name,
103 } => format! ("pub fn {func_name}(&mut self) -> &mut {field_type} {{&mut self.{field_name}}}", func_name = func_name, field_type = field_type, field_name= field_name),
104 SetterGetter::JavaSet {
105 func_name,
106 field_type,
107 field_name,
108 } => format!("pub fn {func_name}(&mut self, value: {field_type}) -> &mut Self {{self.{field_name} = value; self}}", func_name = func_name, field_type = field_type, field_name= field_name),
109 }
110 }
111}
112
113#[derive(FromDeriveInput, Default)]
114#[darling(default, attributes(simplify), forward_attrs(allow, doc, cfg))]
115struct Opts {
116 java_style: bool,
117 setter: bool,
118 getter: bool,
119}
120
121#[derive(FromField, Default)]
122#[darling(default, forward_attrs(allow, doc, cfg))]
123struct FieldOpts {
124 java_style: bool,
125 disabled: bool,
126 rename: Option<String>,
127}
128
129#[proc_macro_derive(Simplify, attributes(simplify))]
130pub fn simplify(input: TokenStream) -> TokenStream {
131 let input: DeriveInput = parse_macro_input!(input);
132 let opts = Opts::from_derive_input(&input).expect("Failed to parse GetterOpts");
133
134 let description = match input.data {
135 syn::Data::Struct(s) => match s.fields {
136 syn::Fields::Named(FieldsNamed { named, .. }) => handle_attributes(&opts, named),
137 syn::Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
138 let num_fields = unnamed.iter().count();
139 format!("a struct with {} unnamed fields", num_fields);
140 Vec::new()
141 }
142 syn::Fields::Unit => {
143 format!("a unit struct");
144 Vec::new()
145 }
146 },
147 _ => panic!("Failure, this derive only works on Stucts"),
148 };
149
150 TokenStream::from_str(&format!(
151 r##"
152 impl {ident} {{
153 {functions}
154 }}"##,
155 ident = input.ident,
156 functions = description.join("\n")
157 ))
158 .unwrap()
159}
160
161fn handle_attributes(global_opts: &Opts, named: Punctuated<Field, Comma>) -> Vec<String> {
162 let idents = named
163 .iter()
164 .flat_map(|f| {
165 let field_opts = FieldOpts::from_field(f).expect("Failed to parse field options");
166 let mut res = Vec::new();
167 if let Some(s) = setter(global_opts, &field_opts, f) {
168 res.push(s)
169 }
170 if let Some(s) = getter(global_opts, &field_opts, f) {
171 res.push(s)
172 }
173 res
174 })
175 .map(|t| t.to_string())
176 .collect::<Vec<String>>();
177 idents
178}
179
180fn setter(global_opts: &Opts, opts: &FieldOpts, f: &Field) -> Option<String> {
181 let ident = &f.ident;
182 let field_type = &f.ty;
183 if global_opts.setter && !opts.disabled {
184 if global_opts.java_style {
185 let str_ident = ident.clone().map(|t| t.to_string());
186 if let (Some(func_name), Some(field_name)) = (
187 opts.rename
188 .clone()
189 .or_else(|| str_ident.clone().map(|str| format!("set_{}", str))),
190 str_ident,
191 ) {
192 Some(
193 SetterGetter::JavaSet {
194 func_name,
195 field_type: (quote! {#field_type}).to_string(),
196 field_name,
197 }
198 .into(),
199 )
200 } else {
201 None
202 }
203 } else {
204 let str_ident = ident.clone().map(|t| t.to_string());
205 if let (Some(func_name), Some(field_name)) = (
206 opts.rename
207 .clone()
208 .or_else(|| str_ident.clone().map(|str| format!("{}_mut", str))),
209 str_ident,
210 ) {
211 Some(
212 SetterGetter::Set {
213 func_name,
214 field_type: (quote! {#field_type}).to_string(),
215 field_name,
216 }
217 .into(),
218 )
219 } else {
220 None
221 }
222 }
223 } else {
224 None
225 }
226}
227
228fn getter(global_opts: &Opts, opts: &FieldOpts, f: &Field) -> Option<String> {
229 let ident = &f.ident;
230 let field_type = &f.ty;
231 if global_opts.setter && !opts.disabled {
232 if global_opts.java_style {
233 let str_ident = ident.clone().map(|t| t.to_string());
234 if let (Some(func_name), Some(field_name)) = (
235 opts.rename
236 .clone()
237 .or_else(|| str_ident.clone().map(|str| format!("get_{}", str))),
238 str_ident,
239 ) {
240 Some(
241 SetterGetter::JavaGet {
242 func_name,
243 field_type: (quote! {#field_type}).to_string(),
244 field_name,
245 }
246 .into(),
247 )
248 } else {
249 None
250 }
251 } else {
252 let str_ident = ident.clone().map(|t| t.to_string());
253 if let (Some(func_name), Some(field_name)) =
254 (opts.rename.clone().or_else(|| str_ident.clone()), str_ident)
255 {
256 Some(
257 SetterGetter::Get {
258 func_name,
259 field_type: (quote! {#field_type}).to_string(),
260 field_name,
261 }
262 .into(),
263 )
264 } else {
265 None
266 }
267 }
268 } else {
269 None
270 }
271}