fc_gpui_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 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 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 #[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 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}