diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-04-01 15:48:41 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-04-01 15:48:41 +0800 |
| commit | 3de10ca22cca06c4d9069984d0e66e370a331dde (patch) | |
| tree | 7e8a9b035c360c016cde848b3442d3e1d5dcac5e /mingling_core/src | |
| parent | f3d6f76dfd07c35dabc11aa86d86c3671cd283c5 (diff) | |
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
Diffstat (limited to 'mingling_core/src')
| -rw-r--r-- | mingling_core/src/any.rs | 56 | ||||
| -rw-r--r-- | mingling_core/src/any/group.rs | 3 | ||||
| -rw-r--r-- | mingling_core/src/asset/chain.rs | 9 | ||||
| -rw-r--r-- | mingling_core/src/asset/chain/error.rs | 5 | ||||
| -rw-r--r-- | mingling_core/src/asset/dispatcher.rs | 140 | ||||
| -rw-r--r-- | mingling_core/src/lib.rs | 9 | ||||
| -rw-r--r-- | mingling_core/src/markers.rs | 1 | ||||
| -rw-r--r-- | mingling_core/src/markers/group_process.rs | 2 | ||||
| -rw-r--r-- | mingling_core/src/program.rs | 57 | ||||
| -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 |
15 files changed, 238 insertions, 218 deletions
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<G> +where + G: Display, +{ inner: Box<dyn std::any::Any + Send + 'static>, pub type_id: std::any::TypeId, + pub member_id: G, } -impl AnyOutput { +impl<G> AnyOutput<G> +where + G: Display, +{ #[cfg(feature = "general_renderer")] pub fn new<T>(value: T) -> Self where - T: Send + Serialize + 'static, + T: Send + Groupped<G> + Serialize + 'static, { Self { inner: Box::new(value), type_id: std::any::TypeId::of::<T>(), + member_id: T::member_id(), } } #[cfg(not(feature = "general_renderer"))] pub fn new<T>(value: T) -> Self where - T: Send + 'static, + T: Send + Groupped<G> + 'static, { Self { inner: Box::new(value), type_id: std::any::TypeId::of::<T>(), + 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<G> { 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<G> { ChainProcess::Ok((self, Next::Renderer)) } } -impl std::ops::Deref for AnyOutput { +impl<G> std::ops::Deref for AnyOutput<G> +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<G> std::ops::DerefMut for AnyOutput<G> +where + G: Display, +{ fn deref_mut(&mut self) -> &mut Self::Target { &mut *self.inner } } -pub enum ChainProcess { - Ok((AnyOutput, Next)), +pub enum ChainProcess<G> +where + G: Display, +{ + Ok((AnyOutput<G>, Next)), Err(ChainProcessError), } @@ -79,7 +102,10 @@ pub enum Next { Renderer, } -impl ChainProcess { +impl<G> ChainProcess<G> +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<G>, 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<G>, Next)) -> (AnyOutput<G>, Next) { match self { Self::Ok(tuple) => tuple, Self::Err(_) => default, } } - pub fn unwrap_or_else<F>(self, f: F) -> (AnyOutput, Next) + pub fn unwrap_or_else<F>(self, f: F) -> (AnyOutput<G>, Next) where - F: FnOnce(ChainProcessError) -> (AnyOutput, Next), + F: FnOnce(ChainProcessError) -> (AnyOutput<G>, 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<Group> { + 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<G> +where + G: Display, +{ type Previous; - fn proc(p: Self::Previous) -> impl Future<Output = ChainProcess> + Send; + fn proc(p: Self::Previous) -> impl Future<Output = ChainProcess<G>> + 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<G> +where + G: Display, +{ fn node(&self) -> Node; - fn begin(&self, args: Vec<String>) -> ChainProcess; - fn clone_dispatcher(&self) -> Box<dyn Dispatcher>; + fn begin(&self, args: Vec<String>) -> ChainProcess<G>; + fn clone_dispatcher(&self) -> Box<dyn Dispatcher<G>>; } -impl Clone for Box<dyn Dispatcher> { +impl<G> Clone for Box<dyn Dispatcher<G>> +where + G: Display, +{ fn clone(&self) -> Self { self.clone_dispatcher() } } -impl<C: crate::program::ProgramCollect> Program<C> { +impl<C: crate::program::ProgramCollect, G: Display> Program<C, G> { /// Adds a dispatcher to the program. - pub fn with_dispatcher<D>(&mut self, dispatcher: D) + pub fn with_dispatcher<Disp>(&mut self, dispatcher: Disp) where - D: Into<Dispatchers>, + Disp: Dispatcher<G> + 'static, { - let dispatchers = dispatcher.into().dispatcher; - self.dispatcher.extend(dispatchers); + self.dispatcher.push(Box::new(dispatcher)); } -} -pub struct Dispatchers { - dispatcher: Vec<Box<dyn Dispatcher + 'static>>, + /// Add some dispatchers to the program. + pub fn with_dispatchers<D>(&mut self, dispatchers: D) + where + D: Into<Dispatchers<G>>, + { + let dispatchers = dispatchers.into(); + self.dispatcher.extend(dispatchers.dispatcher); + } } -impl<D> From<D> for Dispatchers -where - D: Dispatcher + 'static, -{ - fn from(dispatcher: D) -> Self { - Self { - dispatcher: vec![Box::new(dispatcher)], - } - } +pub struct Dispatchers<G> { + dispatcher: Vec<Box<dyn Dispatcher<G> + 'static>>, } -impl From<Vec<Box<dyn Dispatcher>>> for Dispatchers { - fn from(dispatcher: Vec<Box<dyn Dispatcher>>) -> Self { +impl<G> From<Vec<Box<dyn Dispatcher<G>>>> for Dispatchers<G> { + fn from(dispatcher: Vec<Box<dyn Dispatcher<G>>>) -> Self { Self { dispatcher } } } -impl From<Box<dyn Dispatcher>> for Dispatchers { - fn from(dispatcher: Box<dyn Dispatcher>) -> Self { +impl<G> From<Box<dyn Dispatcher<G>>> for Dispatchers<G> { + fn from(dispatcher: Box<dyn Dispatcher<G>>) -> Self { Self { dispatcher: vec![dispatcher], } } } -impl<D> From<(D,)> for Dispatchers +impl<D, G> From<(D,)> for Dispatchers<G> where - D: Dispatcher + 'static, + D: Dispatcher<G> + 'static, + G: Display, { fn from(dispatcher: (D,)) -> Self { Self { @@ -63,10 +69,11 @@ where } } -impl<D1, D2> From<(D1, D2)> for Dispatchers +impl<D1, D2, G> From<(D1, D2)> for Dispatchers<G> where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, + D1: Dispatcher<G> + 'static, + D2: Dispatcher<G> + 'static, + G: Display, { fn from(dispatchers: (D1, D2)) -> Self { Self { @@ -75,11 +82,12 @@ where } } -impl<D1, D2, D3> From<(D1, D2, D3)> for Dispatchers +impl<D1, D2, D3, G> From<(D1, D2, D3)> for Dispatchers<G> where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, + D1: Dispatcher<G> + 'static, + D2: Dispatcher<G> + 'static, + D3: Dispatcher<G> + 'static, + G: Display, { fn from(dispatchers: (D1, D2, D3)) -> Self { Self { @@ -92,12 +100,13 @@ where } } -impl<D1, D2, D3, D4> From<(D1, D2, D3, D4)> for Dispatchers +impl<D1, D2, D3, D4, G> From<(D1, D2, D3, D4)> for Dispatchers<G> where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, + D1: Dispatcher<G> + 'static, + D2: Dispatcher<G> + 'static, + D3: Dispatcher<G> + 'static, + D4: Dispatcher<G> + 'static, + G: Display, { fn from(dispatchers: (D1, D2, D3, D4)) -> Self { Self { @@ -111,13 +120,14 @@ where } } -impl<D1, D2, D3, D4, D5> From<(D1, D2, D3, D4, D5)> for Dispatchers +impl<D1, D2, D3, D4, D5, G> From<(D1, D2, D3, D4, D5)> for Dispatchers<G> where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, - D5: Dispatcher + 'static, + D1: Dispatcher<G> + 'static, + D2: Dispatcher<G> + 'static, + D3: Dispatcher<G> + 'static, + D4: Dispatcher<G> + 'static, + D5: Dispatcher<G> + 'static, + G: Display, { fn from(dispatchers: (D1, D2, D3, D4, D5)) -> Self { Self { @@ -132,14 +142,15 @@ where } } -impl<D1, D2, D3, D4, D5, D6> From<(D1, D2, D3, D4, D5, D6)> for Dispatchers +impl<D1, D2, D3, D4, D5, D6, G> From<(D1, D2, D3, D4, D5, D6)> for Dispatchers<G> where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, - D5: Dispatcher + 'static, - D6: Dispatcher + 'static, + D1: Dispatcher<G> + 'static, + D2: Dispatcher<G> + 'static, + D3: Dispatcher<G> + 'static, + D4: Dispatcher<G> + 'static, + D5: Dispatcher<G> + 'static, + D6: Dispatcher<G> + 'static, + G: Display, { fn from(dispatchers: (D1, D2, D3, D4, D5, D6)) -> Self { Self { @@ -155,15 +166,16 @@ where } } -impl<D1, D2, D3, D4, D5, D6, D7> From<(D1, D2, D3, D4, D5, D6, D7)> for Dispatchers +impl<D1, D2, D3, D4, D5, D6, D7, G> From<(D1, D2, D3, D4, D5, D6, D7)> for Dispatchers<G> where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, - D5: Dispatcher + 'static, - D6: Dispatcher + 'static, - D7: Dispatcher + 'static, + D1: Dispatcher<G> + 'static, + D2: Dispatcher<G> + 'static, + D3: Dispatcher<G> + 'static, + D4: Dispatcher<G> + 'static, + D5: Dispatcher<G> + 'static, + D6: Dispatcher<G> + 'static, + D7: Dispatcher<G> + '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<Box<dyn Dispatcher + 'static>>; +impl<G> std::ops::Deref for Dispatchers<G> { + type Target = Vec<Box<dyn Dispatcher<G> + 'static>>; fn deref(&self) -> &Self::Target { &self.dispatcher } } -impl From<Dispatchers> for Vec<Box<dyn Dispatcher + 'static>> { - fn from(val: Dispatchers) -> Self { +impl<G> From<Dispatchers<G>> for Vec<Box<dyn Dispatcher<G> + 'static>> { + fn from(val: Dispatchers<G>) -> 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<C: ProgramCollect> { +pub struct Program<C, G> +where + C: ProgramCollect, + G: Display, +{ pub(crate) collect: std::marker::PhantomData<C>, + pub(crate) group: std::marker::PhantomData<G>, pub(crate) args: Vec<String>, - pub(crate) dispatcher: Vec<Box<dyn Dispatcher>>, + pub(crate) dispatcher: Vec<Box<dyn Dispatcher<G>>>, pub stdout_setting: ProgramStdoutSetting, pub user_context: ProgramUserContext, } -impl<C> Program<C> +impl<C, G> Program<C, G> where - C: ProgramCollect, + C: ProgramCollect<Enum = G>, + 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<Box<dyn Future<Output = ChainProcess> + Send>>; - fn has_renderer(any: &AnyOutput) -> bool; - fn has_chain(any: &AnyOutput) -> bool; + type Enum: Display; + fn render(any: AnyOutput<Self::Enum>, r: &mut RenderResult); + fn do_chain( + any: AnyOutput<Self::Enum>, + ) -> Pin<Box<dyn Future<Output = ChainProcess<Self::Enum>> + Send>>; + fn has_renderer(any: &AnyOutput<Self::Enum>) -> bool; + fn has_chain(any: &AnyOutput<Self::Enum>) -> 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<Self::Enum>, 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<Box<dyn Future<Output = mingling::ChainProcess> + Send>> { - match any.type_id { + any: mingling::AnyOutput<Self::Enum>, + ) -> std::pin::Pin<Box<dyn Future<Output = mingling::ChainProcess<Self::Enum>> + 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<Self::Enum>>::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<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; |
