diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-03-29 00:52:16 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-03-29 00:52:28 +0800 |
| commit | db9afa0b06355028eafe3bc29fe0b2429ba8fd0a (patch) | |
| tree | 60bf74d0853fcc0c1e9363813c26109a6ca38a4f /mingling/src/program.rs | |
| parent | 7ce68cd11516bd7cf037ecea99a92aee7c31b2c3 (diff) | |
Completed the first preliminary usable version of the Mingling
framework.
Diffstat (limited to 'mingling/src/program.rs')
| -rw-r--r-- | mingling/src/program.rs | 107 |
1 files changed, 101 insertions, 6 deletions
diff --git a/mingling/src/program.rs b/mingling/src/program.rs index e4bc3d0..5e9d1f2 100644 --- a/mingling/src/program.rs +++ b/mingling/src/program.rs @@ -1,6 +1,11 @@ -use crate::asset::dispatcher::Dispatcher; -use std::env; +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; @@ -8,9 +13,12 @@ pub use config::*; mod flag; pub use flag::*; +use tokio::io::AsyncWriteExt; #[derive(Default)] -pub struct Program { +pub struct Program<C: ProgramCollect> { + pub(crate) collect: std::marker::PhantomData<C>, + pub(crate) args: Vec<String>, pub(crate) dispatcher: Vec<Box<dyn Dispatcher>>, @@ -18,18 +26,105 @@ pub struct Program { pub user_context: ProgramUserContext, } -impl Program { +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(), - ..Default::default() + 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) { - todo!() + 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 { + if !result.is_empty() { + print!("{}", result); + if let Err(e) = tokio::io::stdout().flush().await + && stdout_setting.error_output + { + eprintln!("{}", e.to_string()); + } + } + } } } + +pub trait ProgramCollect { + fn render(any: AnyOutput, r: &mut RenderResult); + fn do_chain(any: AnyOutput) -> Pin<Box<dyn Future<Output = ChainProcess> + Send>>; +} + +#[macro_export] +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] +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() + }), + } + } + }; +} |
