From 6980fbf2f9fb4c599d8dc6ff549a8b3288eb24e9 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Mon, 17 Aug 2026 02:29:30 +0800 Subject: refactor!: remove dynamic dispatcher registration API Dispatchers are now always registered at compile time, removing the `with_dispatcher` / `with_dispatchers` methods and the `PathfinderConfig` API. The `dispatch_tree` feature now only controls the matching strategy (trie vs linear list). --- mingling_macros/src/systems/dispatch_list_gen.rs | 57 ++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 mingling_macros/src/systems/dispatch_list_gen.rs (limited to 'mingling_macros/src/systems/dispatch_list_gen.rs') diff --git a/mingling_macros/src/systems/dispatch_list_gen.rs b/mingling_macros/src/systems/dispatch_list_gen.rs new file mode 100644 index 0000000..52b0e86 --- /dev/null +++ b/mingling_macros/src/systems/dispatch_list_gen.rs @@ -0,0 +1,57 @@ +// Doc Not Optimize +use std::cmp::Reverse; + +use proc_macro2::TokenStream; +use quote::quote; + +/// Generate the `dispatch_args()` function body for a `ProgramCollect` impl +/// using linear matching over the compile-time-collected dispatchers. +/// +/// Nodes are sorted by display-name length (longest first) so the first +/// matching node is the most specific one, mirroring the "longest registered +/// prefix wins" rule of the old dynamic dispatcher. +pub(crate) fn gen_dispatch_args(entries: &[(String, String, String)]) -> TokenStream { + let mut nodes: Vec<(String, String)> = entries + .iter() + .map(|(name, disp, _)| (name.replace('.', " "), disp.clone())) + .collect(); + nodes.sort_by_key(|(name, _)| Reverse(name.len())); + + let arms: Vec = nodes + .iter() + .map(|(name, disp_type)| { + let name_space = format!("{name} "); + let name_lit = syn::LitStr::new(&name_space, proc_macro2::Span::call_site()); + let disp_ident = proc_macro2::Ident::new(disp_type, proc_macro2::Span::call_site()); + let prefix_word_count = name.split_whitespace().count(); + quote! { + if raw_str.starts_with(#name_lit) { + let prefix_len = #prefix_word_count; + let trimmed_args: Vec = raw.iter().skip(prefix_len).cloned().collect(); + let __cp = <#disp_ident as ::mingling::Dispatcher>::begin( + &#disp_ident::default(), + trimmed_args, + ); + return match __cp { + ::mingling::ChainProcess::Ok(any_output) => Ok(any_output.0), + ::mingling::ChainProcess::Err(chain_process_error) => { + Err(chain_process_error.into()) + } + }; + } + } + }) + .collect(); + + quote! { + fn dispatch_args( + raw: &[String], + ) -> Result<::mingling::AnyOutput, ::mingling::error::ProgramInternalExecuteError> + { + let raw_string = format!("{} ", raw.join(" ")); + let raw_str = raw_string.as_str(); + #(#arms)* + Ok(Self::build_entry_fallback(raw.to_vec())) + } + } +} -- cgit