From 596e5e2440df2d32f1cf3e052dc633e774edf6ee Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Sun, 29 Mar 2026 21:48:23 +0800 Subject: Rename mingling to mingling_core and update dependencies --- mingling_core/src/program/exec.rs | 126 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 mingling_core/src/program/exec.rs (limited to 'mingling_core/src/program/exec.rs') diff --git a/mingling_core/src/program/exec.rs b/mingling_core/src/program/exec.rs new file mode 100644 index 0000000..853bff1 --- /dev/null +++ b/mingling_core/src/program/exec.rs @@ -0,0 +1,126 @@ +#![allow(clippy::borrowed_box)] + +use crate::{ + AnyOutput, ChainProcess, Dispatcher, Next, Program, ProgramCollect, RenderResult, + error::ProgramInternalExecuteError, + hint::{DispatcherNotFound, RendererNotFound}, +}; + +pub mod error; + +pub async fn exec( + program: Program, +) -> Result { + // Match user input + let matched: (Box, Vec) = match match_user_input(&program) { + Ok(r) => (r.0.clone(), r.1), + Err(ProgramInternalExecuteError::DispatcherNotFound) => { + // If no Dispatcher is found, dispatch to the DispatcherNotFound Dispatcher + // to route it to the NoDispatcherFound struct + let disp: Box = Box::new(DispatcherNotFound); + (disp, program.args) + } + Err(e) => return Err(e), + }; + + // Entry point + let (dispatcher, args) = matched; + let mut current = match dispatcher.begin(args) { + ChainProcess::Ok((any, Next::Renderer)) => return Ok(render::(any)), + ChainProcess::Ok((any, Next::Chain)) => any, + ChainProcess::Err(e) => return Err(e.into()), + }; + + loop { + current = { + // If a chain exists, execute as a chain + if C::has_chain(¤t) { + match C::do_chain(current).await { + ChainProcess::Ok((any, Next::Renderer)) => return Ok(render::(any)), + ChainProcess::Ok((any, Next::Chain)) => any, + ChainProcess::Err(e) => return Err(e.into()), + } + } + // If no chain exists, attempt to render + else if C::has_renderer(¤t) { + let mut render_result = RenderResult::default(); + C::render(current, &mut render_result); + return Ok(render_result); + } + // If no renderer exists, transfer to the RendererNotFound Dispatcher for execution + else { + let disp: Box = Box::new(RendererNotFound); + + match disp.begin(vec![format!("{:?}", current.type_id)]) { + ChainProcess::Ok((any, Next::Renderer)) => return Ok(render::(any)), + ChainProcess::Ok((any, Next::Chain)) => any, + ChainProcess::Err(e) => return Err(e.into()), + } + } + }; + } +} + +/// Match user input against registered dispatchers and return the matched dispatcher and remaining arguments. +fn match_user_input( + program: &Program, +) -> Result<(&Box, Vec), ProgramInternalExecuteError> { + let nodes = get_nodes(program); + let command = format!("{} ", program.args.join(" ")); + + // Find all nodes that match the command prefix + let matching_nodes: Vec<&(String, &Box)> = 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 = program.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 = program.args.iter().skip(prefix_len).cloned().collect(); + Ok((matched_prefix.1, trimmed_args)) + } + } +} + +#[inline(always)] +fn render(any: AnyOutput) -> RenderResult { + let mut render_result = RenderResult::default(); + C::render(any, &mut render_result); + render_result +} + +// Get all registered dispatcher names from the program +fn get_nodes(program: &Program) -> Vec<(String, &Box)> { + program + .dispatcher + .iter() + .map(|disp| { + let node_str = disp + .node() + .to_string() + .split('.') + .collect::>() + .join(" "); + (node_str, disp) + }) + .collect() +} -- cgit