derive_refineable/
derive_refineable.rs1use proc_macro::TokenStream;
2use proc_macro2::TokenStream as TokenStream2;
3use quote::{format_ident, quote};
4use syn::{
5 DeriveInput, Field, FieldsNamed, PredicateType, TraitBound, Type, TypeParamBound, WhereClause,
6 WherePredicate, parse_macro_input, parse_quote,
7};
8
9#[proc_macro_derive(Refineable, attributes(refineable))]
10pub fn derive_refineable(input: TokenStream) -> TokenStream {
11 let DeriveInput {
12 ident,
13 data,
14 generics,
15 attrs,
16 ..
17 } = parse_macro_input!(input);
18
19 let refineable_attr = attrs.iter().find(|attr| attr.path().is_ident("refineable"));
20
21 let mut impl_debug_on_refinement = false;
22 let mut derives_serialize = false;
23 let mut refinement_traits_to_derive = vec![];
24
25 if let Some(refineable_attr) = refineable_attr {
26 let _ = refineable_attr.parse_nested_meta(|meta| {
27 if meta.path.is_ident("Debug") {
28 impl_debug_on_refinement = true;
29 } else {
30 if meta.path.is_ident("Serialize") {
31 derives_serialize = true;
32 }
33 refinement_traits_to_derive.push(meta.path);
34 }
35 Ok(())
36 });
37 }
38
39 let refinement_ident = format_ident!("{}Refinement", ident);
40 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
41
42 let fields = match data {
43 syn::Data::Struct(syn::DataStruct {
44 fields: syn::Fields::Named(FieldsNamed { named, .. }),
45 ..
46 }) => named.into_iter().collect::<Vec<Field>>(),
47 _ => panic!("This derive macro only supports structs with named fields"),
48 };
49
50 let field_names: Vec<_> = fields.iter().map(|f| f.ident.as_ref().unwrap()).collect();
51 let field_visibilities: Vec<_> = fields.iter().map(|f| &f.vis).collect();
52 let wrapped_types: Vec<_> = fields.iter().map(|f| get_wrapper_type(f, &f.ty)).collect();
53
54 let field_attributes: Vec<TokenStream2> = fields
55 .iter()
56 .map(|f| {
57 if derives_serialize {
58 if is_refineable_field(f) {
59 quote! { #[serde(default, skip_serializing_if = "::refineable::IsEmpty::is_empty")] }
60 } else {
61 quote! { #[serde(skip_serializing_if = "::std::option::Option::is_none")] }
62 }
63 } else {
64 quote! {}
65 }
66 })
67 .collect();
68
69 let type_param_bounds: Vec<_> = wrapped_types
71 .iter()
72 .map(|ty| {
73 WherePredicate::Type(PredicateType {
74 lifetimes: None,
75 bounded_ty: ty.clone(),
76 colon_token: Default::default(),
77 bounds: {
78 let mut punctuated = syn::punctuated::Punctuated::new();
79 punctuated.push_value(TypeParamBound::Trait(TraitBound {
80 paren_token: None,
81 modifier: syn::TraitBoundModifier::None,
82 lifetimes: None,
83 path: parse_quote!(Clone),
84 }));
85
86 punctuated
87 },
88 })
89 })
90 .collect();
91
92 let where_clause = match where_clause.cloned() {
94 Some(mut where_clause) => {
95 where_clause.predicates.extend(type_param_bounds);
96 where_clause.clone()
97 }
98 None => WhereClause {
99 where_token: Default::default(),
100 predicates: type_param_bounds.into_iter().collect(),
101 },
102 };
103
104 let refineable_refine_assignments: Vec<TokenStream2> = fields
105 .iter()
106 .map(|field| {
107 let name = &field.ident;
108 let is_refineable = is_refineable_field(field);
109 let is_optional = is_optional_field(field);
110
111 if is_refineable {
112 quote! {
113 self.#name.refine(&refinement.#name);
114 }
115 } else if is_optional {
116 quote! {
117 if let Some(value) = &refinement.#name {
118 self.#name = Some(value.clone());
119 }
120 }
121 } else {
122 quote! {
123 if let Some(value) = &refinement.#name {
124 self.#name = value.clone();
125 }
126 }
127 }
128 })
129 .collect();
130
131 let refineable_refined_assignments: Vec<TokenStream2> = fields
132 .iter()
133 .map(|field| {
134 let name = &field.ident;
135 let is_refineable = is_refineable_field(field);
136 let is_optional = is_optional_field(field);
137
138 if is_refineable {
139 quote! {
140 self.#name = self.#name.refined(refinement.#name);
141 }
142 } else if is_optional {
143 quote! {
144 if let Some(value) = refinement.#name {
145 self.#name = Some(value);
146 }
147 }
148 } else {
149 quote! {
150 if let Some(value) = refinement.#name {
151 self.#name = value;
152 }
153 }
154 }
155 })
156 .collect();
157
158 let refinement_refine_assignments: Vec<TokenStream2> = fields
159 .iter()
160 .map(|field| {
161 let name = &field.ident;
162 let is_refineable = is_refineable_field(field);
163
164 if is_refineable {
165 quote! {
166 self.#name.refine(&refinement.#name);
167 }
168 } else {
169 quote! {
170 if let Some(value) = &refinement.#name {
171 self.#name = Some(value.clone());
172 }
173 }
174 }
175 })
176 .collect();
177
178 let refinement_refined_assignments: Vec<TokenStream2> = fields
179 .iter()
180 .map(|field| {
181 let name = &field.ident;
182 let is_refineable = is_refineable_field(field);
183
184 if is_refineable {
185 quote! {
186 self.#name = self.#name.refined(refinement.#name);
187 }
188 } else {
189 quote! {
190 if let Some(value) = refinement.#name {
191 self.#name = Some(value);
192 }
193 }
194 }
195 })
196 .collect();
197
198 let from_refinement_assignments: Vec<TokenStream2> = fields
199 .iter()
200 .map(|field| {
201 let name = &field.ident;
202 let is_refineable = is_refineable_field(field);
203 let is_optional = is_optional_field(field);
204
205 if is_refineable {
206 quote! {
207 #name: value.#name.into(),
208 }
209 } else if is_optional {
210 quote! {
211 #name: value.#name.map(|v| v.into()),
212 }
213 } else {
214 quote! {
215 #name: value.#name.map(|v| v.into()).unwrap_or_default(),
216 }
217 }
218 })
219 .collect();
220
221 let debug_impl = if impl_debug_on_refinement {
222 let refinement_field_debugs: Vec<TokenStream2> = fields
223 .iter()
224 .map(|field| {
225 let name = &field.ident;
226 quote! {
227 if self.#name.is_some() {
228 debug_struct.field(stringify!(#name), &self.#name);
229 } else {
230 all_some = false;
231 }
232 }
233 })
234 .collect();
235
236 quote! {
237 impl #impl_generics std::fmt::Debug for #refinement_ident #ty_generics
238 #where_clause
239 {
240 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241 let mut debug_struct = f.debug_struct(stringify!(#refinement_ident));
242 let mut all_some = true;
243 #( #refinement_field_debugs )*
244 if all_some {
245 debug_struct.finish()
246 } else {
247 debug_struct.finish_non_exhaustive()
248 }
249 }
250 }
251 }
252 } else {
253 quote! {}
254 };
255
256 let refinement_is_empty_conditions: Vec<TokenStream2> = fields
257 .iter()
258 .map(|field| {
259 let name = &field.ident;
260
261 if is_refineable_field(field) {
262 quote! { self.#name.is_empty() }
263 } else {
264 quote! { self.#name.is_none() }
265 }
266 })
267 .collect();
268
269 let refineable_is_superset_conditions: Vec<TokenStream2> = fields
270 .iter()
271 .map(|field| {
272 let name = &field.ident;
273 let is_refineable = is_refineable_field(field);
274 let is_optional = is_optional_field(field);
275
276 if is_refineable {
277 quote! {
278 if !self.#name.is_superset_of(&refinement.#name) {
279 return false;
280 }
281 }
282 } else if is_optional {
283 quote! {
284 if refinement.#name.is_some() && &self.#name != &refinement.#name {
285 return false;
286 }
287 }
288 } else {
289 quote! {
290 if let Some(refinement_value) = &refinement.#name {
291 if &self.#name != refinement_value {
292 return false;
293 }
294 }
295 }
296 }
297 })
298 .collect();
299
300 let refinement_is_superset_conditions: Vec<TokenStream2> = fields
301 .iter()
302 .map(|field| {
303 let name = &field.ident;
304 let is_refineable = is_refineable_field(field);
305
306 if is_refineable {
307 quote! {
308 if !self.#name.is_superset_of(&refinement.#name) {
309 return false;
310 }
311 }
312 } else {
313 quote! {
314 if refinement.#name.is_some() && &self.#name != &refinement.#name {
315 return false;
316 }
317 }
318 }
319 })
320 .collect();
321
322 let refineable_subtract_assignments: Vec<TokenStream2> = fields
323 .iter()
324 .map(|field| {
325 let name = &field.ident;
326 let is_refineable = is_refineable_field(field);
327 let is_optional = is_optional_field(field);
328
329 if is_refineable {
330 quote! {
331 #name: self.#name.subtract(&refinement.#name),
332 }
333 } else if is_optional {
334 quote! {
335 #name: if &self.#name == &refinement.#name {
336 None
337 } else {
338 self.#name.clone()
339 },
340 }
341 } else {
342 quote! {
343 #name: if let Some(refinement_value) = &refinement.#name {
344 if &self.#name == refinement_value {
345 None
346 } else {
347 Some(self.#name.clone())
348 }
349 } else {
350 Some(self.#name.clone())
351 },
352 }
353 }
354 })
355 .collect();
356
357 let refinement_subtract_assignments: Vec<TokenStream2> = fields
358 .iter()
359 .map(|field| {
360 let name = &field.ident;
361 let is_refineable = is_refineable_field(field);
362
363 if is_refineable {
364 quote! {
365 #name: self.#name.subtract(&refinement.#name),
366 }
367 } else {
368 quote! {
369 #name: if &self.#name == &refinement.#name {
370 None
371 } else {
372 self.#name.clone()
373 },
374 }
375 }
376 })
377 .collect();
378
379 let mut derive_stream = quote! {};
380 for trait_to_derive in refinement_traits_to_derive {
381 derive_stream.extend(quote! { #[derive(#trait_to_derive)] })
382 }
383
384 let r#gen = quote! {
385 #[derive(Clone)]
387 #derive_stream
388 pub struct #refinement_ident #impl_generics {
389 #(
390 #[allow(missing_docs)]
391 #field_attributes
392 #field_visibilities #field_names: #wrapped_types
393 ),*
394 }
395
396 impl #impl_generics Refineable for #ident #ty_generics
397 #where_clause
398 {
399 type Refinement = #refinement_ident #ty_generics;
400
401 fn refine(&mut self, refinement: &Self::Refinement) {
402 #( #refineable_refine_assignments )*
403 }
404
405 fn refined(mut self, refinement: Self::Refinement) -> Self {
406 #( #refineable_refined_assignments )*
407 self
408 }
409
410 fn is_superset_of(&self, refinement: &Self::Refinement) -> bool
411 {
412 #( #refineable_is_superset_conditions )*
413 true
414 }
415
416 fn subtract(&self, refinement: &Self::Refinement) -> Self::Refinement
417 {
418 #refinement_ident {
419 #( #refineable_subtract_assignments )*
420 }
421 }
422 }
423
424 impl #impl_generics Refineable for #refinement_ident #ty_generics
425 #where_clause
426 {
427 type Refinement = #refinement_ident #ty_generics;
428
429 fn refine(&mut self, refinement: &Self::Refinement) {
430 #( #refinement_refine_assignments )*
431 }
432
433 fn refined(mut self, refinement: Self::Refinement) -> Self {
434 #( #refinement_refined_assignments )*
435 self
436 }
437
438 fn is_superset_of(&self, refinement: &Self::Refinement) -> bool
439 {
440 #( #refinement_is_superset_conditions )*
441 true
442 }
443
444 fn subtract(&self, refinement: &Self::Refinement) -> Self::Refinement
445 {
446 #refinement_ident {
447 #( #refinement_subtract_assignments )*
448 }
449 }
450 }
451
452 impl #impl_generics ::refineable::IsEmpty for #refinement_ident #ty_generics
453 #where_clause
454 {
455 fn is_empty(&self) -> bool {
456 true #( && #refinement_is_empty_conditions )*
457 }
458 }
459
460 impl #impl_generics From<#refinement_ident #ty_generics> for #ident #ty_generics
461 #where_clause
462 {
463 fn from(value: #refinement_ident #ty_generics) -> Self {
464 Self {
465 #( #from_refinement_assignments )*
466 }
467 }
468 }
469
470 impl #impl_generics ::core::default::Default for #refinement_ident #ty_generics
471 #where_clause
472 {
473 fn default() -> Self {
474 #refinement_ident {
475 #( #field_names: Default::default() ),*
476 }
477 }
478 }
479
480 impl #impl_generics #refinement_ident #ty_generics
481 #where_clause
482 {
483 pub fn is_some(&self) -> bool {
485 #(
486 if self.#field_names.is_some() {
487 return true;
488 }
489 )*
490 false
491 }
492 }
493
494 #debug_impl
495 };
496 r#gen.into()
497}
498
499fn is_refineable_field(f: &Field) -> bool {
500 f.attrs
501 .iter()
502 .any(|attr| attr.path().is_ident("refineable"))
503}
504
505fn is_optional_field(f: &Field) -> bool {
506 if let Type::Path(typepath) = &f.ty
507 && typepath.qself.is_none()
508 {
509 let segments = &typepath.path.segments;
510 if segments.len() == 1 && segments.iter().any(|s| s.ident == "Option") {
511 return true;
512 }
513 }
514 false
515}
516
517fn get_wrapper_type(field: &Field, ty: &Type) -> syn::Type {
518 if is_refineable_field(field) {
519 let struct_name = if let Type::Path(tp) = ty {
520 tp.path.segments.last().unwrap().ident.clone()
521 } else {
522 panic!("Expected struct type for a refineable field");
523 };
524
525 let refinement_struct_name = if struct_name.to_string().ends_with("Refinement") {
526 format_ident!("{}", struct_name)
527 } else {
528 format_ident!("{}Refinement", struct_name)
529 };
530 let generics = if let Type::Path(tp) = ty {
531 &tp.path.segments.last().unwrap().arguments
532 } else {
533 &syn::PathArguments::None
534 };
535 parse_quote!(#refinement_struct_name #generics)
536 } else if is_optional_field(field) {
537 ty.clone()
538 } else {
539 parse_quote!(Option<#ty>)
540 }
541}