gd_resource_derive/
lib.rs1extern crate proc_macro;
2use proc_macro::TokenStream;
3use quote::{ format_ident, quote };
4use syn;
5
6macro_rules! field_fmt {
7 () => {
8 "_{}_field"
9 };
10}
11
12#[proc_macro_derive(GDResource)]
13pub fn derive_resource_fn(_item: TokenStream) -> TokenStream {
14 let ast = syn::parse(_item).unwrap();
15
16 return impl_macro(&ast);
17}
18
19fn impl_macro(ast: &syn::DeriveInput) -> TokenStream {
20 let name = &ast.ident;
21 let data = &ast.data;
22
23 let syn::Data::Struct(data) = data else { unimplemented!() };
24
25 let fields_names = data.fields.iter().map(|field| {
26 let field_name = &field.ident.clone().unwrap();
27 let field_final = quote::format_ident!(field_fmt!(), field_name);
28
29 quote! {
30 #field_name: #field_final,
31 }
32 });
33
34 let fields_gd_impls = data.fields.iter().map(|field| {
35 let f_name = &field.ident.clone().unwrap();
36 let ty = &field.ty;
37
38 let ident_output = format_ident!(field_fmt!(), f_name);
39
40 quote! {
41 let _res = _object_repr.get(stringify!(#f_name));
42 let _res = <#ty as FromGodot>::try_from_variant(&_res);
43 let Some(#ident_output) = _res.ok() else {
44 return Err(godot::prelude::ConvertError::new(format!("{} convert error", stringify!(#f_name))));
45 };
46 }
47 });
48
49 let fields_resource_impls = data.fields.iter().map(|field| {
50 let f_name = &field.ident.clone().unwrap();
51 let ty = &field.ty;
52
53 let ident_output = format_ident!(field_fmt!(), f_name);
54
55 quote! {
56 let _res = self.get(stringify!(#f_name));
57 let _res = <#ty as FromGodot>::try_from_variant(&_res);
58 let Some(#ident_output) = _res.ok() else {
59 return #name::default();
60 };
61 }
62 });
63
64 let fields_names_2 = fields_names.clone();
65
66 let expanded =
67 quote! {
68 impl Into<#name> for godot::prelude::Gd<godot::prelude::Resource> {
69 fn into(self) -> #name {
70 #(#fields_resource_impls)*
71
72 #name {
73 #(#fields_names_2)*
74 }
75 }
76 }
77
78 impl godot::prelude::GodotConvert for #name {
79 type Via = godot::prelude::Variant;
80 }
81
82 impl godot::prelude::FromGodot for #name {
83 fn try_from_godot (via: Self::Via) -> std::result::Result<Self, godot::prelude::ConvertError> {
84 let _object_repr: Gd<Object> = via.try_to()?;
85
86 #(#fields_gd_impls)*
87
88 Ok(Self {
89 #(#fields_names)*
90 })
91 }
92 }
93 };
94
95 expanded.into()
96}