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 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}