aboutsummaryrefslogtreecommitdiff
path: root/mingling_core/src
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
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')
-rw-r--r--mingling_core/src/asset/dispatcher.rs415
-rw-r--r--mingling_core/src/build/pathf.rs11
-rw-r--r--mingling_core/src/comp.rs40
-rw-r--r--mingling_core/src/program.rs55
-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
8 files changed, 26 insertions, 608 deletions
diff --git a/mingling_core/src/asset/dispatcher.rs b/mingling_core/src/asset/dispatcher.rs
index d700405..1ab7bf6 100644
--- a/mingling_core/src/asset/dispatcher.rs
+++ b/mingling_core/src/asset/dispatcher.rs
@@ -1,6 +1,6 @@
use std::fmt::Display;
-use crate::{ChainProcess, Program, ProgramCollect, asset::node::Node};
+use crate::{ChainProcess, asset::node::Node};
/// The entry logic of the Mingling program
///
@@ -148,307 +148,6 @@ where
}
}
-impl<C> Program<C>
-where
- C: ProgramCollect<Enum = C>,
-{
- /// Add a Dispatcher to the program
- ///
- /// This dynamically registers a Dispatcher into the program, used for command matching at program startup
- ///
- /// ```
- /// # use mingling_core::Program;
- /// # use mingling_core::ChainProcess;
- /// # use mingling_core::Dispatcher;
- /// # use mingling_core::Grouped;
- /// # use mingling_core::Routable;
- /// # use mingling_core::Node;
- /// # use mingling_core::MockProgramCollect as ThisProgram;
- /// # unsafe impl Grouped<ThisProgram> for Foo {
- /// # fn member_id() -> ThisProgram { ThisProgram::Foo }
- /// # }
- /// # struct CMDGreet;
- /// # struct Foo {
- /// # args: Vec<String>
- /// # }
- /// # impl Dispatcher<ThisProgram> for CMDGreet {
- /// # fn node(&self) -> Node {
- /// # Node::default().join("greet")
- /// # }
- /// # fn begin(&self, args: Vec<String>) -> ChainProcess<ThisProgram> {
- /// # Routable::to_chain(Foo { args })
- /// # }
- /// # fn clone_dispatcher(&self) -> Box<dyn Dispatcher<ThisProgram>> {
- /// # Box::new(CMDGreet)
- /// # }
- /// # }
- /// let mut program = Program::<ThisProgram>::new();
- /// program.with_dispatcher(CMDGreet);
- /// ```
- #[cfg_attr(
- feature = "dispatch_tree",
- deprecated(
- note = "When the `dispatch_tree` feature is enabled, the `dispatcher` field no longer exists inside Program. All types are collected at compile time by the `gen_program!()` macro, so the `with_dispatcher` function is no longer needed"
- )
- )]
- pub fn with_dispatcher<Disp>(&mut self, dispatcher: Disp) -> &mut Self
- where
- Disp: Dispatcher<C> + Send + Sync + 'static,
- {
- #[cfg(not(feature = "dispatch_tree"))]
- {
- self.dispatcher.push(Box::new(dispatcher));
- }
- #[cfg(feature = "dispatch_tree")]
- {
- let _ = dispatcher;
- }
- self
- }
-
- /// Add a group of Dispatchers to the program
- ///
- /// This dynamically registers a group of Dispatchers into the program, used for command matching at program startup
- ///
- /// ```
- /// # use mingling_core::Program;
- /// # use mingling_core::ChainProcess;
- /// # use mingling_core::Dispatcher;
- /// # use mingling_core::Grouped;
- /// # use mingling_core::Routable;
- /// # use mingling_core::Node;
- /// # use mingling_core::MockProgramCollect as ThisProgram;
- /// # unsafe impl Grouped<ThisProgram> for Foo {
- /// # fn member_id() -> ThisProgram { ThisProgram::Foo }
- /// # }
- /// # struct CMDGreet;
- /// # struct Foo {
- /// # args: Vec<String>
- /// # }
- /// # impl Dispatcher<ThisProgram> for CMDGreet {
- /// # fn node(&self) -> Node {
- /// # Node::default().join("greet")
- /// # }
- /// # fn begin(&self, args: Vec<String>) -> ChainProcess<ThisProgram> {
- /// # Routable::to_chain(Foo { args })
- /// # }
- /// # fn clone_dispatcher(&self) -> Box<dyn Dispatcher<ThisProgram>> {
- /// # Box::new(CMDGreet)
- /// # }
- /// # }
- /// let mut program = Program::<ThisProgram>::new();
- /// program.with_dispatchers((CMDGreet, /* Other Dispatchers */));
- /// ```
- #[deprecated(
- note = "with_dispatchers is no longer the recommended way to register Dispatchers, please split into multiple with_dispatcher calls"
- )]
- #[allow(deprecated)]
- pub fn with_dispatchers<D>(&mut self, dispatchers: D) -> &mut Self
- where
- D: Into<Dispatchers<C>>,
- {
- #[cfg(not(feature = "dispatch_tree"))]
- {
- let dispatchers = dispatchers.into();
- self.dispatcher.extend(dispatchers.dispatcher);
- }
- #[cfg(feature = "dispatch_tree")]
- {
- let _ = dispatchers;
- }
- self
- }
-}
-
-/// Represents a group of Dispatchers
-///
-/// It records a group of Dispatchers and implements conversion from tuples `(Disp, ..)` for this type,
-/// allowing for simpler construction syntax when using `with_dispatchers`
-///
-/// # Limits
-///
-/// Dispatchers supports conversion from tuples of up to 7 Dispatchers
-#[deprecated(
- note = "with_dispatchers is no longer the recommended way to register Dispatchers, please split into multiple with_dispatcher calls"
-)]
-pub struct Dispatchers<G> {
- dispatcher: Vec<Box<dyn Dispatcher<G> + Send + Sync + 'static>>,
-}
-
-#[allow(deprecated)]
-impl<G> From<Vec<Box<dyn Dispatcher<G> + Send + Sync>>> for Dispatchers<G> {
- fn from(dispatcher: Vec<Box<dyn Dispatcher<G> + Send + Sync>>) -> Self {
- Self { dispatcher }
- }
-}
-
-#[allow(deprecated)]
-impl<G> From<Box<dyn Dispatcher<G> + Send + Sync>> for Dispatchers<G> {
- fn from(dispatcher: Box<dyn Dispatcher<G> + Send + Sync>) -> Self {
- Self {
- dispatcher: vec![dispatcher],
- }
- }
-}
-
-#[allow(deprecated)]
-impl<D, G> From<(D,)> for Dispatchers<G>
-where
- D: Dispatcher<G> + Send + Sync + 'static,
- G: Display,
-{
- fn from(dispatcher: (D,)) -> Self {
- Self {
- dispatcher: vec![Box::new(dispatcher.0)],
- }
- }
-}
-
-#[allow(deprecated)]
-impl<D1, D2, G> From<(D1, D2)> for Dispatchers<G>
-where
- D1: Dispatcher<G> + Send + Sync + 'static,
- D2: Dispatcher<G> + Send + Sync + 'static,
- G: Display,
-{
- fn from(dispatchers: (D1, D2)) -> Self {
- Self {
- dispatcher: vec![Box::new(dispatchers.0), Box::new(dispatchers.1)],
- }
- }
-}
-
-#[allow(deprecated)]
-impl<D1, D2, D3, G> From<(D1, D2, D3)> for Dispatchers<G>
-where
- D1: Dispatcher<G> + Send + Sync + 'static,
- D2: Dispatcher<G> + Send + Sync + 'static,
- D3: Dispatcher<G> + Send + Sync + 'static,
- G: Display,
-{
- fn from(dispatchers: (D1, D2, D3)) -> Self {
- Self {
- dispatcher: vec![
- Box::new(dispatchers.0),
- Box::new(dispatchers.1),
- Box::new(dispatchers.2),
- ],
- }
- }
-}
-
-#[allow(deprecated)]
-impl<D1, D2, D3, D4, G> From<(D1, D2, D3, D4)> for Dispatchers<G>
-where
- D1: Dispatcher<G> + Send + Sync + 'static,
- D2: Dispatcher<G> + Send + Sync + 'static,
- D3: Dispatcher<G> + Send + Sync + 'static,
- D4: Dispatcher<G> + Send + Sync + 'static,
- G: Display,
-{
- fn from(dispatchers: (D1, D2, D3, D4)) -> Self {
- Self {
- dispatcher: vec![
- Box::new(dispatchers.0),
- Box::new(dispatchers.1),
- Box::new(dispatchers.2),
- Box::new(dispatchers.3),
- ],
- }
- }
-}
-
-#[allow(deprecated)]
-impl<D1, D2, D3, D4, D5, G> From<(D1, D2, D3, D4, D5)> for Dispatchers<G>
-where
- D1: Dispatcher<G> + Send + Sync + 'static,
- D2: Dispatcher<G> + Send + Sync + 'static,
- D3: Dispatcher<G> + Send + Sync + 'static,
- D4: Dispatcher<G> + Send + Sync + 'static,
- D5: Dispatcher<G> + Send + Sync + 'static,
- G: Display,
-{
- fn from(dispatchers: (D1, D2, D3, D4, D5)) -> Self {
- Self {
- dispatcher: vec![
- Box::new(dispatchers.0),
- Box::new(dispatchers.1),
- Box::new(dispatchers.2),
- Box::new(dispatchers.3),
- Box::new(dispatchers.4),
- ],
- }
- }
-}
-
-#[allow(deprecated)]
-impl<D1, D2, D3, D4, D5, D6, G> From<(D1, D2, D3, D4, D5, D6)> for Dispatchers<G>
-where
- D1: Dispatcher<G> + Send + Sync + 'static,
- D2: Dispatcher<G> + Send + Sync + 'static,
- D3: Dispatcher<G> + Send + Sync + 'static,
- D4: Dispatcher<G> + Send + Sync + 'static,
- D5: Dispatcher<G> + Send + Sync + 'static,
- D6: Dispatcher<G> + Send + Sync + 'static,
- G: Display,
-{
- fn from(dispatchers: (D1, D2, D3, D4, D5, D6)) -> Self {
- Self {
- dispatcher: vec![
- Box::new(dispatchers.0),
- Box::new(dispatchers.1),
- Box::new(dispatchers.2),
- Box::new(dispatchers.3),
- Box::new(dispatchers.4),
- Box::new(dispatchers.5),
- ],
- }
- }
-}
-
-#[allow(deprecated)]
-impl<D1, D2, D3, D4, D5, D6, D7, G> From<(D1, D2, D3, D4, D5, D6, D7)> for Dispatchers<G>
-where
- D1: Dispatcher<G> + Send + Sync + 'static,
- D2: Dispatcher<G> + Send + Sync + 'static,
- D3: Dispatcher<G> + Send + Sync + 'static,
- D4: Dispatcher<G> + Send + Sync + 'static,
- D5: Dispatcher<G> + Send + Sync + 'static,
- D6: Dispatcher<G> + Send + Sync + 'static,
- D7: Dispatcher<G> + Send + Sync + 'static,
- G: Display,
-{
- fn from(dispatchers: (D1, D2, D3, D4, D5, D6, D7)) -> Self {
- Self {
- dispatcher: vec![
- Box::new(dispatchers.0),
- Box::new(dispatchers.1),
- Box::new(dispatchers.2),
- Box::new(dispatchers.3),
- Box::new(dispatchers.4),
- Box::new(dispatchers.5),
- Box::new(dispatchers.6),
- ],
- }
- }
-}
-
-#[allow(deprecated)]
-impl<G> std::ops::Deref for Dispatchers<G> {
- type Target = Vec<Box<dyn Dispatcher<G> + Send + Sync + 'static>>;
-
- fn deref(&self) -> &Self::Target {
- &self.dispatcher
- }
-}
-
-#[allow(deprecated)]
-impl<G> From<Dispatchers<G>> for Vec<Box<dyn Dispatcher<G> + Send + Sync + 'static>> {
- fn from(val: Dispatchers<G>) -> Self {
- val.dispatcher
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
@@ -485,118 +184,6 @@ mod tests {
}
#[test]
- #[allow(deprecated)]
- fn test_dispatchers_from_single_tuple() {
- let disp = MockDispatcher { name: "foo" };
- let dispatchers: Dispatchers<MockG> = Dispatchers::from((disp,));
- assert_eq!(dispatchers.dispatcher.len(), 1);
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_dispatchers_from_two_tuple() {
- let d1 = MockDispatcher { name: "a" };
- let d2 = MockDispatcher { name: "b" };
- let dispatchers: Dispatchers<MockG> = Dispatchers::from((d1, d2));
- assert_eq!(dispatchers.dispatcher.len(), 2);
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_dispatchers_from_three_tuple() {
- let d1 = MockDispatcher { name: "x" };
- let d2 = MockDispatcher { name: "y" };
- let d3 = MockDispatcher { name: "z" };
- let dispatchers: Dispatchers<MockG> = Dispatchers::from((d1, d2, d3));
- assert_eq!(dispatchers.dispatcher.len(), 3);
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_dispatchers_from_four_tuple() {
- let d1 = MockDispatcher { name: "1" };
- let d2 = MockDispatcher { name: "2" };
- let d3 = MockDispatcher { name: "3" };
- let d4 = MockDispatcher { name: "4" };
- let dispatchers: Dispatchers<MockG> = Dispatchers::from((d1, d2, d3, d4));
- assert_eq!(dispatchers.dispatcher.len(), 4);
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_dispatchers_from_five_tuple() {
- let d1 = MockDispatcher { name: "a" };
- let d2 = MockDispatcher { name: "b" };
- let d3 = MockDispatcher { name: "c" };
- let d4 = MockDispatcher { name: "d" };
- let d5 = MockDispatcher { name: "e" };
- let dispatchers: Dispatchers<MockG> = Dispatchers::from((d1, d2, d3, d4, d5));
- assert_eq!(dispatchers.dispatcher.len(), 5);
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_dispatchers_from_six_tuple() {
- let d1 = MockDispatcher { name: "a" };
- let d2 = MockDispatcher { name: "b" };
- let d3 = MockDispatcher { name: "c" };
- let d4 = MockDispatcher { name: "d" };
- let d5 = MockDispatcher { name: "e" };
- let d6 = MockDispatcher { name: "f" };
- let dispatchers: Dispatchers<MockG> = Dispatchers::from((d1, d2, d3, d4, d5, d6));
- assert_eq!(dispatchers.dispatcher.len(), 6);
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_dispatchers_from_seven_tuple() {
- let d1 = MockDispatcher { name: "a" };
- let d2 = MockDispatcher { name: "b" };
- let d3 = MockDispatcher { name: "c" };
- let d4 = MockDispatcher { name: "d" };
- let d5 = MockDispatcher { name: "e" };
- let d6 = MockDispatcher { name: "f" };
- let d7 = MockDispatcher { name: "g" };
- let dispatchers: Dispatchers<MockG> = Dispatchers::from((d1, d2, d3, d4, d5, d6, d7));
- assert_eq!(dispatchers.dispatcher.len(), 7);
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_dispatchers_from_vec_of_boxed() {
- let d1: Box<dyn Dispatcher<MockG> + Send + Sync> = Box::new(MockDispatcher { name: "a" });
- let d2: Box<dyn Dispatcher<MockG> + Send + Sync> = Box::new(MockDispatcher { name: "b" });
- let dispatchers: Dispatchers<MockG> = vec![d1, d2].into();
- assert_eq!(dispatchers.dispatcher.len(), 2);
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_dispatchers_from_single_boxed() {
- let d: Box<dyn Dispatcher<MockG> + Send + Sync> = Box::new(MockDispatcher { name: "x" });
- let dispatchers: Dispatchers<MockG> = d.into();
- assert_eq!(dispatchers.dispatcher.len(), 1);
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_dispatchers_deref() {
- let disp = MockDispatcher { name: "test" };
- let dispatchers: Dispatchers<MockG> = Dispatchers::from((disp,));
- let inner: &Vec<Box<dyn Dispatcher<MockG> + Send + Sync + 'static>> = &dispatchers;
- assert_eq!(inner.len(), 1);
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_dispatchers_into_vec() {
- let disp = MockDispatcher { name: "foo" };
- let dispatchers: Dispatchers<MockG> = Dispatchers::from((disp,));
- let vec: Vec<Box<dyn Dispatcher<MockG> + Send + Sync + 'static>> = dispatchers.into();
- assert_eq!(vec.len(), 1);
- }
-
- #[test]
fn test_box_clone_dispatcher() {
let disp: Box<dyn Dispatcher<MockG>> = Box::new(MockDispatcher { name: "clonable" });
let cloned = disp.clone_dispatcher();
diff --git a/mingling_core/src/build/pathf.rs b/mingling_core/src/build/pathf.rs
index 23d3910..4b8af1b 100644
--- a/mingling_core/src/build/pathf.rs
+++ b/mingling_core/src/build/pathf.rs
@@ -1,6 +1,5 @@
#![allow(unused_imports)]
-pub use mingling_pathf::config::*;
pub use mingling_pathf::module_pathf::*;
pub use mingling_pathf::pattern_analyzer::*;
pub use mingling_pathf::patterns::*;
@@ -37,10 +36,7 @@ pub fn analyze_and_build_type_mapping_for(
crate_dir: &Path,
output_dir: &Path,
) -> Result<(), crate::error::MinglingPathfinderError> {
- let config = mingling_pathf::config::PathfinderConfig {
- use_dispatch_tree: cfg!(feature = "dispatch_tree"),
- };
- mingling_pathf::analyze_and_build_type_mapping_for(crate_dir, output_dir, &config)
+ mingling_pathf::analyze_and_build_type_mapping_for(crate_dir, output_dir)
}
/// # Analyzes and builds a type mapping
@@ -81,9 +77,6 @@ pub fn analyze_and_build_type_mapping_for(
/// ```
pub fn analyze_and_build_type_mapping() -> Result<(), crate::error::MinglingPathfinderError> {
- let config = mingling_pathf::config::PathfinderConfig {
- use_dispatch_tree: cfg!(feature = "dispatch_tree"),
- };
let crate_dir =
std::env::current_dir().map_err(crate::error::MinglingPathfinderError::IoError)?;
let crate_name = std::env::var("CARGO_PKG_NAME").map_err(|_| {
@@ -99,7 +92,7 @@ pub fn analyze_and_build_type_mapping() -> Result<(), crate::error::MinglingPath
))
})?;
let output_dir = Path::new(&out_dir).join(&crate_name);
- mingling_pathf::analyze_and_build_type_mapping_for(&crate_dir, &output_dir, &config)?;
+ mingling_pathf::analyze_and_build_type_mapping_for(&crate_dir, &output_dir)?;
println!("cargo:rerun-if-changed=src/");
Ok(())
}
diff --git a/mingling_core/src/comp.rs b/mingling_core/src/comp.rs
index aea46e1..399c9bf 100644
--- a/mingling_core/src/comp.rs
+++ b/mingling_core/src/comp.rs
@@ -37,12 +37,6 @@ pub const COMPLETION_SUBCOMMAND: &str = "__comp";
#[cfg(feature = "debug")]
use crate::debug::init_env_logger;
-#[cfg(not(feature = "dispatch_tree"))]
-use crate::ChainProcess;
-
-#[cfg(not(feature = "dispatch_tree"))]
-use crate::exec::match_user_input;
-
/// Mingling Completion Entry Point
///
/// Defines the custom completion logic entry point for the program's shell
@@ -174,30 +168,6 @@ impl CompletionHelper {
let args = first_cmd_match.map_or_else(Vec::new, |start| all_args[start..].to_vec());
trace!("arguments=\"{}\"", args.join(", "));
- #[cfg(not(feature = "dispatch_tree"))]
- let program = this::<P>();
-
- #[cfg(not(feature = "dispatch_tree"))]
- let suggest = if let Ok((dispatcher, args)) = match_user_input(program, &args) {
- trace!(
- "dispatcher matched, dispatcher=\"{}\"",
- dispatcher.node().to_string(),
- );
- let begin = dispatcher.begin(args);
- if let crate::ChainProcess::Ok((any, _)) = begin {
- trace!("entry type: {}", any.member_id);
- let result = P::do_comp(&any, ctx);
- trace!("do_comp result: {:?}", result);
- Some(result)
- } else {
- trace!("begin not Ok");
- None
- }
- } else {
- trace!("no dispatcher matched");
- None
- };
- #[cfg(feature = "dispatch_tree")]
let suggest = if let Ok(any) = P::dispatch_args(&args) {
debug!("dispatch_args OK, member_id = {:?}", any.member_id);
trace!("entry type: {}", any.member_id);
@@ -354,18 +324,8 @@ where
{
let words: Vec<String> = node.split(' ').map(str::to_string).collect();
- #[cfg(feature = "dispatch_tree")]
let lazy_member = P::dispatch_args(&words).ok().map(|any| any.member_id);
- #[cfg(not(feature = "dispatch_tree"))]
- let lazy_member = match match_user_input(this::<P>(), &words) {
- Ok((dispatcher, args)) => match dispatcher.begin(args) {
- ChainProcess::Ok((any, _)) => Some(any.member_id),
- ChainProcess::Err(_) => None,
- },
- Err(_) => None,
- };
-
let member_id = lazy_member?;
P::get_metadata::<Description>(member_id).map(String::from)
}
diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs
index 7bafe72..1c8fb07 100644
--- a/mingling_core/src/program.rs
+++ b/mingling_core/src/program.rs
@@ -53,9 +53,6 @@ where
pub(crate) args: Vec<String>,
- #[cfg(not(feature = "dispatch_tree"))]
- pub(crate) dispatcher: Vec<Box<dyn Dispatcher<C> + Send + Sync>>,
-
/// Program stdout settings.
///
/// This struct controls the program's output behavior, including whether
@@ -116,9 +113,6 @@ where
collect: std::marker::PhantomData,
args: args.into().into(),
- #[cfg(not(feature = "dispatch_tree"))]
- dispatcher: Vec::new(),
-
stdout_setting: ProgramStdoutSetting::default(),
user_context: ProgramUserContext::default(),
@@ -188,25 +182,12 @@ where
get_nodes(self)
}
- /// Dynamically dispatch input arguments to registered entry types
+ /// Dispatch input arguments to an entry
///
/// # Errors
///
/// Returns `Err(ChainProcessError)` if the dispatch fails,
/// e.g., if no dispatcher is found for the given arguments.
- pub fn dispatch_args_dynamic(
- &'static self,
- args: impl Into<StringVec>,
- ) -> Result<AnyOutput<C>, ChainProcessError> {
- let sv: Vec<String> = args.into().into();
- match exec::dispatch_args_dynamic(self, &sv) {
- Ok(ok) => Ok(ok),
- Err(e) => Err(e.into()),
- }
- }
-
- /// Use a prefix tree to quickly match arguments and dispatch to an Entry
- #[cfg(feature = "dispatch_tree")]
pub fn dispatch_args(
&'static self,
args: impl Into<StringVec>,
@@ -225,40 +206,12 @@ where
pub fn get_nodes<C: ProgramCollect<Enum = C>>(
program: &'static Program<C>,
) -> Vec<(String, &'static (dyn Dispatcher<C> + Send + Sync + 'static))> {
- #[cfg(feature = "dispatch_tree")]
let r = C::get_nodes();
- #[cfg(feature = "dispatch_tree")]
- {
- #[cfg(feature = "debug")]
- {
- let node_strs: Vec<String> = r.iter().map(|v| v.0.clone()).collect();
- crate::info!("All Nodes: [{}]", node_strs.join(", "));
- }
- }
-
- #[cfg(not(feature = "dispatch_tree"))]
- let r: Vec<_> = program
- .dispatcher
- .iter()
- .map(|disp| {
- let node_str = disp
- .node()
- .to_string()
- .split('.')
- .collect::<Vec<_>>()
- .join(" ");
- (node_str, &**disp)
- })
- .collect();
-
- #[cfg(not(feature = "dispatch_tree"))]
+ #[cfg(feature = "debug")]
{
- #[cfg(feature = "debug")]
- {
- let node_strs: Vec<String> = r.iter().map(|v| v.0.clone()).collect();
- crate::info!("All Nodes: [{}]", node_strs.join(", "));
- }
+ let node_strs: Vec<String> = r.iter().map(|v| v.0.clone()).collect();
+ crate::info!("All Nodes: [{}]", node_strs.join(", "));
}
r
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!()
}