1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput, Item, ItemImpl, ItemStruct};
4
5mod function_wrapper;
6mod method_wrapper;
7
8#[proc_macro_derive(RustValue)]
9pub fn derive_rust_value(input: TokenStream) -> TokenStream {
10 let input = parse_macro_input!(input as DeriveInput);
11 let name = &input.ident;
12
13 let expanded = quote! {
14 impl crate::core::value::RustValue for #name {
15 fn type_name(&self) -> &'static str {
16 stringify!(#name)
17 }
18 }
19 };
20
21 TokenStream::from(expanded)
22}
23
24#[proc_macro]
25pub fn rustleaf_tests(_input: TokenStream) -> TokenStream {
26 TokenStream::new()
27}
28
29#[proc_macro_attribute]
30pub fn rust_value_any(_args: TokenStream, input: TokenStream) -> TokenStream {
31 let input = parse_macro_input!(input as ItemImpl);
32
33 let as_any_methods = quote! {
35 fn as_any(&self) -> &dyn std::any::Any {
36 self
37 }
38
39 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
40 self
41 }
42 };
43
44 let ItemImpl {
46 attrs,
47 defaultness,
48 unsafety,
49 impl_token,
50 generics,
51 trait_,
52 self_ty,
53 brace_token: _,
54 items,
55 } = input;
56
57 let expanded = if let Some((bang, path, for_token)) = trait_ {
59 quote! {
60 #(#attrs)*
61 #defaultness #unsafety #impl_token #generics #bang #path #for_token #self_ty {
62 #as_any_methods
63
64 #(#items)*
65 }
66 }
67 } else {
68 quote! {
70 #(#attrs)*
71 #defaultness #unsafety #impl_token #generics #self_ty {
72 #as_any_methods
73
74 #(#items)*
75 }
76 }
77 };
78
79 TokenStream::from(expanded)
80}
81
82#[proc_macro_derive(RustLeafWrapper, attributes(core_type))]
83pub fn derive_rustleaf_wrapper(input: TokenStream) -> TokenStream {
84 let input = parse_macro_input!(input as DeriveInput);
85 let wrapper_name = &input.ident;
86
87 let core_type = input
89 .attrs
90 .iter()
91 .find_map(|attr| {
92 if attr.path().is_ident("core_type") {
93 attr.parse_args::<syn::Type>().ok()
94 } else {
95 None
96 }
97 })
98 .expect("RustLeafWrapper requires #[core_type(Type)] attribute");
99
100 let expanded = quote! {
101 impl #wrapper_name {
102 pub fn new(inner: #core_type) -> Self {
103 Self(std::rc::Rc::new(std::cell::RefCell::new(inner)))
104 }
105
106 pub fn borrow(&self) -> std::cell::Ref<#core_type> {
107 self.0.borrow()
108 }
109
110 pub fn borrow_mut(&self) -> std::cell::RefMut<#core_type> {
111 self.0.borrow_mut()
112 }
113 }
114 };
115
116 TokenStream::from(expanded)
117}
118
119#[proc_macro_attribute]
120pub fn rustleaf(_args: TokenStream, input: TokenStream) -> TokenStream {
121 let input = parse_macro_input!(input as Item);
122
123 match input {
124 Item::Struct(item_struct) => rustleaf_struct(item_struct),
125 Item::Impl(item_impl) => method_wrapper::rustleaf_impl(item_impl),
126 Item::Fn(item_fn) => function_wrapper::rustleaf_fn(item_fn),
127 _ => {
128 panic!("rustleaf attribute can only be applied to structs, impl blocks, and functions")
129 }
130 }
131}
132
133fn rustleaf_struct(input: ItemStruct) -> TokenStream {
134 let struct_name = &input.ident;
135 let ref_name = quote::format_ident!("{}Ref", struct_name);
136
137 let original_struct = quote! {
139 #input
140 };
141
142 let wrapper_struct = quote! {
144 #[derive(Debug, Clone, RustLeafWrapper)]
146 #[core_type(#struct_name)]
147 pub struct #ref_name(std::rc::Rc<std::cell::RefCell<#struct_name>>);
148 };
149
150 let rust_value_impl = generate_trivial_rust_value_impl(&ref_name, struct_name);
152
153 let get_property_impl = generate_get_property_impl(&ref_name, &input);
155
156 let borrow_value_impl = generate_borrow_value_impl(struct_name, &ref_name);
158
159 let expanded = quote! {
160 #original_struct
161
162 #wrapper_struct
163
164 #rust_value_impl
165
166 #get_property_impl
167
168 #borrow_value_impl
169 };
170
171 TokenStream::from(expanded)
172}
173
174fn generate_trivial_rust_value_impl(
175 ref_name: &syn::Ident,
176 struct_name: &syn::Ident,
177) -> proc_macro2::TokenStream {
178 let struct_name_str = struct_name.to_string();
179
180 quote! {
181 impl rustleaf::core::RustValue for #ref_name {
182 fn as_any(&self) -> &dyn std::any::Any {
183 self
184 }
185
186 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
187 self
188 }
189
190 fn dyn_clone(&self) -> Box<dyn rustleaf::core::RustValue> {
191 Box::new(self.clone())
192 }
193
194 fn type_name(&self) -> Option<&str> {
195 Some(#struct_name_str)
196 }
197
198 fn str(&self) -> String {
199 format!("{:?}", self.borrow())
201 }
202
203 fn get_attr(&self, name: &str) -> Option<rustleaf::core::Value> {
204 if let Some(value) = self.get_property(name) {
206 return Some(value);
207 }
208
209 self.get_method(name)
211 }
212 }
213 }
214}
215
216fn generate_get_property_impl(
217 ref_name: &syn::Ident,
218 input: &ItemStruct,
219) -> proc_macro2::TokenStream {
220 let mut field_arms = Vec::new();
221
222 if let syn::Fields::Named(named_fields) = &input.fields {
224 for field in &named_fields.named {
225 if let Some(field_name) = &field.ident {
226 if matches!(field.vis, syn::Visibility::Public(_)) {
228 let field_name_str = field_name.to_string();
229 let field_access = field_type_to_value_conversion(
230 &field.ty,
231 quote! { self.borrow().#field_name },
232 );
233
234 field_arms.push(quote! {
235 #field_name_str => Some(#field_access),
236 });
237 }
238 }
239 }
240 }
241
242 quote! {
243 impl #ref_name {
244 pub fn get_property(&self, name: &str) -> Option<rustleaf::core::Value> {
246 match name {
247 #(#field_arms)*
248 _ => None,
249 }
250 }
251 }
252 }
253}
254
255fn field_type_to_value_conversion(
256 field_type: &syn::Type,
257 field_access: proc_macro2::TokenStream,
258) -> proc_macro2::TokenStream {
259 if let syn::Type::Path(type_path) = field_type {
261 if let Some(segment) = type_path.path.segments.last() {
262 match segment.ident.to_string().as_str() {
263 "f64" => return quote! { rustleaf::core::Value::Float(#field_access) },
264 "f32" => return quote! { rustleaf::core::Value::Float(#field_access as f64) },
265 "i64" => return quote! { rustleaf::core::Value::Int(#field_access) },
266 "i32" => return quote! { rustleaf::core::Value::Int(#field_access as i64) },
267 "i16" => return quote! { rustleaf::core::Value::Int(#field_access as i64) },
268 "i8" => return quote! { rustleaf::core::Value::Int(#field_access as i64) },
269 "u64" => return quote! { rustleaf::core::Value::Int(#field_access as i64) },
270 "u32" => return quote! { rustleaf::core::Value::Int(#field_access as i64) },
271 "u16" => return quote! { rustleaf::core::Value::Int(#field_access as i64) },
272 "u8" => return quote! { rustleaf::core::Value::Int(#field_access as i64) },
273 "usize" => return quote! { rustleaf::core::Value::Int(#field_access as i64) },
274 "isize" => return quote! { rustleaf::core::Value::Int(#field_access as i64) },
275 "bool" => return quote! { rustleaf::core::Value::Bool(#field_access) },
276 "String" => return quote! { rustleaf::core::Value::String(#field_access.clone()) },
277 _ => {}
278 }
279 }
280 }
281
282 if matches!(field_type, syn::Type::Reference(_)) {
284 return quote! { rustleaf::core::Value::String(#field_access.to_string()) };
286 }
287
288 quote! { (#field_access).into() }
290}
291
292fn generate_borrow_value_impl(
293 struct_name: &syn::Ident,
294 ref_name: &syn::Ident,
295) -> proc_macro2::TokenStream {
296 quote! {
297 impl rustleaf::core::BorrowValueAs<#struct_name> for rustleaf::core::Value {
299 type Guard<'a> = std::cell::Ref<'a, #struct_name>;
300
301 fn borrow_value_as(&self) -> Result<Self::Guard<'_>, anyhow::Error> {
302 if let Some(rust_value) = self.downcast_rust_value::<#ref_name>() {
303 Ok(rust_value.borrow())
304 } else {
305 Err(anyhow::anyhow!("Cannot borrow {} as {}", self.type_name(), stringify!(#struct_name)))
306 }
307 }
308 }
309
310 impl rustleaf::core::BorrowMutValueAs<#struct_name> for rustleaf::core::Value {
312 type Guard<'a> = std::cell::RefMut<'a, #struct_name>;
313
314 fn borrow_mut_value_as(&mut self) -> Result<Self::Guard<'_>, anyhow::Error> {
315 if let Some(rust_value) = self.downcast_rust_value::<#ref_name>() {
316 Ok(rust_value.borrow_mut())
317 } else {
318 Err(anyhow::anyhow!("Cannot borrow {} as mut {}", self.type_name(), stringify!(#struct_name)))
319 }
320 }
321 }
322 }
323}