aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros/src/lib.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-06-23 00:23:00 +0800
committer魏曹先生 <1992414357@qq.com>2026-06-23 00:23:00 +0800
commitd94103fd7e76dd86cd64c23f00c818165fb7dc22 (patch)
treea435e61fdaa4c273d221d9bbbba640172cb20f6a /mingling_macros/src/lib.rs
parent443ffe86485519a218997955335cde142733f88f (diff)
Replace macro_rules dispatch with proc-macro generation
Generate `render()` and `do_chain()` match dispatch directly in `program_final_gen`, using a compile-time `ASYNC_ENABLED` constant to select the correct sync/async signature. Removes the `__dispatch_program_renderers!` and `__dispatch_program_chains!` macros from `mingling_core`.
Diffstat (limited to 'mingling_macros/src/lib.rs')
-rw-r--r--mingling_macros/src/lib.rs113
1 files changed, 107 insertions, 6 deletions
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index 3b33f09..c6b94c3 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -1624,6 +1624,25 @@ pub fn program_fallback_gen(_input: TokenStream) -> TokenStream {
///
/// # Panics
///
+// Feature detection: baked into the proc-macro binary at compile time
+#[cfg(feature = "async")]
+const ASYNC_ENABLED: bool = true;
+#[cfg(not(feature = "async"))]
+const ASYNC_ENABLED: bool = false;
+
+/// Parses an entry of the format `StructName => EnumVariant,` into a pair of idents.
+fn parse_entry_pair(entry: &proc_macro2::TokenStream) -> (proc_macro2::Ident, proc_macro2::Ident) {
+ let s = entry.to_string();
+ let arrow_idx = s
+ .find("=>")
+ .unwrap_or_else(|| panic!("Entry missing '=>': {s}"));
+ let struct_str = s[..arrow_idx].trim();
+ let variant_str = s[arrow_idx + 2..].trim().trim_end_matches(',');
+ let struct_ident = proc_macro2::Ident::new(struct_str, proc_macro2::Span::call_site());
+ let variant_ident = proc_macro2::Ident::new(variant_str, proc_macro2::Span::call_site());
+ (struct_ident, variant_ident)
+}
+
/// Panics if any of the global registries (`PACKED_TYPES`, `RENDERERS`, `CHAINS`, etc.)
/// are poisoned.
#[proc_macro]
@@ -1749,6 +1768,92 @@ pub fn program_final_gen(_input: TokenStream) -> TokenStream {
#[cfg(not(feature = "comp"))]
let comp = quote! {};
+ // Build render function arms from stored entries
+ let render_fn = if renderer_tokens.is_empty() {
+ quote! {
+ fn render(_any: ::mingling::AnyOutput<Self::Enum>, _renderer_inner_result: &mut ::mingling::RenderResult) {}
+ }
+ } else {
+ let render_arms: Vec<_> = renderer_tokens.iter().map(|entry| {
+ let (struct_ident, variant_ident) = parse_entry_pair(entry);
+ quote! {
+ Self::#variant_ident => {
+ // SAFETY: The `type_id` check ensures that `any` contains a value of type `#variant_ident`,
+ // so downcasting to `#variant_ident` is safe.
+ let value = unsafe { any.downcast::<#variant_ident>().unwrap_unchecked() };
+ <#struct_ident as ::mingling::Renderer>::render(value, __renderer_inner_result);
+ }
+ }
+ }).collect();
+ quote! {
+ fn render(any: ::mingling::AnyOutput<Self::Enum>, __renderer_inner_result: &mut ::mingling::RenderResult) {
+ match any.member_id {
+ #(#render_arms)*
+ _ => (),
+ }
+ }
+ }
+ };
+
+ // Build do_chain function (async and sync versions)
+ let chain_arms_async: Vec<_> = chain_tokens.iter().map(|entry| {
+ let (struct_ident, variant_ident) = parse_entry_pair(entry);
+ quote! {
+ Self::#variant_ident => {
+ // SAFETY: The `type_id` check ensures that `any` contains a value of type `#variant_ident`,
+ // so downcasting to `#variant_ident` is safe.
+ let value = unsafe { any.downcast::<#variant_ident>().unwrap_unchecked() };
+ let fut = async { <#struct_ident as ::mingling::Chain<Self::Enum>>::proc(value).await };
+ ::std::boxed::Box::pin(fut)
+ }
+ }
+ }).collect();
+
+ let chain_arms_sync: Vec<_> = chain_tokens
+ .iter()
+ .map(|entry| {
+ let (struct_ident, variant_ident) = parse_entry_pair(entry);
+ quote! {
+ Self::#variant_ident => {
+ // SAFETY: The `type_id` check ensures that `any` contains a value of type `#variant_ident`,
+ // so downcasting to `#variant_ident` is safe.
+ let value = unsafe { any.downcast::<#variant_ident>().unwrap_unchecked() };
+ <#struct_ident as ::mingling::Chain<Self::Enum>>::proc(value)
+ }
+ }
+ })
+ .collect();
+
+ let do_chain_fn = if chain_tokens.is_empty() {
+ quote! {
+ fn do_chain(_any: ::mingling::AnyOutput<Self::Enum>) -> ::mingling::ChainProcess<Self::Enum> {
+ ::core::panic!("No chain found for type id")
+ }
+ }
+ } else if ASYNC_ENABLED {
+ quote! {
+ fn do_chain(
+ any: ::mingling::AnyOutput<Self::Enum>,
+ ) -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = ::mingling::ChainProcess<Self::Enum>> + ::std::marker::Send>> {
+ match any.member_id {
+ #(#chain_arms_async)*
+ _ => ::core::panic!("No chain found for type id: {:?}", any.type_id),
+ }
+ }
+ }
+ } else {
+ quote! {
+ fn do_chain(
+ any: ::mingling::AnyOutput<Self::Enum>,
+ ) -> ::mingling::ChainProcess<Self::Enum> {
+ match any.member_id {
+ #(#chain_arms_sync)*
+ _ => ::core::panic!("No chain found for type id: {:?}", any.type_id),
+ }
+ }
+ }
+ };
+
let help_tokens: Vec<proc_macro2::TokenStream> = get_global_set(&HELP_REQUESTS)
.lock()
.unwrap()
@@ -1798,12 +1903,8 @@ pub fn program_final_gen(_input: TokenStream) -> TokenStream {
fn build_empty_result() -> ::mingling::AnyOutput<Self::Enum> {
::mingling::AnyOutput::new(ResultEmpty::new(()))
}
- ::mingling::__dispatch_program_renderers!(
- #(#renderer_tokens)*
- );
- ::mingling::__dispatch_program_chains!(
- #(#chain_tokens)*
- );
+ #render_fn
+ #do_chain_fn
fn render_help(any: ::mingling::AnyOutput<Self::Enum>, __renderer_inner_result: &mut ::mingling::RenderResult) {
match any.member_id {
#(#help_tokens)*