summaryrefslogtreecommitdiff
path: root/mingling/src/program.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-03-29 00:52:16 +0800
committer魏曹先生 <1992414357@qq.com>2026-03-29 00:52:28 +0800
commitdb9afa0b06355028eafe3bc29fe0b2429ba8fd0a (patch)
tree60bf74d0853fcc0c1e9363813c26109a6ca38a4f /mingling/src/program.rs
parent7ce68cd11516bd7cf037ecea99a92aee7c31b2c3 (diff)
Completed the first preliminary usable version of the Mingling
framework.
Diffstat (limited to 'mingling/src/program.rs')
-rw-r--r--mingling/src/program.rs107
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()
+ }),
+ }
+ }
+ };
+}