diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-04-01 15:48:41 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-04-01 15:48:41 +0800 |
| commit | 3de10ca22cca06c4d9069984d0e66e370a331dde (patch) | |
| tree | 7e8a9b035c360c016cde848b3442d3e1d5dcac5e /mingling_macros | |
| parent | f3d6f76dfd07c35dabc11aa86d86c3671cd283c5 (diff) | |
Replace typeid-based dispatch with enum-based dispatch
- Add `Groupped` trait and `member_id` to `AnyOutput`
- Add generic parameter `G` to `Dispatcher`, `Chain`, `Program` etc
- Remove `hint` module and its marker types
- Update macros to support explicit group specification
- Add `gen_program` macro for generating enum-based programs
- Add `GroupProcess` marker type for type-level grouping
Diffstat (limited to 'mingling_macros')
| -rw-r--r-- | mingling_macros/src/README.txt | 12 | ||||
| -rw-r--r-- | mingling_macros/src/chain.rs | 97 | ||||
| -rw-r--r-- | mingling_macros/src/dispatcher_chain.rs | 219 | ||||
| -rw-r--r-- | mingling_macros/src/lib.rs | 58 | ||||
| -rw-r--r-- | mingling_macros/src/pack.rs | 158 | ||||
| -rw-r--r-- | mingling_macros/src/renderer.rs | 11 |
6 files changed, 440 insertions, 115 deletions
diff --git a/mingling_macros/src/README.txt b/mingling_macros/src/README.txt new file mode 100644 index 0000000..a882bd0 --- /dev/null +++ b/mingling_macros/src/README.txt @@ -0,0 +1,12 @@ +*Listen up*, this is a messy macro written by AI. +It works, but it looks like expired spaghetti and smells like freshly laid shit. + +But the general idea is mostly right. If I'm in a good mood, this code will definitely need a refactor. + +---------------------------------------------------- +Chinese original version: + +*听着*,这是一坨由 AI 写的乱七八糟的宏 +它能用,但是看起来就像过期的意大利面,闻起来就像刚拉出来的新鲜的屎 + +不过思路大抵是对的,如果心情好这坨代码肯定要重构 diff --git a/mingling_macros/src/chain.rs b/mingling_macros/src/chain.rs index 1fddd3b..f8b1e1c 100644 --- a/mingling_macros/src/chain.rs +++ b/mingling_macros/src/chain.rs @@ -1,10 +1,10 @@ //! Chain Attribute Macro Implementation //! -//! This module provides the `#[chain]` attribute macro for automatically +//! This module provides the `#[chain(Group)]` attribute macro for automatically //! generating structs that implement the `Chain` trait from async functions. use proc_macro::TokenStream; -use quote::quote; +use quote::{ToTokens, quote}; use syn::spanned::Spanned; use syn::{ FnArg, Ident, ItemFn, Pat, PatType, ReturnType, Signature, Type, TypePath, parse_macro_input, @@ -59,7 +59,18 @@ fn extract_return_type(sig: &Signature) -> syn::Result<TypePath> { } } -pub fn chain_attr(item: TokenStream) -> TokenStream { +pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream { + // Parse the attribute arguments (e.g., MyProgram from #[chain(MyProgram)]) + // If no argument is provided, use DefaultProgram + let (group_name, use_crate_prefix) = if attr.is_empty() { + ( + Ident::new("DefaultProgram", proc_macro2::Span::call_site()), + true, + ) + } else { + (parse_macro_input!(attr as Ident), false) + }; + // Parse the function item let input_fn = parse_macro_input!(item as ItemFn); @@ -82,11 +93,22 @@ pub fn chain_attr(item: TokenStream) -> TokenStream { Err(e) => return e.to_compile_error().into(), }; + // Ensure the return type is named "GroupProcess" + if return_type.path.segments.last().unwrap().ident != "GroupProcess" { + return syn::Error::new( + return_type.span(), + "Return type must be 'mingling::marker::GroupProcess'", + ) + .to_compile_error() + .into(); + } + // Get the function body let fn_body = &input_fn.block; // Get function attributes (excluding the chain attribute) let mut fn_attrs = input_fn.attrs.clone(); + // Remove any #[chain(...)] attributes to avoid infinite recursion fn_attrs.retain(|attr| !attr.path().is_ident("chain")); @@ -101,23 +123,55 @@ pub fn chain_attr(item: TokenStream) -> TokenStream { let struct_name = Ident::new(&pascal_case_name, fn_name.span()); // Generate the struct and implementation - let expanded = quote! { - #(#fn_attrs)* - #vis struct #struct_name; - - impl ::mingling::Chain for #struct_name { - type Previous = #previous_type; + let expanded = if use_crate_prefix { + quote! { + #(#fn_attrs)* + #vis struct #struct_name; + + impl ::mingling::Chain<DefaultProgram> for #struct_name { + type Previous = #previous_type; + + async fn proc(#prev_param: Self::Previous) -> + ::mingling::ChainProcess<DefaultProgram> + { + let _ = GroupProcess; + // Call the original function + #fn_name(#prev_param).await + } + } - async fn proc(#prev_param: Self::Previous) -> #return_type { - // Call the original function - #fn_name(#prev_param).await + // Keep the original function for internal use + #(#fn_attrs)* + #vis async fn #fn_name(#prev_param: #previous_type) + -> ::mingling::ChainProcess<DefaultProgram> + { + #fn_body } } + } else { + quote! { + #(#fn_attrs)* + #vis struct #struct_name; + + impl ::mingling::Chain<#group_name> for #struct_name { + type Previous = #previous_type; + + async fn proc(#prev_param: Self::Previous) -> + ::mingling::ChainProcess<#group_name> + { + let _ = GroupProcess; + // Call the original function + #fn_name(#prev_param).await + } + } - // Keep the original function for internal use - #(#fn_attrs)* - #vis async fn #fn_name(#prev_param: #previous_type) -> #return_type { - #fn_body + // Keep the original function for internal use + #(#fn_attrs)* + #vis async fn #fn_name(#prev_param: #previous_type) + -> ::mingling::ChainProcess<#group_name> + { + #fn_body + } } }; @@ -127,21 +181,28 @@ pub fn chain_attr(item: TokenStream) -> TokenStream { }; let chain_exist_entry = quote! { - id if id == std::any::TypeId::of::<#previous_type>() => true, + Self::#previous_type => true, }; let mut chains = crate::CHAINS.lock().unwrap(); let mut chain_exist = crate::CHAINS_EXIST.lock().unwrap(); + let mut packed_types = crate::PACKED_TYPES.lock().unwrap(); let chain_entry = chain_entry.to_string(); let chain_exist_entry = chain_exist_entry.to_string(); + let previous_type_str = previous_type.to_token_stream().to_string(); if !chains.contains(&chain_entry) { chains.push(chain_entry); } - if !chains.contains(&chain_exist_entry) { + + if !chain_exist.contains(&chain_exist_entry) { chain_exist.push(chain_exist_entry); } + if !packed_types.contains(&previous_type_str) { + packed_types.push(previous_type_str); + } + expanded.into() } diff --git a/mingling_macros/src/dispatcher_chain.rs b/mingling_macros/src/dispatcher_chain.rs index 57c11a3..dc02c33 100644 --- a/mingling_macros/src/dispatcher_chain.rs +++ b/mingling_macros/src/dispatcher_chain.rs @@ -8,53 +8,123 @@ use quote::quote; use syn::parse::{Parse, ParseStream}; use syn::{Ident, Result as SynResult, Token}; -/// Parses input in the format: `"command_name", CommandStruct => ChainStruct` -struct DispatcherChainInput { - command_name: syn::LitStr, - command_struct: Ident, - pack: Ident, +enum DispatcherChainInput { + Explicit { + group_name: Ident, + command_name: syn::LitStr, + command_struct: Ident, + pack: Ident, + }, + Default { + command_name: syn::LitStr, + command_struct: Ident, + pack: Ident, + }, } impl Parse for DispatcherChainInput { fn parse(input: ParseStream) -> SynResult<Self> { - let command_name = input.parse()?; - input.parse::<Token![,]>()?; - let command_struct = input.parse()?; - input.parse::<Token![=>]>()?; - let pack = input.parse()?; - - Ok(DispatcherChainInput { - command_name, - command_struct, - pack, - }) + let lookahead = input.lookahead1(); + + if lookahead.peek(Ident) && input.peek2(Token![,]) && input.peek3(syn::LitStr) { + let group_name = input.parse()?; + input.parse::<Token![,]>()?; + let command_name = input.parse()?; + input.parse::<Token![,]>()?; + let command_struct = input.parse()?; + input.parse::<Token![=>]>()?; + let pack = input.parse()?; + + Ok(DispatcherChainInput::Explicit { + group_name, + command_name, + command_struct, + pack, + }) + } else if lookahead.peek(syn::LitStr) { + // Default format: "command_name", CommandStruct => ChainStruct + let command_name = input.parse()?; + input.parse::<Token![,]>()?; + let command_struct = input.parse()?; + input.parse::<Token![=>]>()?; + let pack = input.parse()?; + + Ok(DispatcherChainInput::Default { + command_name, + command_struct, + pack, + }) + } else { + Err(lookahead.error()) + } } } pub fn dispatcher_chain(input: TokenStream) -> TokenStream { - let DispatcherChainInput { - command_name, - command_struct, - pack, - } = syn::parse_macro_input!(input as DispatcherChainInput); + // Parse the input + let dispatcher_input = syn::parse_macro_input!(input as DispatcherChainInput); - let command_name_str = command_name.value(); - - let expanded = quote! { - #[derive(Debug, Default)] - pub struct #command_struct; + // Determine if we're using default or explicit group + let (group_name, command_name, command_struct, pack, use_default) = match dispatcher_input { + DispatcherChainInput::Explicit { + group_name, + command_name, + command_struct, + pack, + } => (group_name, command_name, command_struct, pack, false), + DispatcherChainInput::Default { + command_name, + command_struct, + pack, + } => ( + Ident::new("DefaultProgram", proc_macro2::Span::call_site()), + command_name, + command_struct, + pack, + true, + ), + }; - ::mingling::macros::pack!(#pack = Vec<String>); + let command_name_str = command_name.value(); - impl ::mingling::Dispatcher for #command_struct { - fn node(&self) -> ::mingling::Node { - ::mingling::macros::node!(#command_name_str) + let expanded = if use_default { + // For default case, use DefaultProgram + quote! { + #[derive(Debug, Default)] + pub struct #command_struct; + + ::mingling::macros::pack!(DefaultProgram, #pack = Vec<String>); + + impl ::mingling::Dispatcher<DefaultProgram> for #command_struct { + fn node(&self) -> ::mingling::Node { + ::mingling::macros::node!(#command_name_str) + } + fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess<DefaultProgram> { + #pack::new(args).to_chain() + } + fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher<DefaultProgram>> { + Box::new(#command_struct) + } } - fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess { - #pack::new(args).to_chain() - } - fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher> { - Box::new(#command_struct) + } + } else { + // For explicit case, use the provided group_name + quote! { + #[derive(Debug, Default)] + pub struct #command_struct; + + ::mingling::macros::pack!(#group_name, #pack = Vec<String>); + + impl ::mingling::Dispatcher<#group_name> for #command_struct { + fn node(&self) -> ::mingling::Node { + ::mingling::macros::node!(#command_name_str) + } + fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess<#group_name> { + #pack::new(args).to_chain() + } + fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher<#group_name>> { + Box::new(#command_struct) + } } } }; @@ -63,29 +133,70 @@ pub fn dispatcher_chain(input: TokenStream) -> TokenStream { } pub fn dispatcher_render(input: TokenStream) -> TokenStream { - let DispatcherChainInput { - command_name, - command_struct, - pack, - } = syn::parse_macro_input!(input as DispatcherChainInput); + // Parse the input + let dispatcher_input = syn::parse_macro_input!(input as DispatcherChainInput); - let command_name_str = command_name.value(); - - let expanded = quote! { - #[derive(Debug, Default)] - pub struct #command_struct; + // Determine if we're using default or explicit group + let (group_name, command_name, command_struct, pack, use_default) = match dispatcher_input { + DispatcherChainInput::Explicit { + group_name, + command_name, + command_struct, + pack, + } => (group_name, command_name, command_struct, pack, false), + DispatcherChainInput::Default { + command_name, + command_struct, + pack, + } => ( + Ident::new("DefaultProgram", proc_macro2::Span::call_site()), + command_name, + command_struct, + pack, + true, + ), + }; - ::mingling::macros::pack!(#pack = Vec<String>); + let command_name_str = command_name.value(); - impl ::mingling::Dispatcher for #command_struct { - fn node(&self) -> ::mingling::Node { - ::mingling::macros::node!(#command_name_str) + let expanded = if use_default { + // For default case, use DefaultProgram + quote! { + #[derive(Debug, Default)] + pub struct #command_struct; + + ::mingling::macros::pack!(DefaultProgram, #pack = Vec<String>); + + impl ::mingling::Dispatcher for #command_struct { + fn node(&self) -> ::mingling::Node { + ::mingling::macros::node!(#command_name_str) + } + fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess { + #pack::new(args).to_render() + } + fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher> { + Box::new(#command_struct) + } } - fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess { - #pack::new(args).to_render() - } - fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher> { - Box::new(#command_struct) + } + } else { + // For explicit case, use the provided group_name + quote! { + #[derive(Debug, Default)] + pub struct #command_struct; + + ::mingling::macros::pack!(#group_name, #pack = Vec<String>); + + impl ::mingling::Dispatcher for #command_struct { + fn node(&self) -> ::mingling::Node { + ::mingling::macros::node!(#command_name_str) + } + fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess { + #pack::new(args).to_render() + } + fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher> { + Box::new(#command_struct) + } } } }; diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs index 05bcf0b..832b45a 100644 --- a/mingling_macros/src/lib.rs +++ b/mingling_macros/src/lib.rs @@ -19,6 +19,7 @@ use once_cell::sync::Lazy; use std::sync::Mutex; // Global variable declarations for storing chain and renderer mappings +pub(crate) static PACKED_TYPES: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(Vec::new())); pub(crate) static CHAINS: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(Vec::new())); pub(crate) static RENDERERS: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(Vec::new())); pub(crate) static CHAINS_EXIST: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(Vec::new())); @@ -55,8 +56,8 @@ pub fn r_println(input: TokenStream) -> TokenStream { } #[proc_macro_attribute] -pub fn chain(_attr: TokenStream, item: TokenStream) -> TokenStream { - chain::chain_attr(item) +pub fn chain(attr: TokenStream, item: TokenStream) -> TokenStream { + chain::chain_attr(attr, item) } #[proc_macro_attribute] @@ -65,14 +66,24 @@ pub fn renderer(_attr: TokenStream, item: TokenStream) -> TokenStream { } #[proc_macro] -pub fn program(input: TokenStream) -> TokenStream { - let name = parse_macro_input!(input as Ident); +pub fn gen_program(input: TokenStream) -> TokenStream { + let name = if input.is_empty() { + Ident::new("DefaultProgram", proc_macro2::Span::call_site()) + } else { + parse_macro_input!(input as Ident) + }; + let packed_types = PACKED_TYPES.lock().unwrap().clone(); let renderers = RENDERERS.lock().unwrap().clone(); let chains = CHAINS.lock().unwrap().clone(); let renderer_exist = RENDERERS_EXIST.lock().unwrap().clone(); let chain_exist = CHAINS_EXIST.lock().unwrap().clone(); + let packed_types: Vec<proc_macro2::TokenStream> = packed_types + .iter() + .map(|s| syn::parse_str::<proc_macro2::TokenStream>(s).unwrap()) + .collect(); + let renderer_tokens: Vec<proc_macro2::TokenStream> = renderers .iter() .map(|s| syn::parse_str::<proc_macro2::TokenStream>(s).unwrap()) @@ -94,23 +105,50 @@ pub fn program(input: TokenStream) -> TokenStream { .collect(); let expanded = quote! { - pub struct #name; + ::mingling::macros::pack!(#name, RendererNotFound = String); + ::mingling::macros::pack!(#name, DispatcherNotFound = Vec<String>); + + #[derive(Debug, Default, PartialEq, Eq, Clone)] + #[repr(u32)] + pub enum #name { + #[default] + __FallBack, + DispatcherNotFound, + RendererNotFound, + #(#packed_types),* + } + + impl ::std::fmt::Display for #name { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match self { + #name::__FallBack => write!(f, "__FallBack"), + #name::DispatcherNotFound => { + write!(f, "DispatcherNotFound") + } + #name::RendererNotFound => { + write!(f, "RendererNotFound") + } + #(#name::#packed_types => write!(f, stringify!(#packed_types)),)* + } + } + } impl ::mingling::ProgramCollect for #name { + type Enum = #name; ::mingling::__dispatch_program_renderers!( #(#renderer_tokens)* ); ::mingling::__dispatch_program_chains!( #(#chain_tokens)* ); - fn has_renderer(any: &::mingling::AnyOutput) -> bool { - match any.type_id { + fn has_renderer(any: &::mingling::AnyOutput<Self::Enum>) -> bool { + match any.member_id { #(#renderer_exist_tokens)* _ => false } } - fn has_chain(any: &::mingling::AnyOutput) -> bool { - match any.type_id { + fn has_chain(any: &::mingling::AnyOutput<Self::Enum>) -> bool { + match any.member_id { #(#chain_exist_tokens)* _ => false } @@ -118,7 +156,7 @@ pub fn program(input: TokenStream) -> TokenStream { } impl #name { - pub fn new() -> ::mingling::Program<#name> { + pub fn new() -> ::mingling::Program<#name, #name> { ::mingling::Program::new() } } diff --git a/mingling_macros/src/pack.rs b/mingling_macros/src/pack.rs index bff67d4..c6a6c67 100644 --- a/mingling_macros/src/pack.rs +++ b/mingling_macros/src/pack.rs @@ -8,37 +8,80 @@ use quote::quote; use syn::parse::{Parse, ParseStream}; use syn::{Ident, Result as SynResult, Token, Type}; -/// Parses input in the format: `TypeName = InnerType` -struct PackInput { - type_name: Ident, - inner_type: Type, +enum PackInput { + Explicit { + group_name: Ident, + type_name: Ident, + inner_type: Type, + }, + Default { + type_name: Ident, + inner_type: Type, + }, } impl Parse for PackInput { fn parse(input: ParseStream) -> SynResult<Self> { - let type_name = input.parse()?; - input.parse::<Token![=]>()?; - let inner_type = input.parse()?; + // Try to parse as explicit format first: GroupName, TypeName = InnerType + let lookahead = input.lookahead1(); - Ok(PackInput { - type_name, - inner_type, - }) + if lookahead.peek(Ident) && input.peek2(Token![,]) { + // Explicit format: GroupName, TypeName = InnerType + let group_name = input.parse()?; + input.parse::<Token![,]>()?; + let type_name = input.parse()?; + input.parse::<Token![=]>()?; + let inner_type = input.parse()?; + + Ok(PackInput::Explicit { + group_name, + type_name, + inner_type, + }) + } else if lookahead.peek(Ident) && input.peek2(Token![=]) { + // Default format: TypeName = InnerType + let type_name = input.parse()?; + input.parse::<Token![=]>()?; + let inner_type = input.parse()?; + + Ok(PackInput::Default { + type_name, + inner_type, + }) + } else { + Err(lookahead.error()) + } } } pub fn pack(input: TokenStream) -> TokenStream { - let PackInput { - type_name, - inner_type, - } = syn::parse_macro_input!(input as PackInput); + // Parse the input + let pack_input = syn::parse_macro_input!(input as PackInput); + + // Determine if we're using default or explicit group + let (group_name, type_name, inner_type, use_default) = match pack_input { + PackInput::Explicit { + group_name, + type_name, + inner_type, + } => (group_name, type_name, inner_type, false), + PackInput::Default { + type_name, + inner_type, + } => ( + Ident::new("DefaultProgram", proc_macro2::Span::call_site()), + type_name, + inner_type, + true, + ), + }; // Generate the struct definition #[cfg(not(feature = "serde"))] let struct_def = quote! { #[derive(Debug)] pub struct #type_name { - inner: #inner_type, + pub(crate) inner: #inner_type, } }; @@ -46,7 +89,7 @@ pub fn pack(input: TokenStream) -> TokenStream { let struct_def = quote! { #[derive(Debug, serde::Serialize)] pub struct #type_name { - inner: #inner_type, + pub(crate) inner: #inner_type, } }; @@ -120,42 +163,95 @@ pub fn pack(input: TokenStream) -> TokenStream { }; let any_out_impl = quote! { - impl Into<mingling::AnyOutput> for #type_name { - fn into(self) -> mingling::AnyOutput { + impl Into<mingling::AnyOutput<#group_name>> for #type_name { + fn into(self) -> mingling::AnyOutput<#group_name> { mingling::AnyOutput::new(self) } } - impl Into<mingling::ChainProcess> for #type_name { - fn into(self) -> mingling::ChainProcess { + impl Into<mingling::ChainProcess<#group_name>> for #type_name { + fn into(self) -> mingling::ChainProcess<#group_name> { mingling::AnyOutput::new(self).route_chain() } } impl #type_name { /// Converts the wrapper type into a `ChainProcess` for chaining operations. - pub fn to_chain(self) -> mingling::ChainProcess { + pub fn to_chain(self) -> mingling::ChainProcess<#group_name> { mingling::AnyOutput::new(self).route_chain() } /// Converts the wrapper type into a `ChainProcess` for rendering operations. - pub fn to_render(self) -> mingling::ChainProcess { + pub fn to_render(self) -> mingling::ChainProcess<#group_name> { mingling::AnyOutput::new(self).route_renderer() } } }; + let group_impl = quote! { + impl ::mingling::Groupped<#group_name> for #type_name { + fn member_id() -> #group_name { + #group_name::#type_name + } + } + }; + // Combine all implementations - let expanded = quote! { - #struct_def + let expanded = if use_default { + // For default case, use DefaultProgram + quote! { + #struct_def + + #new_impl + #from_into_impl + #as_ref_impl + #deref_impl + #default_impl + + impl Into<mingling::AnyOutput<DefaultProgram>> for #type_name { + fn into(self) -> mingling::AnyOutput<DefaultProgram> { + mingling::AnyOutput::new(self) + } + } + + impl From<#type_name> for mingling::ChainProcess<DefaultProgram> { + fn from(value: #type_name) -> Self { + mingling::AnyOutput::new(value).route_chain() + } + } - #new_impl - #from_into_impl - #as_ref_impl - #deref_impl - #default_impl + impl #type_name { + /// Converts the wrapper type into a `ChainProcess` for chaining operations. + pub fn to_chain(self) -> mingling::ChainProcess<DefaultProgram> { + mingling::AnyOutput::new(self).route_chain() + } - #any_out_impl + /// Converts the wrapper type into a `ChainProcess` for rendering operations. + pub fn to_render(self) -> mingling::ChainProcess<DefaultProgram> { + mingling::AnyOutput::new(self).route_renderer() + } + } + + impl ::mingling::Groupped<DefaultProgram> for #type_name { + fn member_id() -> DefaultProgram { + DefaultProgram::#type_name + } + } + } + } else { + // For explicit case, use the provided group_name + quote! { + #struct_def + + #new_impl + #from_into_impl + #as_ref_impl + #deref_impl + #default_impl + + #any_out_impl + #group_impl + } }; expanded.into() diff --git a/mingling_macros/src/renderer.rs b/mingling_macros/src/renderer.rs index 21c20c8..0e32b40 100644 --- a/mingling_macros/src/renderer.rs +++ b/mingling_macros/src/renderer.rs @@ -4,7 +4,7 @@ //! generating structs that implement the `Renderer` trait from functions. use proc_macro::TokenStream; -use quote::quote; +use quote::{ToTokens, quote}; use syn::spanned::Spanned; use syn::{FnArg, ItemFn, Pat, PatType, ReturnType, Signature, Type, TypePath, parse_macro_input}; @@ -106,22 +106,29 @@ pub fn renderer_attr(item: TokenStream) -> TokenStream { }; let renderer_exist_entry = quote! { - id if id == std::any::TypeId::of::<#previous_type>() => true, + Self::#previous_type => true, }; let mut renderers = crate::RENDERERS.lock().unwrap(); let mut renderer_exist = crate::RENDERERS_EXIST.lock().unwrap(); + let mut packed_types = crate::PACKED_TYPES.lock().unwrap(); let renderer_entry_str = renderer_entry.to_string(); let renderer_exist_entry_str = renderer_exist_entry.to_string(); + let previous_type_str = previous_type.to_token_stream().to_string(); if !renderers.contains(&renderer_entry_str) { renderers.push(renderer_entry_str); } + if !renderer_exist.contains(&renderer_exist_entry_str) { renderer_exist.push(renderer_exist_entry_str); } + if !packed_types.contains(&previous_type_str) { + packed_types.push(previous_type_str); + } + // Generate the struct and implementation // We need to create a wrapper function that adds the r parameter let expanded = quote! { |
