diff options
Diffstat (limited to 'mingling/src')
| -rw-r--r-- | mingling/src/any.rs | 128 | ||||
| -rw-r--r-- | mingling/src/asset.rs | 4 | ||||
| -rw-r--r-- | mingling/src/asset/chain.rs | 8 | ||||
| -rw-r--r-- | mingling/src/asset/chain/error.rs | 13 | ||||
| -rw-r--r-- | mingling/src/asset/dispatcher.rs | 195 | ||||
| -rw-r--r-- | mingling/src/asset/node.rs | 54 | ||||
| -rw-r--r-- | mingling/src/asset/renderer.rs | 6 | ||||
| -rw-r--r-- | mingling/src/lib.rs | 39 | ||||
| -rw-r--r-- | mingling/src/program.rs | 132 | ||||
| -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 | ||||
| -rw-r--r-- | mingling/src/renderer.rs | 1 | ||||
| -rw-r--r-- | mingling/src/renderer/render_result.rs | 38 |
18 files changed, 0 insertions, 1076 deletions
diff --git a/mingling/src/any.rs b/mingling/src/any.rs deleted file mode 100644 index 1bce96a..0000000 --- a/mingling/src/any.rs +++ /dev/null @@ -1,128 +0,0 @@ -#[cfg(feature = "general_renderer")] -use serde::Serialize; - -use crate::error::ChainProcessError; - -#[derive(Debug)] -pub struct AnyOutput { - inner: Box<dyn std::any::Any + Send + 'static>, - pub type_id: std::any::TypeId, -} - -impl AnyOutput { - #[cfg(feature = "general_renderer")] - pub fn new<T>(value: T) -> Self - where - T: Send + Serialize + 'static, - { - Self { - inner: Box::new(value), - type_id: std::any::TypeId::of::<T>(), - } - } - - #[cfg(not(feature = "general_renderer"))] - pub fn new<T>(value: T) -> Self - where - T: Send + 'static, - { - Self { - inner: Box::new(value), - type_id: std::any::TypeId::of::<T>(), - } - } - - pub fn downcast<T: 'static>(self) -> Result<T, Self> { - if self.type_id == std::any::TypeId::of::<T>() { - Ok(*self.inner.downcast::<T>().unwrap()) - } else { - Err(self) - } - } - - pub fn is<T: 'static>(&self) -> bool { - self.type_id == std::any::TypeId::of::<T>() - } - - /// Route the output to the next Chain - 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 { - ChainProcess::Ok((self, Next::Renderer)) - } -} - -impl std::ops::Deref for AnyOutput { - type Target = dyn std::any::Any + Send + 'static; - - fn deref(&self) -> &Self::Target { - &*self.inner - } -} - -impl std::ops::DerefMut for AnyOutput { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut *self.inner - } -} - -pub enum ChainProcess { - Ok((AnyOutput, Next)), - Err(ChainProcessError), -} - -pub enum Next { - Chain, - Renderer, -} - -impl ChainProcess { - pub fn is_next(&self) -> bool { - matches!(self, Self::Ok(_)) - } - - pub fn is_err(&self) -> bool { - matches!(self, Self::Err(_)) - } - - pub fn next(&self) -> Option<&Next> { - match self { - Self::Ok((_, next)) => Some(next), - Self::Err(_) => None, - } - } - - pub fn err(&self) -> Option<&ChainProcessError> { - match self { - Self::Ok(_) => None, - Self::Err(err) => Some(err), - } - } - - 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) { - match self { - Self::Ok(tuple) => tuple, - Self::Err(_) => default, - } - } - - pub fn unwrap_or_else<F>(self, f: F) -> (AnyOutput, Next) - where - F: FnOnce(ChainProcessError) -> (AnyOutput, Next), - { - match self { - Self::Ok(tuple) => tuple, - Self::Err(err) => f(err), - } - } -} diff --git a/mingling/src/asset.rs b/mingling/src/asset.rs deleted file mode 100644 index c2adf4e..0000000 --- a/mingling/src/asset.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod chain; -pub mod dispatcher; -pub mod node; -pub mod renderer; diff --git a/mingling/src/asset/chain.rs b/mingling/src/asset/chain.rs deleted file mode 100644 index 1ea1125..0000000 --- a/mingling/src/asset/chain.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::ChainProcess; - -pub mod error; - -pub trait Chain { - type Previous; - fn proc(p: Self::Previous) -> impl Future<Output = ChainProcess> + Send; -} diff --git a/mingling/src/asset/chain/error.rs b/mingling/src/asset/chain/error.rs deleted file mode 100644 index d4da4ac..0000000 --- a/mingling/src/asset/chain/error.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::AnyOutput; - -#[derive(thiserror::Error, Debug)] -pub enum ChainProcessError { - #[error("Other error: {0}")] - Other(String), - - #[error("IO error: {0}")] - IO(#[from] std::io::Error), - - #[error("Broken chain")] - Broken(AnyOutput), -} diff --git a/mingling/src/asset/dispatcher.rs b/mingling/src/asset/dispatcher.rs deleted file mode 100644 index 13e35f7..0000000 --- a/mingling/src/asset/dispatcher.rs +++ /dev/null @@ -1,195 +0,0 @@ -use crate::{ChainProcess, Program, asset::node::Node}; - -pub trait Dispatcher { - fn node(&self) -> Node; - fn begin(&self, args: Vec<String>) -> ChainProcess; - fn clone_dispatcher(&self) -> Box<dyn Dispatcher>; -} - -impl Clone for Box<dyn Dispatcher> { - fn clone(&self) -> Self { - self.clone_dispatcher() - } -} - -impl<C: crate::program::ProgramCollect> Program<C> { - /// Adds a dispatcher to the program. - pub fn with_dispatcher<D>(&mut self, dispatcher: D) - where - D: Into<Dispatchers>, - { - let dispatchers = dispatcher.into().dispatcher; - self.dispatcher.extend(dispatchers); - } -} - -pub struct Dispatchers { - dispatcher: Vec<Box<dyn Dispatcher + 'static>>, -} - -impl<D> From<D> for Dispatchers -where - D: Dispatcher + 'static, -{ - fn from(dispatcher: D) -> Self { - Self { - dispatcher: vec![Box::new(dispatcher)], - } - } -} - -impl From<Vec<Box<dyn Dispatcher>>> for Dispatchers { - fn from(dispatcher: Vec<Box<dyn Dispatcher>>) -> Self { - Self { dispatcher } - } -} - -impl From<Box<dyn Dispatcher>> for Dispatchers { - fn from(dispatcher: Box<dyn Dispatcher>) -> Self { - Self { - dispatcher: vec![dispatcher], - } - } -} - -impl<D> From<(D,)> for Dispatchers -where - D: Dispatcher + 'static, -{ - fn from(dispatcher: (D,)) -> Self { - Self { - dispatcher: vec![Box::new(dispatcher.0)], - } - } -} - -impl<D1, D2> From<(D1, D2)> for Dispatchers -where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, -{ - fn from(dispatchers: (D1, D2)) -> Self { - Self { - dispatcher: vec![Box::new(dispatchers.0), Box::new(dispatchers.1)], - } - } -} - -impl<D1, D2, D3> From<(D1, D2, D3)> for Dispatchers -where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, -{ - fn from(dispatchers: (D1, D2, D3)) -> Self { - Self { - dispatcher: vec![ - Box::new(dispatchers.0), - Box::new(dispatchers.1), - Box::new(dispatchers.2), - ], - } - } -} - -impl<D1, D2, D3, D4> From<(D1, D2, D3, D4)> for Dispatchers -where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, -{ - fn from(dispatchers: (D1, D2, D3, D4)) -> Self { - Self { - dispatcher: vec![ - Box::new(dispatchers.0), - Box::new(dispatchers.1), - Box::new(dispatchers.2), - Box::new(dispatchers.3), - ], - } - } -} - -impl<D1, D2, D3, D4, D5> From<(D1, D2, D3, D4, D5)> for Dispatchers -where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, - D5: Dispatcher + 'static, -{ - fn from(dispatchers: (D1, D2, D3, D4, D5)) -> Self { - Self { - dispatcher: vec![ - Box::new(dispatchers.0), - Box::new(dispatchers.1), - Box::new(dispatchers.2), - Box::new(dispatchers.3), - Box::new(dispatchers.4), - ], - } - } -} - -impl<D1, D2, D3, D4, D5, D6> 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, -{ - fn from(dispatchers: (D1, D2, D3, D4, D5, D6)) -> Self { - Self { - dispatcher: vec![ - Box::new(dispatchers.0), - Box::new(dispatchers.1), - Box::new(dispatchers.2), - Box::new(dispatchers.3), - Box::new(dispatchers.4), - Box::new(dispatchers.5), - ], - } - } -} - -impl<D1, D2, D3, D4, D5, D6, D7> 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, -{ - fn from(dispatchers: (D1, D2, D3, D4, D5, D6, D7)) -> Self { - Self { - dispatcher: vec![ - Box::new(dispatchers.0), - Box::new(dispatchers.1), - Box::new(dispatchers.2), - Box::new(dispatchers.3), - Box::new(dispatchers.4), - Box::new(dispatchers.5), - Box::new(dispatchers.6), - ], - } - } -} - -impl std::ops::Deref for Dispatchers { - type Target = Vec<Box<dyn Dispatcher + 'static>>; - - fn deref(&self) -> &Self::Target { - &self.dispatcher - } -} - -impl From<Dispatchers> for Vec<Box<dyn Dispatcher + 'static>> { - fn from(val: Dispatchers) -> Self { - val.dispatcher - } -} diff --git a/mingling/src/asset/node.rs b/mingling/src/asset/node.rs deleted file mode 100644 index c8b7600..0000000 --- a/mingling/src/asset/node.rs +++ /dev/null @@ -1,54 +0,0 @@ -use just_fmt::kebab_case; - -#[derive(Debug, Default)] -pub struct Node { - node: Vec<String>, -} - -impl Node { - pub fn join(self, node: impl Into<String>) -> Node { - let mut new_node = self.node; - new_node.push(node.into()); - Node { node: new_node } - } -} - -impl From<&str> for Node { - fn from(s: &str) -> Self { - let node = s.split('.').map(|part| kebab_case!(part)).collect(); - Node { node } - } -} - -impl From<String> for Node { - fn from(s: String) -> Self { - let node = s.split('.').map(|part| kebab_case!(part)).collect(); - Node { node } - } -} - -impl PartialEq for Node { - fn eq(&self, other: &Self) -> bool { - self.node == other.node - } -} - -impl Eq for Node {} - -impl PartialOrd for Node { - fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for Node { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.node.cmp(&other.node) - } -} - -impl std::fmt::Display for Node { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.node.join(".")) - } -} diff --git a/mingling/src/asset/renderer.rs b/mingling/src/asset/renderer.rs deleted file mode 100644 index 3852b55..0000000 --- a/mingling/src/asset/renderer.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::RenderResult; - -pub trait Renderer { - type Previous; - fn render(p: Self::Previous, r: &mut RenderResult); -} diff --git a/mingling/src/lib.rs b/mingling/src/lib.rs deleted file mode 100644 index 4d9bcc5..0000000 --- a/mingling/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -mod any; -pub use crate::any::*; - -pub mod error { - pub use crate::asset::chain::error::*; - pub use crate::exec::error::*; -} - -mod program; -pub use crate::program::*; -pub mod setup { - pub use crate::program::setup::*; -} -pub mod hint { - pub use crate::program::hint::*; -} - -#[cfg(feature = "macros")] -#[allow(unused_imports)] -pub mod macros { - pub use mingling_macros::chain; - pub use mingling_macros::chain_struct; - pub use mingling_macros::dispatcher; - pub use mingling_macros::dispatcher_render; - pub use mingling_macros::node; - pub use mingling_macros::program; - pub use mingling_macros::r_print; - pub use mingling_macros::r_println; - pub use mingling_macros::renderer; -} - -mod renderer; - -mod asset; -pub use crate::asset::chain::*; -pub use crate::asset::dispatcher::*; -pub use crate::asset::node::*; -pub use crate::asset::renderer::*; -pub use crate::renderer::render_result::*; diff --git a/mingling/src/program.rs b/mingling/src/program.rs deleted file mode 100644 index 3d8bc14..0000000 --- a/mingling/src/program.rs +++ /dev/null @@ -1,132 +0,0 @@ -use crate::{ - AnyOutput, ChainProcess, RenderResult, asset::dispatcher::Dispatcher, - error::ProgramExecuteError, -}; -use std::{env, pin::Pin}; - -pub mod exec; -pub mod hint; -pub mod setup; - -mod config; -pub use config::*; - -mod flag; -pub use flag::*; -use tokio::io::AsyncWriteExt; - -#[derive(Default)] -pub struct Program<C: ProgramCollect> { - pub(crate) collect: std::marker::PhantomData<C>, - - pub(crate) args: Vec<String>, - pub(crate) dispatcher: Vec<Box<dyn Dispatcher>>, - - pub stdout_setting: ProgramStdoutSetting, - pub user_context: ProgramUserContext, -} - -impl<C> Program<C> -where - C: ProgramCollect, -{ - /// Creates a new Program instance, initializing args from environment. - pub fn new() -> Self { - Program { - collect: std::marker::PhantomData, - args: env::args().collect(), - dispatcher: Vec::new(), - stdout_setting: Default::default(), - user_context: Default::default(), - } - } - - /// Run the command line program - pub async fn exec_without_render(mut self) -> Result<RenderResult, ProgramExecuteError> { - self.args = self.args.iter().skip(1).cloned().collect(); - crate::exec::exec(self).await.map_err(|e| e.into()) - } - - /// Run the command line program - pub async fn exec(self) { - let stdout_setting = self.stdout_setting.clone(); - let result = match self.exec_without_render().await { - Ok(r) => r, - Err(e) => match e { - ProgramExecuteError::DispatcherNotFound => { - eprintln!("Dispatcher not found"); - return; - } - ProgramExecuteError::Other(e) => { - eprintln!("{}", e); - return; - } - }, - }; - - // Render result - if stdout_setting.render_output && !result.is_empty() { - print!("{}", result); - if let Err(e) = tokio::io::stdout().flush().await - && stdout_setting.error_output - { - eprintln!("{}", e); - } - } - } -} - -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; -} - -#[macro_export] -#[doc(hidden)] -macro_rules! __dispatch_program_renderers { - ( - $( $render_ty:ty => $prev_ty:ty, )* - ) => { - fn render(any: mingling::AnyOutput, r: &mut mingling::RenderResult) { - match any.type_id { - $( - id if id == std::any::TypeId::of::<$prev_ty>() => { - let value = any.downcast::<$prev_ty>().unwrap(); - <$render_ty as mingling::Renderer>::render(value, r); - } - )* - _ => (), - } - } - }; -} - -#[macro_export] -#[doc(hidden)] -macro_rules! __dispatch_program_chains { - ( - $( $chain_ty:ty => $chain_prev:ty, )* - ) => { - fn do_chain( - any: mingling::AnyOutput, - ) -> std::pin::Pin<Box<dyn Future<Output = mingling::ChainProcess> + Send>> { - match any.type_id { - $( - id if id == std::any::TypeId::of::<$chain_prev>() => { - let value = any.downcast::<$chain_prev>().unwrap(); - let fut = async { <$chain_ty as mingling::Chain>::proc(value).await }; - Box::pin(fut) - } - )* - _ => Box::pin(async move { - mingling::AnyOutput::new(mingling::hint::NoChainFound { - name: format!("{:?}", any.type_id).to_string(), - }) - .route_chain() - }), - } - } - }; -} 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; - }); - } -} diff --git a/mingling/src/renderer.rs b/mingling/src/renderer.rs deleted file mode 100644 index 631092b..0000000 --- a/mingling/src/renderer.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod render_result; diff --git a/mingling/src/renderer/render_result.rs b/mingling/src/renderer/render_result.rs deleted file mode 100644 index 73c38e7..0000000 --- a/mingling/src/renderer/render_result.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::{ - fmt::{Display, Formatter}, - ops::Deref, -}; - -#[derive(Default, Debug, PartialEq)] -pub struct RenderResult { - render_text: String, -} - -impl Display for RenderResult { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - writeln!(f, "{}", self.render_text.trim()) - } -} - -impl Deref for RenderResult { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.render_text - } -} - -impl RenderResult { - pub fn print(&mut self, text: &str) { - self.render_text.push_str(text); - } - - pub fn println(&mut self, text: &str) { - self.render_text.push_str(text); - self.render_text.push('\n'); - } - - pub fn clear(&mut self) { - self.render_text.clear(); - } -} |
