From 3de10ca22cca06c4d9069984d0e66e370a331dde Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Wed, 1 Apr 2026 15:48:41 +0800 Subject: Replace typeid-based dispatch with enum-based dispatch - Add `Groupped` trait and `member_id` to `AnyOutput` - Add generic parameter `G` to `Dispatcher`, `Chain`, `Program` etc - Remove `hint` module and its marker types - Update macros to support explicit group specification - Add `gen_program` macro for generating enum-based programs - Add `GroupProcess` marker type for type-level grouping --- mingling_core/src/any.rs | 56 ++++++++---- mingling_core/src/any/group.rs | 3 + mingling_core/src/asset/chain.rs | 9 +- mingling_core/src/asset/chain/error.rs | 5 -- mingling_core/src/asset/dispatcher.rs | 140 ++++++++++++++++------------- mingling_core/src/lib.rs | 9 +- mingling_core/src/markers.rs | 1 + mingling_core/src/markers/group_process.rs | 2 + mingling_core/src/program.rs | 57 +++++++----- mingling_core/src/program/exec.rs | 69 +++++++------- mingling_core/src/program/exec/error.rs | 12 ++- mingling_core/src/program/flag.rs | 9 +- mingling_core/src/program/hint.rs | 62 ------------- mingling_core/src/program/setup.rs | 15 +++- mingling_core/src/program/setup/basic.rs | 7 +- 15 files changed, 238 insertions(+), 218 deletions(-) create mode 100644 mingling_core/src/any/group.rs create mode 100644 mingling_core/src/markers.rs create mode 100644 mingling_core/src/markers/group_process.rs delete mode 100644 mingling_core/src/program/hint.rs (limited to 'mingling_core') diff --git a/mingling_core/src/any.rs b/mingling_core/src/any.rs index 1bce96a..dac0d44 100644 --- a/mingling_core/src/any.rs +++ b/mingling_core/src/any.rs @@ -1,34 +1,48 @@ +use std::fmt::Display; + #[cfg(feature = "general_renderer")] use serde::Serialize; +use crate::Groupped; use crate::error::ChainProcessError; +pub mod group; + #[derive(Debug)] -pub struct AnyOutput { +pub struct AnyOutput +where + G: Display, +{ inner: Box, pub type_id: std::any::TypeId, + pub member_id: G, } -impl AnyOutput { +impl AnyOutput +where + G: Display, +{ #[cfg(feature = "general_renderer")] pub fn new(value: T) -> Self where - T: Send + Serialize + 'static, + T: Send + Groupped + Serialize + 'static, { Self { inner: Box::new(value), type_id: std::any::TypeId::of::(), + member_id: T::member_id(), } } #[cfg(not(feature = "general_renderer"))] pub fn new(value: T) -> Self where - T: Send + 'static, + T: Send + Groupped + 'static, { Self { inner: Box::new(value), type_id: std::any::TypeId::of::(), + member_id: T::member_id(), } } @@ -45,17 +59,20 @@ impl AnyOutput { } /// Route the output to the next Chain - pub fn route_chain(self) -> ChainProcess { + pub fn route_chain(self) -> ChainProcess { ChainProcess::Ok((self, Next::Chain)) } /// Route the output to the Renderer, ending execution - pub fn route_renderer(self) -> ChainProcess { + pub fn route_renderer(self) -> ChainProcess { ChainProcess::Ok((self, Next::Renderer)) } } -impl std::ops::Deref for AnyOutput { +impl std::ops::Deref for AnyOutput +where + G: Display, +{ type Target = dyn std::any::Any + Send + 'static; fn deref(&self) -> &Self::Target { @@ -63,14 +80,20 @@ impl std::ops::Deref for AnyOutput { } } -impl std::ops::DerefMut for AnyOutput { +impl std::ops::DerefMut for AnyOutput +where + G: Display, +{ fn deref_mut(&mut self) -> &mut Self::Target { &mut *self.inner } } -pub enum ChainProcess { - Ok((AnyOutput, Next)), +pub enum ChainProcess +where + G: Display, +{ + Ok((AnyOutput, Next)), Err(ChainProcessError), } @@ -79,7 +102,10 @@ pub enum Next { Renderer, } -impl ChainProcess { +impl ChainProcess +where + G: Display, +{ pub fn is_next(&self) -> bool { matches!(self, Self::Ok(_)) } @@ -102,23 +128,23 @@ impl ChainProcess { } } - pub fn unwrap(self) -> (AnyOutput, Next) { + pub fn unwrap(self) -> (AnyOutput, Next) { match self { Self::Ok(tuple) => tuple, Self::Err(_) => panic!("called `ChainProcess2::unwrap()` on an `Error` value"), } } - pub fn unwrap_or(self, default: (AnyOutput, Next)) -> (AnyOutput, Next) { + pub fn unwrap_or(self, default: (AnyOutput, Next)) -> (AnyOutput, Next) { match self { Self::Ok(tuple) => tuple, Self::Err(_) => default, } } - pub fn unwrap_or_else(self, f: F) -> (AnyOutput, Next) + pub fn unwrap_or_else(self, f: F) -> (AnyOutput, Next) where - F: FnOnce(ChainProcessError) -> (AnyOutput, Next), + F: FnOnce(ChainProcessError) -> (AnyOutput, Next), { match self { Self::Ok(tuple) => tuple, diff --git a/mingling_core/src/any/group.rs b/mingling_core/src/any/group.rs new file mode 100644 index 0000000..29d6a48 --- /dev/null +++ b/mingling_core/src/any/group.rs @@ -0,0 +1,3 @@ +pub trait Groupped { + fn member_id() -> Group; +} diff --git a/mingling_core/src/asset/chain.rs b/mingling_core/src/asset/chain.rs index 1ea1125..9f62228 100644 --- a/mingling_core/src/asset/chain.rs +++ b/mingling_core/src/asset/chain.rs @@ -1,8 +1,13 @@ +use std::fmt::Display; + use crate::ChainProcess; pub mod error; -pub trait Chain { +pub trait Chain +where + G: Display, +{ type Previous; - fn proc(p: Self::Previous) -> impl Future + Send; + fn proc(p: Self::Previous) -> impl Future> + Send; } diff --git a/mingling_core/src/asset/chain/error.rs b/mingling_core/src/asset/chain/error.rs index d4da4ac..cc22bdc 100644 --- a/mingling_core/src/asset/chain/error.rs +++ b/mingling_core/src/asset/chain/error.rs @@ -1,5 +1,3 @@ -use crate::AnyOutput; - #[derive(thiserror::Error, Debug)] pub enum ChainProcessError { #[error("Other error: {0}")] @@ -7,7 +5,4 @@ pub enum ChainProcessError { #[error("IO error: {0}")] IO(#[from] std::io::Error), - - #[error("Broken chain")] - Broken(AnyOutput), } diff --git a/mingling_core/src/asset/dispatcher.rs b/mingling_core/src/asset/dispatcher.rs index 13e35f7..0863f16 100644 --- a/mingling_core/src/asset/dispatcher.rs +++ b/mingling_core/src/asset/dispatcher.rs @@ -1,60 +1,66 @@ +use std::fmt::Display; + use crate::{ChainProcess, Program, asset::node::Node}; -pub trait Dispatcher { +pub trait Dispatcher +where + G: Display, +{ fn node(&self) -> Node; - fn begin(&self, args: Vec) -> ChainProcess; - fn clone_dispatcher(&self) -> Box; + fn begin(&self, args: Vec) -> ChainProcess; + fn clone_dispatcher(&self) -> Box>; } -impl Clone for Box { +impl Clone for Box> +where + G: Display, +{ fn clone(&self) -> Self { self.clone_dispatcher() } } -impl Program { +impl Program { /// Adds a dispatcher to the program. - pub fn with_dispatcher(&mut self, dispatcher: D) + pub fn with_dispatcher(&mut self, dispatcher: Disp) where - D: Into, + Disp: Dispatcher + 'static, { - let dispatchers = dispatcher.into().dispatcher; - self.dispatcher.extend(dispatchers); + self.dispatcher.push(Box::new(dispatcher)); } -} -pub struct Dispatchers { - dispatcher: Vec>, + /// Add some dispatchers to the program. + pub fn with_dispatchers(&mut self, dispatchers: D) + where + D: Into>, + { + let dispatchers = dispatchers.into(); + self.dispatcher.extend(dispatchers.dispatcher); + } } -impl From for Dispatchers -where - D: Dispatcher + 'static, -{ - fn from(dispatcher: D) -> Self { - Self { - dispatcher: vec![Box::new(dispatcher)], - } - } +pub struct Dispatchers { + dispatcher: Vec + 'static>>, } -impl From>> for Dispatchers { - fn from(dispatcher: Vec>) -> Self { +impl From>>> for Dispatchers { + fn from(dispatcher: Vec>>) -> Self { Self { dispatcher } } } -impl From> for Dispatchers { - fn from(dispatcher: Box) -> Self { +impl From>> for Dispatchers { + fn from(dispatcher: Box>) -> Self { Self { dispatcher: vec![dispatcher], } } } -impl From<(D,)> for Dispatchers +impl From<(D,)> for Dispatchers where - D: Dispatcher + 'static, + D: Dispatcher + 'static, + G: Display, { fn from(dispatcher: (D,)) -> Self { Self { @@ -63,10 +69,11 @@ where } } -impl From<(D1, D2)> for Dispatchers +impl From<(D1, D2)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, + D1: Dispatcher + 'static, + D2: Dispatcher + 'static, + G: Display, { fn from(dispatchers: (D1, D2)) -> Self { Self { @@ -75,11 +82,12 @@ where } } -impl From<(D1, D2, D3)> for Dispatchers +impl From<(D1, D2, D3)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, + D1: Dispatcher + 'static, + D2: Dispatcher + 'static, + D3: Dispatcher + 'static, + G: Display, { fn from(dispatchers: (D1, D2, D3)) -> Self { Self { @@ -92,12 +100,13 @@ where } } -impl From<(D1, D2, D3, D4)> for Dispatchers +impl From<(D1, D2, D3, D4)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, + D1: Dispatcher + 'static, + D2: Dispatcher + 'static, + D3: Dispatcher + 'static, + D4: Dispatcher + 'static, + G: Display, { fn from(dispatchers: (D1, D2, D3, D4)) -> Self { Self { @@ -111,13 +120,14 @@ where } } -impl From<(D1, D2, D3, D4, D5)> for Dispatchers +impl From<(D1, D2, D3, D4, D5)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, - D5: Dispatcher + 'static, + D1: Dispatcher + 'static, + D2: Dispatcher + 'static, + D3: Dispatcher + 'static, + D4: Dispatcher + 'static, + D5: Dispatcher + 'static, + G: Display, { fn from(dispatchers: (D1, D2, D3, D4, D5)) -> Self { Self { @@ -132,14 +142,15 @@ where } } -impl From<(D1, D2, D3, D4, D5, D6)> for Dispatchers +impl From<(D1, D2, D3, D4, D5, D6)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, - D5: Dispatcher + 'static, - D6: Dispatcher + 'static, + D1: Dispatcher + 'static, + D2: Dispatcher + 'static, + D3: Dispatcher + 'static, + D4: Dispatcher + 'static, + D5: Dispatcher + 'static, + D6: Dispatcher + 'static, + G: Display, { fn from(dispatchers: (D1, D2, D3, D4, D5, D6)) -> Self { Self { @@ -155,15 +166,16 @@ where } } -impl From<(D1, D2, D3, D4, D5, D6, D7)> for Dispatchers +impl From<(D1, D2, D3, D4, D5, D6, D7)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, - D5: Dispatcher + 'static, - D6: Dispatcher + 'static, - D7: Dispatcher + 'static, + D1: Dispatcher + 'static, + D2: Dispatcher + 'static, + D3: Dispatcher + 'static, + D4: Dispatcher + 'static, + D5: Dispatcher + 'static, + D6: Dispatcher + 'static, + D7: Dispatcher + 'static, + G: Display, { fn from(dispatchers: (D1, D2, D3, D4, D5, D6, D7)) -> Self { Self { @@ -180,16 +192,16 @@ where } } -impl std::ops::Deref for Dispatchers { - type Target = Vec>; +impl std::ops::Deref for Dispatchers { + type Target = Vec + 'static>>; fn deref(&self) -> &Self::Target { &self.dispatcher } } -impl From for Vec> { - fn from(val: Dispatchers) -> Self { +impl From> for Vec + 'static>> { + fn from(val: Dispatchers) -> Self { val.dispatcher } } diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs index 10a1830..3d2be11 100644 --- a/mingling_core/src/lib.rs +++ b/mingling_core/src/lib.rs @@ -1,6 +1,12 @@ mod any; +pub use crate::any::group::*; pub use crate::any::*; +mod markers; +pub mod marker { + pub use crate::markers::group_process::*; +} + pub mod error { pub use crate::asset::chain::error::*; pub use crate::exec::error::*; @@ -11,9 +17,6 @@ pub use crate::program::*; pub mod setup { pub use crate::program::setup::*; } -pub mod hint { - pub use crate::program::hint::*; -} mod renderer; diff --git a/mingling_core/src/markers.rs b/mingling_core/src/markers.rs new file mode 100644 index 0000000..e95fb8a --- /dev/null +++ b/mingling_core/src/markers.rs @@ -0,0 +1 @@ +pub mod group_process; diff --git a/mingling_core/src/markers/group_process.rs b/mingling_core/src/markers/group_process.rs new file mode 100644 index 0000000..c9176f4 --- /dev/null +++ b/mingling_core/src/markers/group_process.rs @@ -0,0 +1,2 @@ +#[allow(dead_code)] +pub struct GroupProcess; diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs index b13a879..1c8c0b4 100644 --- a/mingling_core/src/program.rs +++ b/mingling_core/src/program.rs @@ -2,10 +2,9 @@ use crate::{ AnyOutput, ChainProcess, RenderResult, asset::dispatcher::Dispatcher, error::ProgramExecuteError, }; -use std::{env, pin::Pin}; +use std::{env, fmt::Display, pin::Pin}; pub mod exec; -pub mod hint; pub mod setup; mod config; @@ -16,24 +15,31 @@ pub use flag::*; use tokio::io::AsyncWriteExt; #[derive(Default)] -pub struct Program { +pub struct Program +where + C: ProgramCollect, + G: Display, +{ pub(crate) collect: std::marker::PhantomData, + pub(crate) group: std::marker::PhantomData, pub(crate) args: Vec, - pub(crate) dispatcher: Vec>, + pub(crate) dispatcher: Vec>>, pub stdout_setting: ProgramStdoutSetting, pub user_context: ProgramUserContext, } -impl Program +impl Program where - C: ProgramCollect, + C: ProgramCollect, + G: Display, { /// Creates a new Program instance, initializing args from environment. pub fn new() -> Self { Program { collect: std::marker::PhantomData, + group: std::marker::PhantomData, args: env::args().collect(), dispatcher: Vec::new(), stdout_setting: Default::default(), @@ -57,6 +63,10 @@ where eprintln!("Dispatcher not found"); return; } + ProgramExecuteError::RendererNotFound(renderer_name) => { + eprintln!("Renderer `{}` not found", renderer_name); + return; + } ProgramExecuteError::Other(e) => { eprintln!("{}", e); return; @@ -77,24 +87,27 @@ where } pub trait ProgramCollect { - fn render(any: AnyOutput, r: &mut RenderResult); - fn do_chain(any: AnyOutput) -> Pin + Send>>; - fn has_renderer(any: &AnyOutput) -> bool; - fn has_chain(any: &AnyOutput) -> bool; + type Enum: Display; + fn render(any: AnyOutput, r: &mut RenderResult); + fn do_chain( + any: AnyOutput, + ) -> Pin> + Send>>; + fn has_renderer(any: &AnyOutput) -> bool; + fn has_chain(any: &AnyOutput) -> bool; } #[macro_export] #[doc(hidden)] macro_rules! __dispatch_program_renderers { ( - $( $render_ty:ty => $prev_ty:ty, )* + $( $render_ty:ty => $prev_ty:ident, )* ) => { - fn render(any: mingling::AnyOutput, r: &mut mingling::RenderResult) { - match any.type_id { + fn render(any: mingling::AnyOutput, r: &mut mingling::RenderResult) { + match any.member_id { $( - id if id == std::any::TypeId::of::<$prev_ty>() => { - // SAFETY: The `type_id` check ensures that `any` contains a value of type `$chain_prev`, - // so downcasting to `$chain_prev` is safe. + Self::$prev_ty => { + // SAFETY: The `type_id` check ensures that `any` contains a value of type `$prev_ty`, + // so downcasting to `$prev_ty` is safe. let value = unsafe { any.downcast::<$prev_ty>().unwrap_unchecked() }; <$render_ty as mingling::Renderer>::render(value, r); } @@ -109,18 +122,18 @@ macro_rules! __dispatch_program_renderers { #[doc(hidden)] macro_rules! __dispatch_program_chains { ( - $( $chain_ty:ty => $chain_prev:ty, )* + $( $chain_ty:ty => $chain_prev:ident, )* ) => { fn do_chain( - any: mingling::AnyOutput, - ) -> std::pin::Pin + Send>> { - match any.type_id { + any: mingling::AnyOutput, + ) -> std::pin::Pin> + Send>> { + match any.member_id { $( - id if id == std::any::TypeId::of::<$chain_prev>() => { + Self::$chain_prev => { // SAFETY: The `type_id` check ensures that `any` contains a value of type `$chain_prev`, // so downcasting to `$chain_prev` is safe. let value = unsafe { any.downcast::<$chain_prev>().unwrap_unchecked() }; - let fut = async { <$chain_ty as mingling::Chain>::proc(value).await }; + let fut = async { <$chain_ty as mingling::Chain>::proc(value).await }; Box::pin(fut) } )* 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( - program: Program, -) -> Result { +pub async fn exec(program: Program) -> Result +where + C: ProgramCollect, + G: Display, +{ + let mut current; + // Match user input - let matched: (Box, Vec) = 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::(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 = 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::(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::Renderer)) => return Ok(render::(any)), ChainProcess::Ok((any, Next::Chain)) => any, ChainProcess::Err(e) => return Err(e.into()), } @@ -47,29 +49,28 @@ pub async fn exec( 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 = 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()), - } + 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( - program: &Program, -) -> Result<(&Box, Vec), ProgramInternalExecuteError> { +fn match_user_input( + program: &Program, +) -> Result<(&Box>, Vec), ProgramInternalExecuteError> +where + C: ProgramCollect, + 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)> = nodes + 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))) @@ -102,14 +103,16 @@ fn match_user_input( } #[inline(always)] -fn render(any: AnyOutput) -> RenderResult { +fn render, G: Display>(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)> { +fn get_nodes, G: Display>( + program: &Program, +) -> Vec<(String, &Box>)> { 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 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 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 Program +impl Program where C: ProgramCollect, + G: Display, { /// Registers a global argument (with value) and its handler. pub fn global_argument(&mut self, arguments: A, do_fn: F) where - F: Fn(&mut Program, String), + F: Fn(&mut Program, String), A: Into, { let flag = arguments.into(); @@ -111,7 +114,7 @@ where /// Registers a global flag (boolean) and its handler. pub fn global_flag(&mut self, flag: A, do_fn: F) where - F: Fn(&mut Program), + F: Fn(&mut Program), A: Into, { 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, -} - -#[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) -> ChainProcess { - AnyOutput::new(NoDispatcherFound { args }).route_renderer() - } - - fn clone_dispatcher(&self) -> Box { - 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) -> ChainProcess { - AnyOutput::new(NoRendererFound { - type_to_render: args.first().unwrap().clone(), - }) - .route_renderer() - } - - fn clone_dispatcher(&self) -> Box { - 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 { - fn setup(&mut self, program: &mut Program); +pub trait ProgramSetup +where + C: ProgramCollect, + G: Display, +{ + fn setup(&mut self, program: &mut Program); } -impl Program +impl Program where C: ProgramCollect, + G: Display, { /// Load and execute init logic - pub fn with_setup + 'static>(&mut self, mut setup: S) -> S { + pub fn with_setup + '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 ProgramSetup for BasicProgramSetup +impl ProgramSetup for BasicProgramSetup where C: ProgramCollect, + G: Display, { - fn setup(&mut self, program: &mut Program) { + fn setup(&mut self, program: &mut Program) { program.global_flag(["--quiet", "-q"], |p| { p.stdout_setting.render_output = false; p.stdout_setting.error_output = false; -- cgit