spottedcat_ecs_macro/
lib.rs1
2use proc_macro::TokenStream;
3use quote::{quote};
4use syn::{
5 DeriveInput,
6 Ident,
7 Field,
8};
9
10#[proc_macro_attribute]
11pub fn component(_attr: TokenStream, item: TokenStream) -> TokenStream {
12 let mut ast = syn::parse_macro_input!(item as DeriveInput);
13 impl_component(&mut ast)
14}
15
16fn impl_component(ast: &mut syn::DeriveInput) -> TokenStream {
17 let name = &ast.ident;
18 let inner_name = Ident::new(&format!("{}Inner", name), name.span());
19
20 let has_derive_default = ast.attrs.iter()
21 .filter(|attr| attr.path.is_ident("derive"))
22 .flat_map(|attr| match attr.parse_meta() {
23 Ok(syn::Meta::List(list)) => Some(list.nested.into_iter().collect::<Vec<_>>()),
24 _ => None
25 })
26 .flatten()
27 .any(|nested_meta| {
28 if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = nested_meta {
29 path.is_ident("Default")
30 } else {
31 false
32 }
33 });
34
35 if !has_derive_default {
36 return syn::Error::new_spanned(
37 ast,
38 "#[component] requires #[derive(Default)]",
39 )
40 .to_compile_error()
41 .into();
42 }
43
44 let fields = match &ast.data {
46 syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(fields), .. }) => {
47 &fields.named
48 }
49 _ => {
50 return syn::Error::new_spanned(
51 ast,
52 "#[component] can only be used on structs with named fields",
53 )
54 .to_compile_error()
55 .into();
56 }
57 };
58
59 let inner_fields = fields.iter().map(|f| {
61 let Field { ident, ty, .. } = f;
62 quote! {
63 pub #ident: #ty
64 }
65 });
66
67 let getter_setter_methods = fields.iter().map(|f| {
69 let name = f.ident.as_ref().unwrap();
70 let ty = &f.ty;
71 let get_name = Ident::new(&format!("get_{}", name), name.span());
72 let set_name = Ident::new(&format!("set_{}", name), name.span());
73
74 quote! {
75 pub fn #get_name(&self) -> Result<#ty, std::cell::BorrowError> {
76 match self.inner.try_borrow() {
77 Ok(borrowed) => Ok(borrowed.#name.clone()),
78 Err(e) => Err(e)
79 }
80 }
81 pub fn #set_name(&self, value: #ty) -> Result<(), std::cell::BorrowMutError> {
82 match self.inner.try_borrow_mut() {
83 Ok(mut borrowed) => {
84 borrowed.#name = value;
85 Ok(())
86 }
87 Err(e) => Err(e)
88 }
89 }
90 }
91 });
92
93 let attrs = ast.attrs.iter()
95 .filter(|attr| !attr.path.is_ident("component"))
96 .cloned()
97 .collect::<Vec<_>>();
98
99 let expanded = quote! {
100 #(#attrs)*
101 pub struct #inner_name {
102 #(#inner_fields),*
103 }
104
105 #(#attrs)*
106 pub struct #name {
107 inner: std::sync::Arc<std::cell::RefCell<#inner_name>>,
108 }
109
110 impl #name {
111 pub fn new() -> Self {
112 let inner = #inner_name::default();
113 Self {
114 inner: std::sync::Arc::new(std::cell::RefCell::new(inner)),
115 }
116 }
117
118 #(#getter_setter_methods)*
119 }
120
121 impl Component for #name {
122 fn get_type_id(&self) -> std::any::TypeId {
123 std::any::TypeId::of::<Self>()
124 }
125 }
126 };
127
128 expanded.into()
129}