diff options
Diffstat (limited to 'mingling_core/src/program')
| -rw-r--r-- | mingling_core/src/program/exec.rs | 69 | ||||
| -rw-r--r-- | mingling_core/src/program/exec/error.rs | 12 | ||||
| -rw-r--r-- | mingling_core/src/program/flag.rs | 9 | ||||
| -rw-r--r-- | mingling_core/src/program/hint.rs | 62 | ||||
| -rw-r--r-- | mingling_core/src/program/setup.rs | 15 | ||||
| -rw-r--r-- | mingling_core/src/program/setup/basic.rs | 7 |
6 files changed, 67 insertions, 107 deletions
diff --git a/mingling_core/src/program/exec.rs b/mingling_core/src/program/exec.rs index 853bff1..cdbb2b0 100644 --- a/mingling_core/src/program/exec.rs +++ b/mingling_core/src/program/exec.rs @@ -1,42 +1,44 @@ #![allow(clippy::borrowed_box)] +use std::fmt::Display; + 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> { +pub async fn exec<C, G>(program: Program<C, G>) -> Result<RenderResult, ProgramInternalExecuteError> +where + C: ProgramCollect<Enum = G>, + G: Display, +{ + let mut current; + // Match user input - let matched: (Box<dyn Dispatcher>, Vec<String>) = match match_user_input(&program) { - Ok(r) => (r.0.clone(), r.1), + match match_user_input(&program) { + Ok((dispatcher, args)) => { + // Entry point + current = match dispatcher.begin(args) { + ChainProcess::Ok((any, Next::Renderer)) => return Ok(render::<C, G>(any)), + ChainProcess::Ok((any, Next::Chain)) => any, + ChainProcess::Err(e) => return Err(e.into()), + }; + } 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) + // No matching Dispatcher is found + return Err(ProgramInternalExecuteError::DispatcherNotFound); } 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::Renderer)) => return Ok(render::<C, G>(any)), ChainProcess::Ok((any, Next::Chain)) => any, ChainProcess::Err(e) => return Err(e.into()), } @@ -47,29 +49,28 @@ pub async fn exec<C: ProgramCollect>( C::render(current, &mut render_result); return Ok(render_result); } - // If no renderer exists, transfer to the RendererNotFound Dispatcher for execution + // No renderer exists 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()), - } + let renderer_name = current.member_id.to_string(); + return Err(ProgramInternalExecuteError::RendererNotFound(renderer_name)); } }; } } /// 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> { +fn match_user_input<C, G>( + program: &Program<C, G>, +) -> Result<(&Box<dyn Dispatcher<G>>, Vec<String>), ProgramInternalExecuteError> +where + C: ProgramCollect<Enum = G>, + G: Display, +{ 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 + let matching_nodes: Vec<&(String, &Box<dyn Dispatcher<G>>)> = nodes .iter() // Also add a space to the node string to ensure consistent matching logic .filter(|(node_str, _)| command.starts_with(&format!("{} ", node_str))) @@ -102,14 +103,16 @@ fn match_user_input<C: ProgramCollect>( } #[inline(always)] -fn render<C: ProgramCollect>(any: AnyOutput) -> RenderResult { +fn render<C: ProgramCollect<Enum = G>, G: Display>(any: AnyOutput<G>) -> 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>)> { +fn get_nodes<C: ProgramCollect<Enum = G>, G: Display>( + program: &Program<C, G>, +) -> Vec<(String, &Box<dyn Dispatcher<G>>)> { program .dispatcher .iter() diff --git a/mingling_core/src/program/exec/error.rs b/mingling_core/src/program/exec/error.rs index fe66e22..b4ff378 100644 --- a/mingling_core/src/program/exec/error.rs +++ b/mingling_core/src/program/exec/error.rs @@ -5,6 +5,9 @@ pub enum ProgramExecuteError { #[error("No Dispatcher Found")] DispatcherNotFound, + #[error("No Renderer (`{0}`) Found")] + RendererNotFound(String), + #[error("Other error: {0}")] Other(String), } @@ -14,6 +17,9 @@ pub enum ProgramInternalExecuteError { #[error("No Dispatcher Found")] DispatcherNotFound, + #[error("No Renderer (`{0}`) Found")] + RendererNotFound(String), + #[error("Other error: {0}")] Other(String), @@ -27,6 +33,9 @@ impl From<ProgramInternalExecuteError> for ProgramExecuteError { ProgramInternalExecuteError::DispatcherNotFound => { ProgramExecuteError::DispatcherNotFound } + ProgramInternalExecuteError::RendererNotFound(s) => { + ProgramExecuteError::RendererNotFound(s) + } ProgramInternalExecuteError::Other(s) => ProgramExecuteError::Other(s), ProgramInternalExecuteError::IO(e) => ProgramExecuteError::Other(format!("{}", e)), } @@ -38,9 +47,6 @@ impl From<ChainProcessError> for ProgramInternalExecuteError { 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_core/src/program/flag.rs b/mingling_core/src/program/flag.rs index 74435e4..84fae01 100644 --- a/mingling_core/src/program/flag.rs +++ b/mingling_core/src/program/flag.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + use crate::{Program, ProgramCollect}; pub struct Flag { @@ -88,14 +90,15 @@ macro_rules! special_argument { }}; } -impl<C> Program<C> +impl<C, G> Program<C, G> where C: ProgramCollect, + G: Display, { /// 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), + F: Fn(&mut Program<C, G>, String), A: Into<Flag>, { let flag = arguments.into(); @@ -111,7 +114,7 @@ where /// 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>), + F: Fn(&mut Program<C, G>), A: Into<Flag>, { let flag = flag.into(); diff --git a/mingling_core/src/program/hint.rs b/mingling_core/src/program/hint.rs deleted file mode 100644 index 6dbbac2..0000000 --- a/mingling_core/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_core/src/program/setup.rs b/mingling_core/src/program/setup.rs index e81247e..1f16f80 100644 --- a/mingling_core/src/program/setup.rs +++ b/mingling_core/src/program/setup.rs @@ -1,18 +1,25 @@ +use std::fmt::Display; + use crate::{ProgramCollect, program::Program}; mod basic; pub use basic::*; -pub trait ProgramSetup<C: ProgramCollect> { - fn setup(&mut self, program: &mut Program<C>); +pub trait ProgramSetup<C, G> +where + C: ProgramCollect, + G: Display, +{ + fn setup(&mut self, program: &mut Program<C, G>); } -impl<C> Program<C> +impl<C, G> Program<C, G> where C: ProgramCollect, + G: Display, { /// Load and execute init logic - pub fn with_setup<S: ProgramSetup<C> + 'static>(&mut self, mut setup: S) -> S { + pub fn with_setup<S: ProgramSetup<C, G> + 'static>(&mut self, mut setup: S) -> S { S::setup(&mut setup, self); setup } diff --git a/mingling_core/src/program/setup/basic.rs b/mingling_core/src/program/setup/basic.rs index 43c14b9..8316a33 100644 --- a/mingling_core/src/program/setup/basic.rs +++ b/mingling_core/src/program/setup/basic.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + use crate::{ ProgramCollect, program::{Program, setup::ProgramSetup}, @@ -10,11 +12,12 @@ use crate::{ /// - Collects `--confirm` flag to skip user confirmation pub struct BasicProgramSetup; -impl<C> ProgramSetup<C> for BasicProgramSetup +impl<C, G> ProgramSetup<C, G> for BasicProgramSetup where C: ProgramCollect, + G: Display, { - fn setup(&mut self, program: &mut Program<C>) { + fn setup(&mut self, program: &mut Program<C, G>) { program.global_flag(["--quiet", "-q"], |p| { p.stdout_setting.render_output = false; p.stdout_setting.error_output = false; |
