diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-03-29 21:48:23 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-03-29 21:48:23 +0800 |
| commit | 596e5e2440df2d32f1cf3e052dc633e774edf6ee (patch) | |
| tree | dc98eb6a1789847b899207d0b99337bb3ccd92a5 /mingling_core/src/program.rs | |
| parent | 25a164f74c011e6e78846f226cbd7a8bd87db92f (diff) | |
Rename mingling to mingling_core and update dependencies
Diffstat (limited to 'mingling_core/src/program.rs')
| -rw-r--r-- | mingling_core/src/program.rs | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs new file mode 100644 index 0000000..3d8bc14 --- /dev/null +++ b/mingling_core/src/program.rs @@ -0,0 +1,132 @@ +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() + }), + } + } + }; +} |
