aboutsummaryrefslogtreecommitdiff
path: root/mingling_core/src/program
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-08-17 02:29:30 +0800
committer魏曹先生 <1992414357@qq.com>2026-08-17 02:39:56 +0800
commit6980fbf2f9fb4c599d8dc6ff549a8b3288eb24e9 (patch)
treebc7049698955d7a40706ea691fd5bab526a6b5e5 /mingling_core/src/program
parent4c191b2b46a67a0dda6e9a867b40f45156af4f9c (diff)
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).
Diffstat (limited to 'mingling_core/src/program')
-rw-r--r--mingling_core/src/program/collection.rs20
-rw-r--r--mingling_core/src/program/collection/mock.rs3
-rw-r--r--mingling_core/src/program/exec.rs80
-rw-r--r--mingling_core/src/program/hook.rs10
4 files changed, 19 insertions, 94 deletions
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<Self::Enum>;
- /// Use a prefix tree to quickly match arguments and dispatch to an Entry
- #[cfg(feature = "dispatch_tree")]
- fn dispatch_args(
- raw: &[String],
- ) -> Result<AnyOutput<Self::Enum>, 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<AnyOutput<Self::Enum>, crate::error::ProgramInternalExecuteError> {
- unreachable!()
- }
+ raw: &[String],
+ ) -> Result<AnyOutput<Self::Enum>, crate::error::ProgramInternalExecuteError>;
/// Get all registered dispatcher names from the program
- #[cfg(feature = "dispatch_tree")]
fn get_nodes() -> Vec<(String, &'static (dyn Dispatcher<Self::Enum> + 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<AnyOutput<Self::Enum>, crate::error::ProgramInternalExecuteError> {
unreachable!()
}
- #[cfg(feature = "dispatch_tree")]
fn get_nodes() -> Vec<(String, &'static (dyn Dispatcher<Self::Enum> + 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<C>(
- program: &'static Program<C>,
- args: &[String],
-) -> Result<AnyOutput<C>, ProgramInternalExecuteError>
-where
- C: ProgramCollect<Enum = C>,
-{
- 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<C>(
- program: &'static Program<C>,
- args: &[String],
-) -> Result<(&'static (dyn Dispatcher<C> + Send + Sync), Vec<String>), ProgramInternalExecuteError>
-where
- C: ProgramCollect<Enum = C>,
-{
- 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<C> + 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<String> = 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<String> = args.iter().skip(prefix_len).cloned().collect();
- Ok((matched_prefix.1, trimmed_args))
- }
- }
-}
-
#[inline]
pub(crate) fn handle_program_control<C: ProgramCollect<Enum = C>>(
program: &Program<C>,
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::AnyOutput<Self>, crate::error::ProgramInternalExecuteError> {
+ unreachable!()
+ }
+
+ fn get_nodes() -> Vec<(String, &'static (dyn crate::Dispatcher<Self> + Send + Sync))> {
+ unreachable!()
+ }
+
fn build_renderer_not_found(_member_id: Self) -> crate::AnyOutput<Self> {
unreachable!()
}