aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros/src/attr/renderer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_macros/src/attr/renderer.rs')
-rw-r--r--mingling_macros/src/attr/renderer.rs75
1 files changed, 49 insertions, 26 deletions
diff --git a/mingling_macros/src/attr/renderer.rs b/mingling_macros/src/attr/renderer.rs
index c7cbb0b..038edd8 100644
--- a/mingling_macros/src/attr/renderer.rs
+++ b/mingling_macros/src/attr/renderer.rs
@@ -1,7 +1,7 @@
use proc_macro::TokenStream;
use quote::{ToTokens, quote};
use syn::spanned::Spanned;
-use syn::{ItemFn, ReturnType, Signature, TypePath, parse_macro_input};
+use syn::{ItemFn, Pat, ReturnType, Signature, TypePath, parse_macro_input};
use crate::get_global_set;
use crate::res_injection::{extract_args_info, generate_immut_resource_bindings};
@@ -15,9 +15,7 @@ fn extract_user_return_type(sig: &Signature) -> Option<proc_macro2::TokenStream>
}
#[allow(clippy::too_many_lines)]
-pub(crate) fn renderer_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
- // #[renderer] takes no arguments; always use the default program path
- let _ = attr;
+pub(crate) fn renderer_attr(item: TokenStream) -> TokenStream {
let program_path = crate::default_program_path();
let program_type = &program_path;
@@ -31,8 +29,8 @@ pub(crate) fn renderer_attr(attr: TokenStream, item: TokenStream) -> TokenStream
.into();
}
- // Extract the previous type, parameter name, and resource injection params
- let (prev_param, previous_type, resources) = match extract_args_info(&input_fn.sig) {
+ // Extract the previous type and resource injection params
+ let (_, previous_type, resources) = match extract_args_info(&input_fn.sig) {
Ok(info) => info,
Err(e) => return e.to_compile_error().into(),
};
@@ -69,37 +67,59 @@ pub(crate) fn renderer_attr(attr: TokenStream, item: TokenStream) -> TokenStream
let immut_resource_stmts = generate_immut_resource_bindings(resources.iter(), program_type);
let mut_resources: Vec<_> = resources.iter().filter(|r| r.is_mut).collect();
- let inner_body_with_resources = if has_mut_resources {
- let mut wrapped = quote! { #(#fn_body_stmts)* };
+ // Build the call to the original function with resource arguments injected
+ let resource_args: Vec<_> = resources
+ .iter()
+ .map(|res| {
+ let var_name = &res.var_name;
+ quote! { #var_name }
+ })
+ .collect();
+
+ // Use a fixed parameter name `prev` for the trait method, regardless of
+ // the user's original parameter name (which may be `_` and cannot be
+ // referenced in expression position).
+ let fixed_prev: Pat = syn::parse_quote!(prev);
+
+ let fn_call = if has_resources {
+ quote! { #fn_name(#fixed_prev, #(#resource_args),*) }
+ } else {
+ quote! { #fn_name(#fixed_prev) }
+ };
+
+ // Wrap the function call with modify_res for mutable resources
+ let inner_call = if has_mut_resources {
+ let mut wrapped = fn_call;
for res in mut_resources.iter().rev() {
let var_name = &res.var_name;
let inner_type = &res.inner_type;
wrapped = quote! {
- ::mingling::this::<#program_type>().modify_res(|#var_name: &mut #inner_type| {
+ ::mingling::this::<#program_type>()
+ .modify_res(|#var_name: &mut #inner_type| {
#wrapped
})
};
}
wrapped
} else {
- quote! { #(#fn_body_stmts)* }
+ fn_call
};
- // Build the Renderer::render body with resource injection
- // The user's body now directly creates and returns a RenderResult.
+ // Build the Renderer::render body with resource injection.
+ // The trait method injects resources and calls the original function.
let render_fn_body = if has_resources {
quote! {
#(#immut_resource_stmts)*
- #inner_body_with_resources
+ #inner_call
}
} else {
- quote! { #inner_body_with_resources }
+ quote! { #inner_call }
};
// The original function preserves the user's exact signature and body.
// Resource parameters are passed directly by the caller, NOT injected from context.
let original_inputs = input_fn.sig.inputs.clone();
- let original_return_type = user_return_type.clone().unwrap_or(quote! { () });
+ let original_return_type = user_return_type.unwrap_or_else(|| quote! { () });
let expanded = quote! {
#(#fn_attrs)*
@@ -112,14 +132,13 @@ pub(crate) fn renderer_attr(attr: TokenStream, item: TokenStream) -> TokenStream
impl ::mingling::Renderer for #struct_name {
type Previous = #previous_type;
- fn render(#prev_param: Self::Previous) -> ::mingling::RenderResult {
+ fn render(#fixed_prev: Self::Previous) -> ::mingling::RenderResult {
let __renderer_result = { #render_fn_body };
::std::convert::Into::into(__renderer_result)
}
}
// Keep the original function unchanged
- #[allow(dead_code)]
#(#fn_attrs)*
#vis fn #fn_name(#original_inputs) -> #original_return_type {
#(#fn_body_stmts)*
@@ -228,14 +247,15 @@ pub(crate) fn register_renderer(input: TokenStream) -> TokenStream {
}
} // renderers lock released here
- let mut renderers = get_global_set(&crate::RENDERERS).lock().unwrap();
- let mut renderer_exist = get_global_set(&crate::RENDERERS_EXIST).lock().unwrap();
-
- #[cfg(feature = "structural_renderer")]
- let mut structural_renderers = get_global_set(&crate::STRUCTURAL_RENDERERS).lock().unwrap();
-
- renderers.insert(renderer_entry_str);
- renderer_exist.insert(renderer_exist_entry_str);
+ // Insert renderer registration directly without holding a lock variable
+ get_global_set(&crate::RENDERERS)
+ .lock()
+ .unwrap()
+ .insert(renderer_entry_str);
+ get_global_set(&crate::RENDERERS_EXIST)
+ .lock()
+ .unwrap()
+ .insert(renderer_exist_entry_str);
// Only register structural renderer if the type is in STRUCTURED_TYPES
#[cfg(feature = "structural_renderer")]
@@ -245,7 +265,10 @@ pub(crate) fn register_renderer(input: TokenStream) -> TokenStream {
.unwrap()
.contains(&variant_name);
if is_structured {
- structural_renderers.insert(structural_renderer_entry_str);
+ get_global_set(&crate::STRUCTURAL_RENDERERS)
+ .lock()
+ .unwrap()
+ .insert(structural_renderer_entry_str);
}
}