picea_macro_tools/
lib.rs

1use proc_macro::TokenStream;
2use quote::{quote, ToTokens};
3use syn::{
4    parenthesized, parse_macro_input, punctuated::Punctuated, spanned::Spanned, Attribute, Data,
5    DeriveInput, Ident, LitStr, Meta, Visibility,
6};
7
8#[proc_macro_derive(Shape, attributes(inner))]
9pub fn shape(input: TokenStream) -> TokenStream {
10    let input = parse_macro_input!(input as DeriveInput);
11    let ident = input.ident;
12    let generics = input.generics;
13
14    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
15
16    quote!(
17        impl #impl_generics crate::collision::Collider for #ident #ty_generics #where_clause {}
18
19        impl #impl_generics crate::element::SelfClone for #ident #ty_generics #where_clause {
20            fn self_clone(&self) -> Box<dyn crate::element::ShapeTraitUnion> {
21                self.clone().into()
22            }
23        }
24    )
25    .into()
26}
27
28#[proc_macro_derive(Deref, attributes(deref))]
29pub fn deref(input: TokenStream) -> TokenStream {
30    let input = parse_macro_input!(input as DeriveInput);
31    let ident = input.ident;
32    let generics = input.generics;
33    let Data::Struct(data) = input.data else {
34        return syn::Error::new(ident.span(), "Deref can only be applied to structs")
35            .into_compile_error()
36            .into();
37    };
38
39    let mut deref_field: Option<(syn::Ident, syn::Type)> = None;
40
41    for field in data.fields {
42        for attr in field.attrs.iter() {
43            if attr.path().is_ident("deref") {
44                deref_field = Some((field.ident.clone().unwrap(), field.ty.clone()));
45            }
46        }
47    }
48
49    let Some((deref_field_ident, deref_field_ty)) = deref_field else {
50        return syn::Error::new(
51            ident.span(),
52            "must set one deref field when use Deref macro",
53        )
54        .into_compile_error()
55        .into();
56    };
57
58    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
59
60    quote!(
61        impl #impl_generics core::ops::Deref for #ident #ty_generics #where_clause {
62            type Target = #deref_field_ty;
63            fn deref(&self) -> &Self::Target {
64                &self.#deref_field_ident
65            }
66        }
67
68        impl #impl_generics core::ops::DerefMut for #ident #ty_generics #where_clause {
69           fn deref_mut(&mut self) -> &mut Self::Target {
70             &mut self.#deref_field_ident
71           }
72        }
73    )
74    .into()
75}
76
77#[proc_macro_derive(Builder, attributes(default, builder, shared))]
78pub fn builder(input: TokenStream) -> TokenStream {
79    let input = parse_macro_input!(input as DeriveInput);
80    let origin_ident = input.ident;
81    let generics = input.generics;
82
83    let vis = input.vis;
84
85    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
86
87    let Data::Struct(data) = input.data else {
88        return syn::Error::new(origin_ident.span(), "error")
89            .into_compile_error()
90            .into();
91    };
92
93    let ident = Ident::new(&format!("{}Builder", origin_ident), origin_ident.span());
94
95    let fields_iter = || {
96        data.fields.iter().filter(|field| {
97            field
98                .attrs
99                .iter()
100                .find(|attr| attr.path().is_ident("builder") || attr.path().is_ident("shared"))
101                .map(|attr| {
102                    let mut is_skip = false;
103                    let _ = attr.parse_nested_meta(|meta| {
104                        is_skip = meta.path.is_ident("skip");
105                        Ok(())
106                    });
107                    !is_skip
108                })
109                .unwrap_or(true)
110        })
111    };
112
113    let default_fields: Vec<_> = data
114        .fields
115        .iter()
116        .map(|field| {
117            let field_ident = &field.ident;
118            let default_expr: Option<syn::Expr> = field
119                .attrs
120                .iter()
121                .find(|attr| attr.path().is_ident("default"))
122                .and_then(|attr| match &attr.meta {
123                    Meta::Path(_) => None,
124                    Meta::NameValue(meta) => Some(meta.value.clone()),
125                    Meta::List(list) => list.parse_args().ok(),
126                });
127
128            match default_expr {
129                Some(expr) => quote!(
130                    #field_ident: #expr,
131                ),
132                None => quote!(
133                    #field_ident: Default::default(),
134                ),
135            }
136        })
137        .collect();
138
139    let fields: Vec<_> = data
140        .fields
141        .iter()
142        .map(|field| {
143            let field_ident = &field.ident;
144            let ty = &field.ty;
145
146            quote!(
147                #field_ident: #ty,
148            )
149        })
150        .collect();
151
152    let build_fields: Vec<_> = data
153        .fields
154        .iter()
155        .map(|field| {
156            let field_ident = &field.ident;
157            quote!(
158                #field_ident: value.#field_ident,
159            )
160        })
161        .collect();
162
163    let property_methods: Vec<_> = fields_iter()
164        .map(|field| {
165            let field_ident = &field.ident;
166            let ty = &field.ty;
167            quote!(
168                pub fn #field_ident(mut self, value: impl Into<#ty>) -> Self {
169                    self.#field_ident = value.into();
170                    self
171                }
172            )
173        })
174        .collect();
175
176    quote!(
177        #vis struct #ident {
178            #(#fields)*
179        }
180
181        impl #impl_generics Default for #ident #ty_generics #where_clause {
182            fn default() -> Self {
183                Self {
184                    #(#default_fields)*
185                }
186            }
187        }
188
189        impl #impl_generics Default for #origin_ident #ty_generics #where_clause {
190            fn default() -> Self {
191                Self {
192                    #(#default_fields)*
193                }
194            }
195        }
196
197        impl #impl_generics From<#ident #ty_generics> for #origin_ident #ty_generics #where_clause {
198            fn from(value: #ident #ty_generics) -> Self {
199                Self {
200                    #(#build_fields)*
201                }
202            }
203        }
204
205        impl #impl_generics #ident #ty_generics #where_clause {
206            pub fn new() -> Self {
207                Self::default()
208            }
209
210            #(#property_methods)*
211        }
212    )
213    .into()
214}
215
216#[proc_macro_derive(Fields, attributes(shared, r, w))]
217pub fn fields(input: TokenStream) -> TokenStream {
218    let input = parse_macro_input!(input as DeriveInput);
219    let ident = input.ident;
220    let generics = input.generics;
221
222    let input_vis = input.vis;
223
224    fn find_attr<'a>(attrs: &'a [syn::Attribute], ident: &str) -> Option<&'a Attribute> {
225        attrs.iter().find(|attr| attr.path().is_ident(ident))
226    }
227
228    let should_skip = |attrs: &[syn::Attribute]| -> bool {
229        attrs
230            .iter()
231            .filter(|attr| ["shared", "r", "w"].iter().any(|k| attr.path().is_ident(k)))
232            .any(|attr| {
233                let mut is_skip = false;
234                let _ = attr.parse_nested_meta(|meta| {
235                    is_skip = meta.path.is_ident("skip");
236                    Ok(())
237                });
238                is_skip
239            })
240    };
241
242    let parse_attr_read = |attrs: &[syn::Attribute]| -> Option<Visibility> {
243        find_attr(attrs, "r").map(|attr| {
244            let mut field_vis: Visibility = input_vis.clone();
245            let _ = attr.parse_nested_meta(|meta| {
246                if meta.path.is_ident("vis") {
247                    let content;
248                    parenthesized!(content in meta.input);
249                    let value = content.parse::<Visibility>()?;
250                    field_vis = value;
251                }
252                Ok(())
253            });
254
255            field_vis
256        })
257    };
258
259    let parse_attr_write = |attrs: &[syn::Attribute]| -> Option<(bool, bool, Visibility)> {
260        find_attr(attrs, "w").map(|attr| {
261            let mut field_reducer: bool = false;
262            let mut field_set: bool = false;
263            let mut field_vis: Visibility = input_vis.clone();
264            let _ = attr.parse_nested_meta(|meta| {
265                if meta.path.is_ident("reducer") {
266                    field_reducer = true;
267                    field_set = true;
268                }
269                if meta.path.is_ident("set") {
270                    field_set = true;
271                }
272
273                if meta.path.is_ident("vis") {
274                    let content;
275                    parenthesized!(content in meta.input);
276                    let value = content.parse::<Visibility>()?;
277                    field_vis = value;
278                }
279                Ok(())
280            });
281            (field_reducer, field_set, field_vis)
282        })
283    };
284
285    let global_attr_read = parse_attr_read(&input.attrs);
286
287    let global_attr_write = parse_attr_write(&input.attrs);
288
289    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
290
291    let Data::Struct(data) = input.data else {
292        return syn::Error::new(ident.span(), "error")
293            .into_compile_error()
294            .into();
295    };
296
297    let property_method = data
298        .fields
299        .iter()
300        .filter(|field| !should_skip(&field.attrs))
301        .map(|field| {
302            let field_ident = field.ident.clone().unwrap();
303            let ty = field.ty.clone();
304
305            let primitive_types = [
306                "bool", "u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128",
307                "f32", "f64", "FloatNum", "ID",
308            ];
309
310            let should_return_copy_when_read = match &field.ty {
311                syn::Type::Path(path) => {
312                    let t = path.into_token_stream().to_string();
313                    primitive_types
314                        .iter()
315                        .any(|primitive_type| primitive_type == &t)
316                }
317                _ => false,
318            };
319            let read_field_method = parse_attr_read(&field.attrs)
320                .or(global_attr_read.clone())
321                .map(|vis| {
322                    if should_return_copy_when_read {
323                        quote!(
324                            #vis fn #field_ident(&self) -> #ty {
325                                self.#field_ident
326                            }
327                        )
328                    } else {
329                        quote!(
330                            #vis fn #field_ident(&self) -> &#ty {
331                                &self.#field_ident
332                            }
333                        )
334                    }
335                });
336
337            let write_field_method = parse_attr_write(&field.attrs)
338                .or(global_attr_write.clone())
339                .map(|(use_reducer, use_set_prefix_method, vis)| {
340                    if use_set_prefix_method {
341                    let set_field_ident =
342                        Ident::new(&format!("set_{}", field_ident), field.ident.span());
343                        if use_reducer {
344                    quote!(
345                        #vis fn #set_field_ident(&mut self, mut reducer: impl FnOnce(#ty)-> #ty) -> &mut Self {
346                            self.#field_ident = reducer(self.#field_ident);
347                            self
348                        }
349                    )
350                }else{
351                    quote!(
352                        #vis fn #set_field_ident(&mut self, value: impl Into<#ty>) -> &mut Self {
353                            self.#field_ident = value.into();
354                            self
355                        }
356                    )
357                    }
358                } else {
359                    let filed_ident_mut =
360                        Ident::new(&format!("{}_mut", field_ident), field.ident.span());
361
362                    quote!(
363                        #vis fn #filed_ident_mut(&mut self) -> &mut #ty {
364                            &mut self.#field_ident
365                        }
366                    )
367                }
368            });
369
370
371            quote!(
372                #read_field_method
373
374                #write_field_method
375            )
376        });
377
378    quote!(
379        impl #impl_generics #ident #ty_generics #where_clause {
380            #(#property_method)*
381        }
382    )
383    .into()
384}
385
386fn underscore_to_camelcase(input: &str) -> String {
387    let mut result = String::new();
388    let mut capitalize_next = false;
389
390    for c in input.chars() {
391        if c == '_' {
392            capitalize_next = true;
393        } else if capitalize_next {
394            result.push(c.to_ascii_uppercase());
395            capitalize_next = false;
396        } else {
397            result.push(c);
398        }
399    }
400
401    result
402}
403
404#[proc_macro_attribute]
405pub fn wasm_config(attr: TokenStream, item: TokenStream) -> TokenStream {
406    let item = parse_macro_input!(item as syn::Item);
407
408    let args_parsed =
409        parse_macro_input!(attr with Punctuated::<Meta, syn::Token![,]>::parse_terminated);
410
411    let mut bind_obj: Option<syn::Expr> = None;
412
413    for arg in args_parsed {
414        arg.path().is_ident("bind");
415        let Meta::NameValue(meta) = arg else {
416            return syn::Error::new(arg.span(), "bind can only use with bind = {{Obj}} ")
417                .into_compile_error()
418                .into();
419        };
420
421        let bind_object = meta.value;
422        bind_obj = Some(bind_object);
423    }
424
425    let syn::Item::Struct(struct_data) = item else {
426        return syn::Error::new(item.span(), "only apply to struct")
427            .into_compile_error()
428            .into();
429    };
430
431    let ident = struct_data.ident;
432
433    let (impl_generics, ty_generics, where_clause) = struct_data.generics.split_for_impl();
434
435    let fields: Vec<_> = struct_data
436        .fields
437        .iter()
438        .map(|field| {
439            let field_ident = field.ident.clone();
440            let ty = field.ty.clone();
441            let field_name_str = field.ident.to_token_stream().to_string();
442            let serde_field_name = underscore_to_camelcase(&field_name_str);
443
444            let serde_field_name = LitStr::new(&serde_field_name, field_ident.span());
445            quote!(
446                #[serde(rename = #serde_field_name)]
447                #field_ident: Option<#ty>,
448            )
449        })
450        .collect();
451
452    let bind_obj = bind_obj.map(|expr| {
453        let bind_fields = struct_data.fields.iter().map(|field| {
454            let field_ident = field.ident.clone();
455            quote!(
456                #field_ident: Some(target.#field_ident().into()),
457            )
458        });
459
460        let target = expr;
461
462        let builder_ident = Ident::new(
463            &format!("{}Builder", target.to_token_stream()),
464            target.span(),
465        );
466
467        let default_fields = struct_data.fields.iter().map(|field| {
468            let field_ident = field.ident.clone();
469            let default_expr = field
470                .attrs
471                .iter()
472                .find(|attr| attr.path().is_ident("default"))
473                .and_then(|attr| {
474                    let Meta::NameValue(ref kv) = attr.meta else {
475                        return None;
476                    };
477
478                    let value = kv.value.clone();
479                    quote!(Some(#value)).into()
480                })
481                .unwrap_or(quote!(Some(Default::default())));
482
483            quote!(
484                #field_ident: #default_expr,
485            )
486        });
487
488        let builder_fields = struct_data.fields.iter().map(|field| {
489            let field_ident = field.ident.clone();
490            let default_expr = field
491                .attrs
492                .iter()
493                .find(|attr| attr.path().is_ident("default"))
494                .and_then(|attr| {
495                    let Meta::NameValue(ref kv) = attr.meta else {
496                        return None;
497                    };
498
499                    Some(kv.value.clone())
500                });
501
502            match default_expr {
503                Some(expr) => {
504                    quote!(
505                        .#field_ident(target.#field_ident.unwrap_or(#expr))
506                    )
507                }
508                None => {
509                    quote!(
510                        .#field_ident(target.#field_ident.unwrap_or_default())
511                    )
512                }
513            }
514        });
515
516        quote!(
517            impl From<&picea::prelude::#target> for #ident {
518                fn from(target: &picea::prelude::#target) -> Self {
519                    Self {
520                        #(#bind_fields)*
521                    }
522                }
523            }
524
525            impl From<&#ident> for picea::prelude::#builder_ident {
526                fn from(target: &#ident) -> Self {
527                    #builder_ident::new()
528                        #(#builder_fields)*
529                }
530            }
531
532            impl Default for #ident {
533                fn default() -> Self {
534                    Self {
535                        #(#default_fields)*
536                    }
537                }
538            }
539
540        )
541    });
542
543    let attrs = struct_data.attrs;
544
545    let web_config_ident = Ident::new(&format!("Web{}", ident), ident.span());
546    let optional_web_config_ident = Ident::new(&format!("OptionalWeb{}", ident), ident.span());
547
548    let field_valid_warning = {
549        let mut field_valid_warning = format!("value of {} is not valid", ident);
550        // TODO list all field and it's type
551        field_valid_warning
552    };
553
554    let ident_str = format!("{ident}");
555
556    let optional_ident_str = format!("{ident}Partial");
557
558    let vis = struct_data.vis;
559
560    quote!(
561        #(#attrs)*
562        #[derive(picea_macro_tools::Fields)]
563        #[r]
564        #[derive(Deserialize, Serialize)]
565        #vis struct #impl_generics #ident #ty_generics #where_clause {
566            #(#fields)*
567        }
568
569        impl TryInto<#ident> for #optional_web_config_ident {
570            type Error = &'static str;
571            fn try_into(self) -> Result<#ident, Self::Error> {
572                let value: JsValue = self.into();
573                let value: #ident = from_value(value).map_err(|_| {
574                  #field_valid_warning
575                })?;
576
577                Ok(value)
578            }
579        }
580
581        impl From<&#ident> for #web_config_ident {
582            fn from(target: &#ident) -> #web_config_ident {
583                serde_wasm_bindgen::to_value(&target).unwrap().into()
584            }
585        }
586
587        #[wasm_bindgen]
588        extern "C" {
589            #[wasm_bindgen(typescript_type = #ident_str)]
590            pub type #web_config_ident;
591
592            #[wasm_bindgen(typescript_type = #optional_ident_str)]
593            pub type #optional_web_config_ident;
594        }
595
596        #bind_obj
597    )
598    .into()
599}