1extern crate proc_macro;
2
3use std::collections::HashMap;
4
5use inflector::Inflector;
6use proc_macro::TokenStream;
7use quote::quote;
8use syn::parse::{Parse, ParseStream, Result};
9use syn::punctuated::Punctuated;
10use syn::{braced, parse_macro_input};
11use syn::{Error, Expr, ExprLit, Ident, Lit, LitStr, Token, Type, Visibility};
12
13mod kw {
14 syn::custom_keyword!(alias);
15 syn::custom_keyword!(brief);
16 syn::custom_keyword!(rename);
17 syn::custom_keyword!(base_traits);
18 syn::custom_keyword!(group_traits);
19 syn::custom_keyword!(extend);
20 syn::custom_keyword!(functional);
21}
22
23struct PropertyStruct {
24 functional: bool,
25 ident: Ident,
26 variants: Punctuated<PropertyVariant, Token![,]>,
27}
28
29impl Parse for PropertyStruct {
30 fn parse(input: ParseStream) -> Result<Self> {
31 let lookahead = input.lookahead1();
32 let functional = if lookahead.peek(kw::functional) {
33 input.parse::<kw::functional>()?;
34 true
35 } else {
36 false
37 };
38 let ident = input.parse()?;
39
40 let content;
41 braced!(content in input);
42 let variants = content.parse_terminated(PropertyVariant::parse)?;
43
44 Ok(PropertyStruct {
45 ident,
46 functional,
47 variants,
48 })
49 }
50}
51
52struct PropertyVariant {
53 ident: Ident,
54 ty: Type,
55}
56
57impl Parse for PropertyVariant {
58 fn parse(input: ParseStream) -> Result<Self> {
59 let ident = input.parse()?;
60 input.parse::<Token![:]>()?;
61 let ty = input.parse()?;
62 Ok(PropertyVariant { ident, ty })
63 }
64}
65
66#[proc_macro]
67pub fn complex_property(input: TokenStream) -> TokenStream {
68 let PropertyStruct {
69 ident,
70 functional,
71 variants,
72 } = parse_macro_input!(input as PropertyStruct);
73
74 let enum_variants = variants.iter().map(|variant| {
75 let ident = &variant.ident;
76 let ty = &variant.ty;
77 let singular_name = format!("{}", ident).to_pascal_case();
78 let plural_name = format!("{}", ident).to_pascal_case().to_plural();
79 let singular_ident = Ident::new(&singular_name, ident.span());
80 let plural_ident = Ident::new(&plural_name, ident.span());
81 match ty {
82 Type::TraitObject(_) => {
83 if functional {
84 quote! {
85 #singular_ident(std::boxed::Box<#ty>)
86 }
87 } else {
88 quote! {
89 #singular_ident(std::boxed::Box<#ty>),
90 #plural_ident(std::vec::Vec<std::boxed::Box<#ty>>)
91 }
92 }
93 }
94 _ => {
95 if functional {
96 quote! {
97 #singular_ident(#ty)
98 }
99 } else {
100 quote! {
101 #singular_ident(#ty),
102 #plural_ident(std::vec::Vec<#ty>)
103 }
104 }
105 }
106 }
107 });
108
109 let from_impls = variants.iter().map(|variant| {
163 let enum_ident = &ident;
164 let ident = &variant.ident;
165 let ty = &variant.ty;
166 let singular_name = format!("{}", ident).to_pascal_case();
167 let plural_name = format!("{}", ident).to_pascal_case().to_plural();
168 let singular_ident = Ident::new(&singular_name, ident.span());
169 let plural_ident = Ident::new(&plural_name, ident.span());
170 match ty {
171 Type::TraitObject(_) => {
172 if functional {
173 quote! {
174 impl From<std::boxed::Box<#ty>> for #enum_ident {
175 fn from(value: std::boxed::Box<#ty>) -> Self {
176 Self::#singular_ident(value)
177 }
178 }
179 }
180 } else {
181 quote! {
182 impl From<std::boxed::Box<#ty>> for #enum_ident {
183 fn from(value: std::boxed::Box<#ty>) -> Self {
184 Self::#singular_ident(value)
185 }
186 }
187 impl From<std::vec::Vec<std::boxed::Box<#ty>>> for #enum_ident {
188 fn from(value: std::vec::Vec<std::boxed::Box<#ty>>) -> Self {
189 Self::#plural_ident(value)
190 }
191 }
192 }
193 }
194 }
195 _ => {
196 if functional {
197 quote! {
198 impl std::convert::From<#ty> for #enum_ident {
199 fn from(value: #ty) -> Self {
200 Self::#singular_ident(value)
201 }
202 }
203 }
204 } else {
205 quote! {
206 impl std::convert::From<#ty> for #enum_ident {
207 fn from(value: #ty) -> Self {
208 Self::#singular_ident(value)
209 }
210 }
211 impl std::convert::From<std::vec::Vec<#ty>> for #enum_ident {
212 fn from(values: std::vec::Vec<#ty>) -> Self {
213 Self::#plural_ident(values)
214 }
215 }
216 }
217 }
218 }
219 }
220 });
221
222 let expanded = quote! {
223 #[derive(std::clone::Clone, std::fmt::Debug, serde::Serialize, serde::Deserialize)]
224 #[serde(untagged)]
225 pub enum #ident {
226 None,
227 #(#enum_variants,)*
228 }
229
230 impl Default for #ident {
235 fn default() -> Self {
236 Self::None
237 }
238 }
239
240 impl ActivitypubProperty for #ident {
241 fn is_none(&self) -> bool {
242 match self {
243 #ident::None => true,
244 _ => false,
245 }
246 }
247
248 fn is_some(&self) -> bool {
249 match self {
250 #ident::None => false,
251 _ => true,
252 }
253 }
254 }
255
256 #(#from_impls)*
257 };
258 expanded.into()
259}
260
261struct ActivitypubProperty {
263 visibility: Visibility,
264 name: Ident,
265 functional: bool,
266 possible_ty: Punctuated<Ident, Token![,]>,
267}
268
269impl Parse for ActivitypubProperty {
270 fn parse(input: ParseStream) -> Result<Self> {
271 let visibility = input.parse()?;
272 let name = input.parse()?;
273 input.parse::<Token![,]>()?;
274 let functional_expr: Expr = input.parse()?;
275 input.parse::<Token![,]>()?;
276 let possible_ty = input.parse_terminated(Ident::parse)?;
277
278 let functional = if let Expr::Lit(ExprLit {
279 lit: Lit::Bool(b), ..
280 }) = functional_expr
281 {
282 b.value
283 } else {
284 return Err(Error::new_spanned(
285 functional_expr,
286 "expected true or false",
287 ));
288 };
289
290 Ok(ActivitypubProperty {
291 visibility,
292 name,
293 possible_ty,
294 functional,
295 })
296 }
297}
298
299#[proc_macro]
301pub fn activitypub_property(input: TokenStream) -> TokenStream {
302 activitypub_property_vec(input)
303}
304
305#[proc_macro]
306pub fn activitypub_property_vec(input: TokenStream) -> TokenStream {
307 let ActivitypubProperty {
308 visibility,
309 name,
310 possible_ty,
311 functional,
312 } = parse_macro_input!(input as ActivitypubProperty);
313
314 let variants = possible_ty.iter().map(|ty| {
315 let singular_name = format!("{}", ty).to_pascal_case();
316 let plural_name = format!("{}", ty).to_pascal_case().to_plural();
317 let singular_ident = Ident::new(&singular_name, ty.span());
318 let plural_ident = Ident::new(&plural_name, ty.span());
319 if functional {
320 quote! {
321 #singular_ident(Box<#ty>)
322 }
323 } else {
324 quote! {
325 #singular_ident(Box<#ty>),
326 #plural_ident(Vec<#ty>)
327 }
328 }
329 });
330
331 let constructors = possible_ty.iter().map(|ty| {
332 let singular_name = format!("{}", ty).to_pascal_case();
333 let plural_name = format!("{}", ty).to_pascal_case().to_plural();
334 let singular_ident = Ident::new(&singular_name, ty.span());
335 let plural_ident = Ident::new(&plural_name, ty.span());
336
337 let singular_constructor_name = format!("{}", ty).to_snake_case();
338 let plural_constructor_name = format!("{}", ty).to_snake_case().to_plural();
339 let singular_constructor_ident = Ident::new(&singular_constructor_name, ty.span());
340 let plural_constructor_ident = Ident::new(&plural_constructor_name, ty.span());
341 if functional {
342 quote! {
343 #visibility fn #singular_constructor_ident(value: #ty) -> Self {
344 Self::#singular_ident(Box::new(value))
345 }
346 }
347 } else {
348 quote! {
349 #visibility fn #singular_constructor_ident(value: #ty) -> Self {
350 Self::#singular_ident(Box::new(value))
351 }
352 #visibility fn #plural_constructor_ident(values: Vec<#ty>) -> Self {
353 Self::#plural_ident(values)
354 }
355 }
356 }
357 });
358
359 let expanded = quote! {
360 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
361 #[serde(untagged)]
362 #visibility enum #name {
363 None,
364 #(#variants,)*
365 }
366
367 impl #name {
368 #(#constructors)*
369 }
370
371 impl Default for #name {
372 fn default() -> Self {
373 Self::None
374 }
375 }
376
377 impl ActivitypubProperty for #name {
378 fn is_none(&self) -> bool {
379 self == &Self::None
380 }
381
382 fn is_some(&self) -> bool {
383 self != &Self::None
384 }
385 }
386 };
387
388 expanded.into()
389}
390
391#[proc_macro]
392pub fn activitypub_property_hashmap(input: TokenStream) -> TokenStream {
393 let ActivitypubProperty {
394 visibility,
395 name,
396 possible_ty,
397 functional,
398 } = parse_macro_input!(input as ActivitypubProperty);
399
400 let variants = possible_ty.iter().map(|ty| {
401 let singular_name = format!("{}", ty).to_pascal_case();
402 let plural_name = format!("{}", ty).to_pascal_case().to_plural();
403 let singular_ident = Ident::new(&singular_name, ty.span());
404 let plural_ident = Ident::new(&plural_name, ty.span());
405 if functional {
406 quote! {
407 #singular_ident(Box<#ty>)
408 }
409 } else {
410 quote! {
411 #singular_ident(Box<#ty>),
412 #plural_ident(HashMap<String, #ty>)
413 }
414 }
415 });
416
417 let constructors = possible_ty.iter().map(|ty| {
418 let singular_name = format!("{}", ty).to_pascal_case();
419 let plural_name = format!("{}", ty).to_pascal_case().to_plural();
420 let singular_ident = Ident::new(&singular_name, ty.span());
421 let plural_ident = Ident::new(&plural_name, ty.span());
422
423 let singular_constructor_name = format!("{}", ty).to_snake_case();
424 let plural_constructor_name = format!("{}", ty).to_snake_case().to_plural();
425 let singular_constructor_ident = Ident::new(&singular_constructor_name, ty.span());
426 let plural_constructor_ident = Ident::new(&plural_constructor_name, ty.span());
427 if functional {
428 quote! {
429 #visibility fn #singular_constructor_ident(value: #ty) -> Self {
430 Self::#singular_ident(Box::new(value))
431 }
432 }
433 } else {
434 quote! {
435 #visibility fn #singular_constructor_ident(value: #ty) -> Self {
436 Self::#singular_ident(Box::new(value))
437 }
438 #visibility fn #plural_constructor_ident(values: HashMap<String, #ty>) -> Self {
439 Self::#plural_ident(values)
440 }
441 }
442 }
443 });
444
445 let expanded = quote! {
446 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
447 #[serde(untagged)]
448 #visibility enum #name {
449 None,
450 #(#variants,)*
451 }
452
453 impl #name {
454 #(#constructors)*
455 }
456
457 impl Default for #name {
458 fn default() -> Self {
459 Self::None
460 }
461 }
462
463 impl ActivitypubProperty for #name {
464 fn is_none(&self) -> bool {
465 self == &Self::None
466 }
467
468 fn is_some(&self) -> bool {
469 self != &Self::None
470 }
471 }
472 };
473
474 expanded.into()
475}
476
477struct ActivitypubStruct {
478 visibility: Visibility,
479 ident: Ident,
480 fields: Punctuated<ActivitypubField, Token![,]>,
481 brief: ActivitypubField,
482}
483
484#[derive(Clone)]
485struct ActivitypubField {
486 visibility: Visibility,
487 ident: Ident,
488 alias: Option<LitStr>,
489 rename: Option<LitStr>,
490 ty: Type,
491}
492
493impl Parse for ActivitypubStruct {
494 fn parse(input: ParseStream) -> Result<Self> {
495 let content;
496 let visibility = input.parse()?;
497 input.parse::<Token![struct]>()?;
498 let ident = input.parse()?;
499 braced!(content in input);
500 let fields = content.parse_terminated(ActivitypubField::parse)?;
501 input.parse::<kw::brief>()?;
502 let brief_ident: Ident = input.parse()?;
503 let brief = fields
504 .iter()
505 .find(|field| field.ident.to_string() == brief_ident.to_string())
506 .unwrap()
507 .clone();
508
509 Ok(ActivitypubStruct {
510 visibility,
511 ident,
512 fields,
513 brief,
514 })
515 }
516}
517
518impl Parse for ActivitypubField {
519 fn parse(input: ParseStream) -> Result<Self> {
520 let visibility = input.parse()?;
521 let ident = input.parse()?;
522 let lookahead = input.lookahead1();
526 let (alias, rename) = if lookahead.peek(kw::alias) {
527 input.parse::<kw::alias>()?;
528 (Some(input.parse()?), None)
529 } else if lookahead.peek(kw::rename) {
530 input.parse::<kw::rename>()?;
531 (None, Some(input.parse()?))
532 } else {
533 (None, None)
534 };
535
536 input.parse::<Token![:]>()?;
537
538 Ok(ActivitypubField {
539 visibility,
540 ident,
541 alias,
542 rename,
543 ty: input.parse()?,
544 })
545 }
546}
547
548#[proc_macro]
549pub fn activitypub_core(input: TokenStream) -> TokenStream {
550 let ActivitypubStruct {
551 visibility,
552 ident,
553 fields,
554 brief,
555 } = parse_macro_input!(input as ActivitypubStruct);
556
557 let struct_fields = fields.iter().map(|field| {
558 let visibility = &field.visibility;
559 let ident = &field.ident;
560 let ty = &field.ty;
561 if let Some(alias) = &field.alias {
562 quote! {
563 #[serde(alias = #alias)]
564 #visibility #ident: #ty
565 }
566 } else if let Some(rename) = &field.rename {
567 quote! {
568 #[serde(rename = #rename)]
569 #visibility #ident: #ty
570 }
571 } else {
572 quote! {
573 #visibility #ident: #ty
574 }
575 }
576 });
577
578 let enum_fields = fields.iter().map(|field| {
579 let ident = &field.ident;
580 let ty = &field.ty;
581 if let Some(alias) = &field.alias {
582 quote! {
583 #[serde(alias = #alias, skip_serializing_if = "ActivitypubProperty::is_none", default)]
584 #ident: #ty
585 }
586 } else if let Some(rename) = &field.rename {
587 quote! {
588 #[serde(rename = #rename, skip_serializing_if = "ActivitypubProperty::is_none", default)]
589 #ident: #ty
590 }
591 } else {
592 quote! {
593 #[serde(skip_serializing_if = "ActivitypubProperty::is_none", default)]
594 #ident: #ty
595 }
596 }
597 });
598
599 let enum_ident_string = format!("{}Enum", ident);
600 let enum_ident = Ident::new(&enum_ident_string, ident.span());
601 let builder_ident = Ident::new(&format!("{}Builder", ident), ident.span());
602 let brief_ident = &brief.ident;
603 let brief_ty = &brief.ty;
604
605 let from_enum_fields = fields.iter().map(|field| {
606 let ident = &field.ident;
607 quote! { #ident }
608 });
609
610 let from_enum_fields2 = fields.iter().map(|field| {
611 let ident = &field.ident;
612 quote! { #ident }
613 });
614
615 let from_struct_fields = fields.iter().map(|field| {
616 let ident = &field.ident;
617 if ident.to_string() != brief_ident.to_string() {
618 quote! { && struct_value.#ident.is_none() }
619 } else {
620 quote! {}
621 }
622 });
623
624 let from_struct_fields2 = fields.iter().map(|field| {
625 let ident = &field.ident;
626 quote! { #ident: struct_value.#ident }
627 });
628
629 let expanded = quote! {
630 #[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize, derive_builder::Builder)]
631 #[serde(rename_all = "camelCase", from = #enum_ident_string, into = #enum_ident_string)]
632 #[builder(default, setter(strip_option))]
633 #visibility struct #ident {
634 #(#struct_fields,)*
635 }
636
637 #[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
638 #[serde(untagged)]
639 #visibility enum #enum_ident {
640 Brief(String),
641 #[serde(rename_all = "camelCase")]
642 Full {
643 #(#enum_fields,)*
644 },
645 }
646
647 impl From<#enum_ident> for #ident {
648 fn from(enum_value: #enum_ident) -> Self {
649 match enum_value {
650 #enum_ident::Brief(#brief_ident) => #builder_ident::default()
651 .#brief_ident(#brief_ty::String(Box::new(#brief_ident)))
652 .build()
653 .unwrap(),
654 #enum_ident::Full {
655 #(#from_enum_fields,)*
656 } => {
657 #ident {
658 #(#from_enum_fields2,)*
659 }
660 },
661 }
662 }
663 }
664
665 impl From<#ident> for #enum_ident {
666 fn from(struct_value: #ident) -> Self {
667 if struct_value.#brief_ident.is_some()
668 #(#from_struct_fields)* {
669 match struct_value.#brief_ident {
670 #brief_ty::String(#brief_ident) => #enum_ident::Brief(#brief_ident.to_string()),
671 _ => unreachable!(),
672 }
673 } else {
674 #enum_ident::Full {
675 #(#from_struct_fields2,)*
676 }
677 }
678 }
679 }
680 };
681
682 expanded.into()
683}
684
685struct ComplexStruct {
686 base_traits: Punctuated<Ident, Token![,]>,
687 group_traits: Punctuated<GroupTrait, Token![,]>,
688 type_groups: Punctuated<TypeGroup, Token![,]>,
689}
690
691impl Parse for ComplexStruct {
692 fn parse(input: ParseStream) -> Result<Self> {
693 input.parse::<kw::base_traits>()?;
694
695 let content;
696 braced!(content in input);
697 let base_traits = content.parse_terminated(Ident::parse)?;
698
699 input.parse::<kw::group_traits>()?;
700 let content;
701 braced!(content in input);
702 let group_traits = content.parse_terminated(GroupTrait::parse)?;
703
704 let type_groups = input.parse_terminated(TypeGroup::parse)?;
705
706 Ok(ComplexStruct {
707 base_traits,
708 group_traits,
709 type_groups,
710 })
711 }
712}
713
714struct GroupTrait {
715 ident: Ident,
716 parent: Ident,
717}
718
719impl Parse for GroupTrait {
720 fn parse(input: ParseStream) -> Result<Self> {
721 let ident = input.parse()?;
722 input.parse::<Token![:]>()?;
723 let parent = input.parse()?;
724
725 Ok(GroupTrait { ident, parent })
726 }
727}
728
729struct TypeGroup {
730 ident: Ident,
731 types: Punctuated<TypeDefinition, Token![,]>,
732}
733
734impl Parse for TypeGroup {
735 fn parse(input: ParseStream) -> Result<Self> {
736 let ident = input.parse()?;
737
738 let content;
739 braced!(content in input);
740 let types = content.parse_terminated(TypeDefinition::parse)?;
741
742 Ok(TypeGroup { ident, types })
743 }
744}
745
746#[derive(Clone)]
747struct TypeDefinition {
748 ident: Ident,
749 parent: Option<Ident>,
750 fields: Punctuated<TypeField, Token![,]>,
751}
752
753impl Parse for TypeDefinition {
754 fn parse(input: ParseStream) -> Result<Self> {
755 let ident = input.parse()?;
756
757 let lookahead = input.lookahead1();
758 let parent = if lookahead.peek(kw::extend) {
759 input.parse::<kw::extend>()?;
760 Some(input.parse()?)
761 } else {
762 None
763 };
764
765 let content;
766 braced!(content in input);
767 let fields = content.parse_terminated(TypeField::parse)?;
768
769 Ok(TypeDefinition {
770 ident,
771 parent,
772 fields,
773 })
774 }
775}
776
777#[derive(Clone)]
778struct TypeField {
779 ident: Ident,
780 alias: Option<LitStr>,
781 rename: Option<LitStr>,
782 ty: Type,
783}
784
785impl Parse for TypeField {
786 fn parse(input: ParseStream) -> Result<Self> {
787 let ident = input.parse()?;
788
789 let lookahead = input.lookahead1();
790 let (alias, rename) = if lookahead.peek(kw::alias) {
791 input.parse::<kw::alias>()?;
792 (Some(input.parse()?), None)
793 } else if lookahead.peek(kw::rename) {
794 input.parse::<kw::rename>()?;
795 (None, Some(input.parse()?))
796 } else {
797 (None, None)
798 };
799
800 input.parse::<Token![:]>()?;
801 let ty = input.parse()?;
802
803 Ok(TypeField {
804 ident,
805 alias,
806 rename,
807 ty,
808 })
809 }
810}
811
812#[derive(Clone)]
813struct FullTypeDefinition {
814 ident: Ident,
815 fields: Vec<TypeField>,
816}
817
818#[proc_macro]
819pub fn activitypub_complex(input: TokenStream) -> TokenStream {
820 let ComplexStruct {
821 base_traits,
822 group_traits,
823 type_groups,
824 } = parse_macro_input!(input as ComplexStruct);
825
826 let base_trait_defs = base_traits.iter().map(|base_trait| {
840 quote! {
841 #[typetag::serde(tag = "type")]
842 pub trait #base_trait: std::fmt::Debug {
843 fn any_ref(&self) -> &dyn std::any::Any;
844 fn kind(&self) -> &str;
845 fn box_clone(&self) -> Box<dyn #base_trait>;
846 }
847
848 impl std::clone::Clone for Box<dyn #base_trait> {
849 fn clone(&self) -> Box<dyn #base_trait> {
850 self.box_clone()
851 }
852 }
853 }
854 });
855
856 let group_trait_defs = group_traits.iter().map(|group_trait| {
858 let ident = &group_trait.ident;
859 quote! {
861 #[typetag::serde(tag = "type")]
862 pub trait #ident: std::fmt::Debug {
863 fn any_ref(&self) -> &dyn std::any::Any;
864 fn box_clone(&self) -> Box<dyn #ident>;
865 }
866
867 impl std::clone::Clone for Box<dyn #ident> {
868 fn clone(&self) -> Box<dyn #ident> {
869 self.box_clone()
870 }
871 }
872 }
873 });
874
875 let mut type_definitions: HashMap<Ident, TypeDefinition> = HashMap::new();
877 let mut full_type_definitions: HashMap<Ident, FullTypeDefinition> = HashMap::new();
878
879 for type_group in type_groups.iter() {
880 for type_definition in type_group.types.iter() {
881 type_definitions.insert(type_definition.ident.clone(), type_definition.clone());
882 }
883 }
884
885 while !type_definitions.is_empty() {
886 let temp_type_definitions = type_definitions.clone();
887 let keys = temp_type_definitions.keys();
888 for key in keys {
889 let type_definition = type_definitions.get(key).unwrap();
890 let mut full_type_definition = FullTypeDefinition {
891 ident: type_definition.ident.clone(),
892 fields: type_definition
893 .fields
894 .iter()
895 .map(|type_field| type_field.clone())
896 .collect(),
897 };
898 if let Some(parent) = &type_definition.parent {
900 if let Some(parent_definition) = full_type_definitions.get(parent) {
902 let parent_fields = parent_definition.fields.clone();
903 full_type_definition.fields.extend(parent_fields);
904 full_type_definitions
905 .insert(full_type_definition.ident.clone(), full_type_definition);
906 type_definitions.remove(key);
907 } } else {
909 full_type_definitions
911 .insert(full_type_definition.ident.clone(), full_type_definition);
912 type_definitions.remove(key);
913 }
914 }
915 }
916
917 let group_trait_dyn_impls = type_groups.iter().map(|type_group| {
919 let ident = &type_group.ident;
920 let as_methods = type_group.types.iter().map(|type_definition| {
921 let ident = &type_definition.ident;
922 let method_name = format!("as_{}", ident).to_snake_case();
923 let as_method_ident = Ident::new(&method_name, ident.span());
924 quote! {
925 pub fn #as_method_ident(&self) -> std::option::Option<&#ident> {
926 self.downcast_ref::<#ident>()
927 }
928 }
929 });
930 quote! {
931 impl dyn #ident {
932 pub fn downcast_ref<T: std::any::Any>(&self) -> std::option::Option<&T> {
933 self.any_ref().downcast_ref()
934 }
935 #(#as_methods)*
936 }
937 }
938 });
939
940 let type_defs = full_type_definitions
942 .iter()
943 .map(|(ident, full_type_definition)| {
944 let struct_fields = full_type_definition.fields.iter().map(|type_field| {
945 let ident = &type_field.ident;
946 let ty = &type_field.ty;
947 if let Some(alias) = &type_field.alias {
948 quote! {
949 #[serde(alias = #alias)]
950 pub #ident: #ty
951 }
952 } else if let Some(rename) = &type_field.rename {
953 quote! {
954 #[serde(rename = #rename)]
955 pub #ident: #ty
956 }
957 } else {
958 quote! {
959 pub #ident: #ty
960 }
961 }
962 });
963 let enum_fields = full_type_definition.fields.iter().map(|type_field| {
964 let ident = &type_field.ident;
965 let ty = &type_field.ty;
966 if let Some(alias) = &type_field.alias {
967 quote! {
968 #[serde(alias = #alias, skip_serializing_if = "ActivitypubProperty::is_none", default)]
969 #ident: #ty
970 }
971 } else if let Some(rename) = &type_field.rename {
972 quote! {
973 #[serde(rename = #rename, skip_serializing_if = "ActivitypubProperty::is_none", default)]
974 #ident: #ty
975 }
976 } else {
977 quote! {
978 #[serde(skip_serializing_if = "ActivitypubProperty::is_none", default)]
979 #ident: #ty
980 }
981 }
982 });
983 let enum_ident_string = format!("{}Enum", ident);
984 let enum_ident = Ident::new(&enum_ident_string, ident.span());
985 quote! {
986 #[derive(std::clone::Clone, std::fmt::Debug, std::default::Default, serde::Deserialize, serde::Serialize, derive_builder::Builder)]
987 #[serde(rename_all = "camelCase", from = #enum_ident_string, into = #enum_ident_string)]
988 #[builder(default, setter(into))]
989 pub struct #ident {
990 #(#struct_fields,)*
991 }
992
993 #[derive(std::clone::Clone, std::fmt::Debug, serde::Deserialize, serde::Serialize)]
994 #[serde(untagged)]
995 pub enum #enum_ident {
996 Brief(String),
997 #[serde(rename_all = "camelCase")]
998 Full {
999 #(#enum_fields,)*
1000 },
1001 }
1002 }
1003 });
1004
1005 let mut base_to_group_traits: HashMap<Ident, Vec<Ident>> = HashMap::new();
1009 let mut group_to_base_traits: HashMap<Ident, Ident> = HashMap::new();
1010 for group_trait in group_traits.iter() {
1011 group_to_base_traits.insert(group_trait.ident.clone(), group_trait.parent.clone());
1012 if base_to_group_traits.contains_key(&group_trait.parent) {
1013 base_to_group_traits
1014 .get_mut(&group_trait.parent)
1015 .unwrap()
1016 .push(group_trait.ident.clone());
1017 } else {
1018 base_to_group_traits
1019 .insert(group_trait.parent.clone(), vec![group_trait.ident.clone()]);
1020 }
1021 }
1022
1023 let trait_impls = type_groups.iter().map(|type_group| {
1024 let group_ident = &type_group.ident;
1025 let base_ident = group_to_base_traits.get(group_ident).unwrap();
1026 let type_trait_impls = type_group.types.iter().map(|type_definition| {
1027 let ident = &type_definition.ident;
1028 let kind = format!("{}", ident);
1029 quote! {
1030 #[typetag::serde]
1031 impl #base_ident for #ident {
1032 fn any_ref(&self) -> &dyn std::any::Any {
1033 self
1034 }
1035 fn kind(&self) -> &str {
1036 #kind
1037 }
1038 fn box_clone(&self) -> Box<dyn #base_ident> {
1039 Box::new((*self).clone())
1040 }
1041 }
1042 #[typetag::serde]
1043 impl #group_ident for #ident {
1044 fn any_ref(&self) -> &dyn std::any::Any {
1045 self
1046 }
1047 fn box_clone(&self) -> Box<dyn #group_ident> {
1048 Box::new((*self).clone())
1049 }
1050 }
1051 }
1052 });
1053 quote! {
1054 #(#type_trait_impls)*
1055 }
1056 });
1057
1058 let from_impls = full_type_definitions
1060 .iter()
1061 .map(|(ident, full_type_definition)| {
1062 let enum_ident_string = format!("{}Enum", ident);
1063 let enum_ident = Ident::new(&enum_ident_string, ident.span());
1064 let builder_ident = Ident::new(&format!("{}Builder", ident), ident.span());
1065 let brief_ident = match &full_type_definition.ident.to_string()[..] {
1066 "Link" | "Mention" => Ident::new("href", full_type_definition.ident.span()),
1067 _ => Ident::new("id", full_type_definition.ident.span()),
1068 };
1069
1070 let brief = full_type_definition
1071 .fields
1072 .iter()
1073 .find(|type_field| type_field.ident.to_string() == brief_ident.to_string())
1074 .unwrap()
1075 .clone();
1076 let brief_ident = &brief.ident;
1077 let brief_ty = &brief.ty;
1078
1079 let from_enum_fields = full_type_definition.fields.iter().map(|type_field| {
1080 let ident = &type_field.ident;
1081 quote! { #ident }
1082 });
1083
1084 let from_enum_fields2 = full_type_definition.fields.iter().map(|type_field| {
1085 let ident = &type_field.ident;
1086 quote! { #ident }
1087 });
1088
1089 let from_struct_fields = full_type_definition.fields.iter().map(|type_field| {
1090 let ident = &type_field.ident;
1091 if ident.to_string() != brief_ident.to_string() {
1092 quote! { && struct_value.#ident.is_none() }
1093 } else {
1094 quote! {}
1095 }
1096 });
1097
1098 let from_struct_fields2 = full_type_definition.fields.iter().map(|type_field| {
1099 let ident = &type_field.ident;
1100 quote! { #ident: struct_value.#ident }
1101 });
1102
1103 quote! {
1104 impl From<#enum_ident> for #ident {
1105 fn from(enum_value: #enum_ident) -> Self {
1106 match enum_value {
1107 #enum_ident::Brief(#brief_ident) => #builder_ident::default()
1108 .#brief_ident(#brief_ty::String(#brief_ident))
1109 .build()
1110 .unwrap(),
1111 #enum_ident::Full {
1112 #(#from_enum_fields,)*
1113 } => {
1114 #ident {
1115 #(#from_enum_fields2,)*
1116 }
1117 },
1118 }
1119 }
1120 }
1121
1122 impl From<#ident> for #enum_ident {
1123 fn from(struct_value: #ident) -> Self {
1124 if struct_value.#brief_ident.is_some()
1125 #(#from_struct_fields)* {
1126 match struct_value.#brief_ident {
1127 #brief_ty::String(#brief_ident) => #enum_ident::Brief(#brief_ident),
1128 _ => unreachable!(),
1129 }
1130 } else {
1131 #enum_ident::Full {
1132 #(#from_struct_fields2,)*
1133 }
1134 }
1135 }
1136 }
1137 }
1138 });
1139
1140 let expanded = quote! {
1141 #(#base_trait_defs)*
1142 #(#group_trait_defs)*
1143 #(#group_trait_dyn_impls)*
1144 #(#type_defs)*
1145 #(#trait_impls)*
1146 #(#from_impls)*
1147 };
1148 expanded.into()
1149}