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_core/src/program/collection.rs | 20 +++---- mingling_core/src/program/collection/mock.rs | 3 -- mingling_core/src/program/exec.rs | 80 ++-------------------------- mingling_core/src/program/hook.rs | 10 ++++ 4 files changed, 19 insertions(+), 94 deletions(-) (limited to 'mingling_core/src/program') diff --git a/mingling_core/src/program/collection.rs b/mingling_core/src/program/collection.rs index 438b800..c571887 100644 --- a/mingling_core/src/program/collection.rs +++ b/mingling_core/src/program/collection.rs @@ -2,7 +2,6 @@ #[cfg(feature = "async")] use std::pin::Pin; -#[cfg(feature = "dispatch_tree")] use crate::Dispatcher; use crate::{AnyOutput, ChainProcess, Grouped, RenderResult}; @@ -34,26 +33,19 @@ pub trait ProgramCollect { /// you can use the `empty_result!()` macro to create this type ResultEmpty: Grouped; - /// Use a prefix tree to quickly match arguments and dispatch to an Entry - #[cfg(feature = "dispatch_tree")] - fn dispatch_args( - raw: &[String], - ) -> Result, crate::error::ProgramInternalExecuteError>; - - #[cfg(not(feature = "dispatch_tree"))] - /// Use a prefix tree to quickly match arguments and dispatch to an Entry + /// Dispatch the raw user arguments to an Entry. + /// + /// The concrete matching strategy (trie or linear list) is generated by + /// `gen_program!` and selected by the `dispatch_tree` feature. /// /// # Errors /// /// Returns an error if the program fails to execute the given arguments. fn dispatch_args( - _raw: &[String], - ) -> Result, crate::error::ProgramInternalExecuteError> { - unreachable!() - } + raw: &[String], + ) -> Result, crate::error::ProgramInternalExecuteError>; /// Get all registered dispatcher names from the program - #[cfg(feature = "dispatch_tree")] fn get_nodes() -> Vec<(String, &'static (dyn Dispatcher + Send + Sync))>; /// Build an [`AnyOutput`](./struct.AnyOutput.html) to indicate that a renderer was not found diff --git a/mingling_core/src/program/collection/mock.rs b/mingling_core/src/program/collection/mock.rs index 662d8f2..d256cc1 100644 --- a/mingling_core/src/program/collection/mock.rs +++ b/mingling_core/src/program/collection/mock.rs @@ -3,7 +3,6 @@ use crate::{AnyOutput, ChainProcess, Grouped, ProgramCollect, RenderResult}; #[cfg(feature = "async")] use std::pin::Pin; -#[cfg(feature = "dispatch_tree")] use crate::Dispatcher; #[cfg(feature = "comp")] @@ -74,14 +73,12 @@ impl ProgramCollect for MockProgramCollect { type ErrorRendererNotFound = Self; type ResultEmpty = Self; - #[cfg(feature = "dispatch_tree")] fn dispatch_args( _raw: &[String], ) -> Result, crate::error::ProgramInternalExecuteError> { unreachable!() } - #[cfg(feature = "dispatch_tree")] fn get_nodes() -> Vec<(String, &'static (dyn Dispatcher + Send + Sync))> { unreachable!() } diff --git a/mingling_core/src/program/exec.rs b/mingling_core/src/program/exec.rs index 3ad5ba8..4980d40 100644 --- a/mingling_core/src/program/exec.rs +++ b/mingling_core/src/program/exec.rs @@ -3,7 +3,7 @@ #![allow(clippy::too_many_lines)] use crate::{ - AnyOutput, ChainProcess, Dispatcher, NextProcess, Program, ProgramCollect, RenderResult, + AnyOutput, ChainProcess, NextProcess, Program, ProgramCollect, RenderResult, error::ProgramInternalExecuteError, hook::ProgramControls, }; @@ -58,12 +58,8 @@ where current ); - // Dispatch args - either via dynamic dispatch or trie dispatch based on feature flag - let mut current = if cfg!(not(feature = "dispatch_tree")) { - dispatch_args_dynamic(program, args)? - } else { - C::dispatch_args(args)? - }; + // Dispatch args + let mut current = C::dispatch_args(args)?; // Run hook control!( @@ -180,76 +176,6 @@ where Ok(render_result) } -/// Dynamically dispatch input arguments to registered entry types -pub(crate) fn dispatch_args_dynamic( - program: &'static Program, - args: &[String], -) -> Result, ProgramInternalExecuteError> -where - C: ProgramCollect, -{ - let next = match match_user_input(program, args) { - Ok((dispatcher, args)) => { - // Entry point - match dispatcher.begin(args) { - ChainProcess::Ok((any, _)) => any, - ChainProcess::Err(e) => return Err(e.into()), - } - } - Err(ProgramInternalExecuteError::DispatcherNotFound) => { - // No matching Dispatcher is found - C::build_entry_fallback(args.to_vec()) - } - Err(e) => return Err(e), - }; - Ok(next) -} - -/// Match user input against registered dispatchers and return the matched dispatcher and remaining arguments. -#[allow(clippy::type_complexity)] -pub(crate) fn match_user_input( - program: &'static Program, - args: &[String], -) -> Result<(&'static (dyn Dispatcher + Send + Sync), Vec), ProgramInternalExecuteError> -where - C: ProgramCollect, -{ - let nodes = program.get_nodes(); - let command = format!("{} ", args.join(" ")); - - // Find all nodes that match the command prefix - let matching_nodes: Vec<&(String, &(dyn Dispatcher + Send + Sync))> = nodes - .iter() - // Also add a space to the node string to ensure consistent matching logic - .filter(|(node_str, _)| command.starts_with(&format!("{node_str} "))) - .collect(); - - match matching_nodes.len() { - 0 => { - // No matching node found - Err(ProgramInternalExecuteError::DispatcherNotFound) - } - 1 => { - let matched_prefix = matching_nodes[0]; - let prefix_len = matched_prefix.0.split_whitespace().count(); - let trimmed_args: Vec = args.iter().skip(prefix_len).cloned().collect(); - Ok((matched_prefix.1, trimmed_args)) - } - _ => { - // Multiple matching nodes found - // Find the node with the longest length (most specific match) - let matched_prefix = matching_nodes - .iter() - .max_by_key(|node| node.0.len()) - .unwrap(); - - let prefix_len = matched_prefix.0.split_whitespace().count(); - let trimmed_args: Vec = args.iter().skip(prefix_len).cloned().collect(); - Ok((matched_prefix.1, trimmed_args)) - } - } -} - #[inline] pub(crate) fn handle_program_control>( program: &Program, diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs index 92106f9..a5cd3a7 100644 --- a/mingling_core/src/program/hook.rs +++ b/mingling_core/src/program/hook.rs @@ -722,6 +722,16 @@ mod tests { type ErrorRendererNotFound = Self; type ResultEmpty = Self; + fn dispatch_args( + _raw: &[String], + ) -> Result, crate::error::ProgramInternalExecuteError> { + unreachable!() + } + + fn get_nodes() -> Vec<(String, &'static (dyn crate::Dispatcher + Send + Sync))> { + unreachable!() + } + fn build_renderer_not_found(_member_id: Self) -> crate::AnyOutput { unreachable!() } -- cgit