summaryrefslogtreecommitdiff
path: root/mingling/src/program
diff options
context:
space:
mode:
Diffstat (limited to 'mingling/src/program')
-rw-r--r--mingling/src/program/config.rs26
-rw-r--r--mingling/src/program/exec.rs126
-rw-r--r--mingling/src/program/exec/error.rs46
-rw-r--r--mingling/src/program/flag.rs148
-rw-r--r--mingling/src/program/hint.rs62
-rw-r--r--mingling/src/program/setup.rs19
-rw-r--r--mingling/src/program/setup/basic.rs31
7 files changed, 0 insertions, 458 deletions
diff --git a/mingling/src/program/config.rs b/mingling/src/program/config.rs
deleted file mode 100644
index 386b112..0000000
--- a/mingling/src/program/config.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-#[derive(Debug, Clone)]
-pub struct ProgramStdoutSetting {
- /// Output error messages
- pub error_output: bool,
-
- /// Render results and output
- pub render_output: bool,
-}
-
-impl Default for ProgramStdoutSetting {
- fn default() -> Self {
- ProgramStdoutSetting {
- error_output: true,
- render_output: true,
- }
- }
-}
-
-#[derive(Debug, Clone, Default)]
-pub struct ProgramUserContext {
- /// View help information instead of running the command
- pub help: bool,
-
- /// Skip user confirmation step
- pub confirm: bool,
-}
diff --git a/mingling/src/program/exec.rs b/mingling/src/program/exec.rs
deleted file mode 100644
index 853bff1..0000000
--- a/mingling/src/program/exec.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-#![allow(clippy::borrowed_box)]
-
-use crate::{
- AnyOutput, ChainProcess, Dispatcher, Next, Program, ProgramCollect, RenderResult,
- error::ProgramInternalExecuteError,
- hint::{DispatcherNotFound, RendererNotFound},
-};
-
-pub mod error;
-
-pub async fn exec<C: ProgramCollect>(
- program: Program<C>,
-) -> Result<RenderResult, ProgramInternalExecuteError> {
- // Match user input
- let matched: (Box<dyn Dispatcher>, Vec<String>) = match match_user_input(&program) {
- Ok(r) => (r.0.clone(), r.1),
- Err(ProgramInternalExecuteError::DispatcherNotFound) => {
- // If no Dispatcher is found, dispatch to the DispatcherNotFound Dispatcher
- // to route it to the NoDispatcherFound struct
- let disp: Box<dyn Dispatcher> = Box::new(DispatcherNotFound);
- (disp, program.args)
- }
- Err(e) => return Err(e),
- };
-
- // Entry point
- let (dispatcher, args) = matched;
- let mut current = match dispatcher.begin(args) {
- ChainProcess::Ok((any, Next::Renderer)) => return Ok(render::<C>(any)),
- ChainProcess::Ok((any, Next::Chain)) => any,
- ChainProcess::Err(e) => return Err(e.into()),
- };
-
- loop {
- current = {
- // If a chain exists, execute as a chain
- if C::has_chain(&current) {
- 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(&current) {
- 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;
- });
- }
-}