diff options
Diffstat (limited to 'mingling/src/program')
| -rw-r--r-- | mingling/src/program/config.rs | 26 | ||||
| -rw-r--r-- | mingling/src/program/exec.rs | 126 | ||||
| -rw-r--r-- | mingling/src/program/exec/error.rs | 46 | ||||
| -rw-r--r-- | mingling/src/program/flag.rs | 148 | ||||
| -rw-r--r-- | mingling/src/program/hint.rs | 62 | ||||
| -rw-r--r-- | mingling/src/program/setup.rs | 19 | ||||
| -rw-r--r-- | mingling/src/program/setup/basic.rs | 31 |
7 files changed, 0 insertions, 458 deletions
diff --git a/mingling/src/program/config.rs b/mingling/src/program/config.rs deleted file mode 100644 index 386b112..0000000 --- a/mingling/src/program/config.rs +++ /dev/null @@ -1,26 +0,0 @@ -#[derive(Debug, Clone)] -pub struct ProgramStdoutSetting { - /// Output error messages - pub error_output: bool, - - /// Render results and output - pub render_output: bool, -} - -impl Default for ProgramStdoutSetting { - fn default() -> Self { - ProgramStdoutSetting { - error_output: true, - render_output: true, - } - } -} - -#[derive(Debug, Clone, Default)] -pub struct ProgramUserContext { - /// View help information instead of running the command - pub help: bool, - - /// Skip user confirmation step - pub confirm: bool, -} diff --git a/mingling/src/program/exec.rs b/mingling/src/program/exec.rs deleted file mode 100644 index 853bff1..0000000 --- a/mingling/src/program/exec.rs +++ /dev/null @@ -1,126 +0,0 @@ -#![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<C: ProgramCollect>( - program: Program<C>, -) -> Result<RenderResult, ProgramInternalExecuteError> { - // Match user input - let matched: (Box<dyn Dispatcher>, Vec<String>) = 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<dyn Dispatcher> = 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::<C>(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::<C>(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<dyn Dispatcher> = Box::new(RendererNotFound); - - match disp.begin(vec![format!("{:?}", current.type_id)]) { - ChainProcess::Ok((any, Next::Renderer)) => return Ok(render::<C>(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<C: ProgramCollect>( - program: &Program<C>, -) -> Result<(&Box<dyn Dispatcher>, Vec<String>), 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<dyn Dispatcher>)> = 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> = 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<String> = program.args.iter().skip(prefix_len).cloned().collect(); - Ok((matched_prefix.1, trimmed_args)) - } - } -} - -#[inline(always)] -fn render<C: ProgramCollect>(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<C: ProgramCollect>(program: &Program<C>) -> Vec<(String, &Box<dyn Dispatcher>)> { - program - .dispatcher - .iter() - .map(|disp| { - let node_str = disp - .node() - .to_string() - .split('.') - .collect::<Vec<_>>() - .join(" "); - (node_str, disp) - }) - .collect() -} diff --git a/mingling/src/program/exec/error.rs b/mingling/src/program/exec/error.rs deleted file mode 100644 index fe66e22..0000000 --- a/mingling/src/program/exec/error.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::error::ChainProcessError; - -#[derive(thiserror::Error, Debug)] -pub enum ProgramExecuteError { - #[error("No Dispatcher Found")] - DispatcherNotFound, - - #[error("Other error: {0}")] - Other(String), -} - -#[derive(thiserror::Error, Debug)] -pub enum ProgramInternalExecuteError { - #[error("No Dispatcher Found")] - DispatcherNotFound, - - #[error("Other error: {0}")] - Other(String), - - #[error("IO error: {0}")] - IO(#[from] std::io::Error), -} - -impl From<ProgramInternalExecuteError> for ProgramExecuteError { - fn from(value: ProgramInternalExecuteError) -> Self { - match value { - ProgramInternalExecuteError::DispatcherNotFound => { - ProgramExecuteError::DispatcherNotFound - } - ProgramInternalExecuteError::Other(s) => ProgramExecuteError::Other(s), - ProgramInternalExecuteError::IO(e) => ProgramExecuteError::Other(format!("{}", e)), - } - } -} - -impl From<ChainProcessError> for ProgramInternalExecuteError { - fn from(value: ChainProcessError) -> Self { - match value { - ChainProcessError::Other(s) => ProgramInternalExecuteError::Other(s), - ChainProcessError::IO(error) => ProgramInternalExecuteError::IO(error), - ChainProcessError::Broken(_) => { - ProgramInternalExecuteError::Other("Broken".to_string()) - } - } - } -} diff --git a/mingling/src/program/flag.rs b/mingling/src/program/flag.rs deleted file mode 100644 index 3a678be..0000000 --- a/mingling/src/program/flag.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::{Program, ProgramCollect}; - -pub struct Flag { - vec: Vec<&'static str>, -} - -impl From<&'static str> for Flag { - fn from(s: &'static str) -> Self { - Flag { vec: vec![s] } - } -} - -impl From<&'static [&'static str]> for Flag { - fn from(slice: &'static [&'static str]) -> Self { - Flag { - vec: slice.to_vec(), - } - } -} - -impl<const N: usize> From<[&'static str; N]> for Flag { - fn from(slice: [&'static str; N]) -> Self { - Flag { - vec: slice.to_vec(), - } - } -} - -impl<const N: usize> From<&'static [&'static str; N]> for Flag { - fn from(slice: &'static [&'static str; N]) -> Self { - Flag { - vec: slice.to_vec(), - } - } -} - -impl AsRef<[&'static str]> for Flag { - fn as_ref(&self) -> &[&'static str] { - &self.vec - } -} - -impl std::ops::Deref for Flag { - type Target = [&'static str]; - - fn deref(&self) -> &Self::Target { - &self.vec - } -} - -macro_rules! special_flag { - ($args:expr, $flag:expr) => {{ - let flag = $flag; - let found = $args.iter().any(|arg| arg == flag); - $args.retain(|arg| arg != flag); - found - }}; -} - -macro_rules! special_argument { - ($args:expr, $flag:expr) => {{ - let flag = $flag; - let mut value: Option<String> = None; - let mut i = 0; - while i < $args.len() { - if &$args[i] == flag { - if i + 1 < $args.len() { - value = Some($args[i + 1].clone()); - $args.remove(i + 1); - $args.remove(i); - } else { - value = None; - $args.remove(i); - } - break; - } - i += 1; - } - value - }}; -} - -impl<C> Program<C> -where - C: ProgramCollect, -{ - /// Registers a global argument (with value) and its handler. - pub fn global_argument<F, A>(&mut self, arguments: A, do_fn: F) - where - F: Fn(&mut Program<C>, String), - A: Into<Flag>, - { - let flag = arguments.into(); - for argument in flag.iter() { - let value = special_argument!(self.args, argument); - if let Some(value) = value { - do_fn(self, value); - return; - } - } - } - - /// Registers a global flag (boolean) and its handler. - pub fn global_flag<F, A>(&mut self, flag: A, do_fn: F) - where - F: Fn(&mut Program<C>), - A: Into<Flag>, - { - let flag = flag.into(); - for argument in flag.iter() { - let enabled = special_flag!(self.args, argument); - if enabled { - do_fn(self); - return; - } - } - } - - /// Extracts a global argument (with value) from arguments - pub fn pick_global_argument<F>(&mut self, flag: F) -> Option<String> - where - F: Into<Flag>, - { - let flag: Flag = flag.into(); - for argument in flag.iter() { - let value = special_argument!(self.args, argument); - if value.is_some() { - return value; - } - } - None - } - - /// Extracts global flags from arguments - pub fn pick_global_flag<F>(&mut self, flag: F) -> bool - where - F: Into<Flag>, - { - let flag: Flag = flag.into(); - for argument in flag.iter() { - let enabled = special_flag!(self.args, argument); - if enabled { - return enabled; - } - } - false - } -} diff --git a/mingling/src/program/hint.rs b/mingling/src/program/hint.rs deleted file mode 100644 index 6dbbac2..0000000 --- a/mingling/src/program/hint.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::{AnyOutput, ChainProcess, Dispatcher, Node}; - -/// Marker: Dispatcher Not Found -/// -/// If a Dispatcher outputs NoDispatcherFound to the Chain, -/// the program will terminate directly. -/// -/// You can implement Renderer for NoDispatcherFound -/// to render relevant information when a Dispatcher cannot be found. -#[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] -pub struct NoDispatcherFound { - pub args: Vec<String>, -} - -#[derive(Default)] -#[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] -pub struct DispatcherNotFound; -impl Dispatcher for DispatcherNotFound { - fn node(&self) -> crate::Node { - Node::default().join("_not_found") - } - - fn begin(&self, args: Vec<String>) -> ChainProcess { - AnyOutput::new(NoDispatcherFound { args }).route_renderer() - } - - fn clone_dispatcher(&self) -> Box<dyn Dispatcher> { - Box::new(DispatcherNotFound) - } -} - -/// Marker: Renderer Not Found -/// -/// If a Chain outputs NoRendererFound to the Chain, -/// the program will terminate directly. -/// -/// You can implement Renderer for NoRendererFound -/// to render relevant information when a Renderer cannot be found. -#[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] -pub struct NoRendererFound { - pub type_to_render: String, -} - -#[derive(Default)] -#[cfg_attr(feature = "general_renderer", derive(serde::Serialize))] -pub struct RendererNotFound; -impl Dispatcher for RendererNotFound { - fn node(&self) -> crate::Node { - Node::default().join("_not_found") - } - - fn begin(&self, args: Vec<String>) -> ChainProcess { - AnyOutput::new(NoRendererFound { - type_to_render: args.first().unwrap().clone(), - }) - .route_renderer() - } - - fn clone_dispatcher(&self) -> Box<dyn Dispatcher> { - Box::new(RendererNotFound) - } -} diff --git a/mingling/src/program/setup.rs b/mingling/src/program/setup.rs deleted file mode 100644 index e81247e..0000000 --- a/mingling/src/program/setup.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::{ProgramCollect, program::Program}; - -mod basic; -pub use basic::*; - -pub trait ProgramSetup<C: ProgramCollect> { - fn setup(&mut self, program: &mut Program<C>); -} - -impl<C> Program<C> -where - C: ProgramCollect, -{ - /// Load and execute init logic - pub fn with_setup<S: ProgramSetup<C> + 'static>(&mut self, mut setup: S) -> S { - S::setup(&mut setup, self); - setup - } -} diff --git a/mingling/src/program/setup/basic.rs b/mingling/src/program/setup/basic.rs deleted file mode 100644 index 43c14b9..0000000 --- a/mingling/src/program/setup/basic.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::{ - ProgramCollect, - program::{Program, setup::ProgramSetup}, -}; - -/// Performs basic program initialization: -/// -/// - Collects `--quiet` flag to control message rendering -/// - Collects `--help` flag to enable help mode -/// - Collects `--confirm` flag to skip user confirmation -pub struct BasicProgramSetup; - -impl<C> ProgramSetup<C> for BasicProgramSetup -where - C: ProgramCollect, -{ - fn setup(&mut self, program: &mut Program<C>) { - program.global_flag(["--quiet", "-q"], |p| { - p.stdout_setting.render_output = false; - p.stdout_setting.error_output = false; - }); - - program.global_flag(["--help", "-h"], |p| { - p.user_context.help = true; - }); - - program.global_flag(["--confirm", "-C"], |p| { - p.user_context.confirm = true; - }); - } -} |
