Skip to main content

fc_gpui_derive_refineable/
derive_refineable.rs

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