diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-04-19 00:31:05 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-04-19 00:31:05 +0800 |
| commit | 532f4ceba2bddb1c84d2e0bdd69808a3ebd5ca4a (patch) | |
| tree | 043514a2aca670d8b2398726b17aab1066938ba1 /mingling_core/src/program.rs | |
| parent | ecc1329bbd31cd98fa9b4c2f25a3114f133987ae (diff) | |
Make async an optional feature
Diffstat (limited to 'mingling_core/src/program.rs')
| -rw-r--r-- | mingling_core/src/program.rs | 127 |
1 files changed, 120 insertions, 7 deletions
diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs index 7ea3a38..ce4a5fa 100644 --- a/mingling_core/src/program.rs +++ b/mingling_core/src/program.rs @@ -8,7 +8,10 @@ use crate::{ AnyOutput, ChainProcess, RenderResult, asset::dispatcher::Dispatcher, error::ProgramExecuteError, }; -use std::{fmt::Display, pin::Pin, sync::OnceLock}; +use std::{fmt::Display, sync::OnceLock}; + +#[cfg(feature = "async")] +use std::pin::Pin; #[doc(hidden)] pub mod exec; @@ -20,7 +23,6 @@ pub use config::*; mod flag; pub use flag::*; -use tokio::io::AsyncWriteExt; /// Global static reference to the current program instance static THIS_PROGRAM: OnceLock<Option<Box<dyn std::any::Any + Send + Sync>>> = OnceLock::new(); @@ -97,7 +99,7 @@ where } /// Returns a reference to the current program instance, if set. - pub async fn this_program() -> &'static Program<C, G> + pub fn this_program() -> &'static Program<C, G> where C: 'static, G: 'static, @@ -111,6 +113,19 @@ where .unwrap() } + // Get all registered dispatcher names from the program + pub fn get_nodes(&self) -> Vec<(String, &(dyn Dispatcher<G> + Send + Sync))> { + get_nodes(self) + } +} + +// Async program +#[cfg(feature = "async")] +impl<C, G> Program<C, G> +where + C: ProgramCollect<Enum = G>, + G: Display, +{ /// Sets the current program instance and runs the provided async function. async fn set_instance_and_run<F, Fut>(self, f: F) -> Fut::Output where @@ -169,17 +184,84 @@ where // Render result if stdout_setting.render_output && !result.is_empty() { print!("{}", result); - if let Err(e) = tokio::io::stdout().flush().await + if let Err(e) = std::io::Write::flush(&mut std::io::stdout()) && stdout_setting.error_output { eprintln!("{}", e); } } } +} - // Get all registered dispatcher names from the program - pub fn get_nodes(&self) -> Vec<(String, &(dyn Dispatcher<G> + Send + Sync))> { - get_nodes(self) +// Sync program +#[cfg(not(feature = "async"))] +impl<C, G> Program<C, G> +where + C: ProgramCollect<Enum = G>, + G: Display, +{ + /// Sets the current program instance and runs the provided function. + fn set_instance_and_run<F, R>(self, f: F) -> R + where + C: 'static + Send + Sync, + G: 'static + Send + Sync, + F: FnOnce(&'static Program<C, G>) -> R + Send + Sync, + { + THIS_PROGRAM.get_or_init(|| Some(Box::new(self))); + let program = THIS_PROGRAM + .get() + .unwrap() + .as_ref() + .unwrap() + .downcast_ref::<Program<C, G>>() + .unwrap(); + f(program) + } + + /// Run the command line program + pub fn exec_without_render(mut self) -> Result<RenderResult, ProgramExecuteError> + where + C: 'static + Send + Sync, + G: 'static + Send + Sync, + { + self.args = self.args.iter().skip(1).cloned().collect(); + self.set_instance_and_run(|p| crate::exec::exec(p).map_err(|e| e.into())) + } + + /// Run the command line program + pub fn exec(self) + where + C: 'static + Send + Sync, + G: 'static + Send + Sync, + { + let stdout_setting = self.stdout_setting.clone(); + let result = match self.exec_without_render() { + Ok(r) => r, + Err(e) => match e { + ProgramExecuteError::DispatcherNotFound => { + eprintln!("Dispatcher not found"); + return; + } + ProgramExecuteError::RendererNotFound(renderer_name) => { + eprintln!("Renderer `{}` not found", renderer_name); + return; + } + ProgramExecuteError::Other(e) => { + eprintln!("{}", e); + return; + } + }, + }; + + // Render result + if stdout_setting.render_output && !result.is_empty() { + print!("{}", result); + if let Err(e) = std::io::Write::flush(&mut std::io::stdout()) + && stdout_setting.error_output + { + eprintln!("{}", e); + } + } } } @@ -200,10 +282,15 @@ pub trait ProgramCollect { fn render(any: AnyOutput<Self::Enum>, r: &mut RenderResult); /// Find a matching chain to continue execution based on the input [AnyOutput](./struct.AnyOutput.html), returning a new [AnyOutput](./struct.AnyOutput.html) + #[cfg(feature = "async")] fn do_chain( any: AnyOutput<Self::Enum>, ) -> Pin<Box<dyn Future<Output = ChainProcess<Self::Enum>> + Send>>; + /// Find a matching chain to continue execution based on the input [AnyOutput](./struct.AnyOutput.html), returning a new [AnyOutput](./struct.AnyOutput.html) + #[cfg(not(feature = "async"))] + fn do_chain(any: AnyOutput<Self::Enum>) -> ChainProcess<Self::Enum>; + /// Match and execute specific completion logic based on any Entry #[cfg(feature = "comp")] fn do_comp(any: &AnyOutput<Self::Enum>, ctx: &ShellContext) -> Suggest; @@ -246,6 +333,7 @@ macro_rules! __dispatch_program_renderers { #[macro_export] #[doc(hidden)] +#[cfg(feature = "async")] macro_rules! __dispatch_program_chains { ( $( $chain_ty:ty => $chain_prev:ident, )* @@ -269,6 +357,31 @@ macro_rules! __dispatch_program_chains { }; } +#[macro_export] +#[doc(hidden)] +#[cfg(not(feature = "async"))] +macro_rules! __dispatch_program_chains { + ( + $( $chain_ty:ty => $chain_prev:ident, )* + ) => { + fn do_chain( + any: mingling::AnyOutput<Self::Enum>, + ) -> mingling::ChainProcess<Self::Enum> { + match any.member_id { + $( + Self::$chain_prev => { + // SAFETY: The `type_id` check ensures that `any` contains a value of type `$chain_prev`, + // so downcasting to `$chain_prev` is safe. + let value = unsafe { any.downcast::<$chain_prev>().unwrap_unchecked() }; + <$chain_ty as mingling::Chain<Self::Enum>>::proc(value) + } + )* + _ => panic!("No chain found for type id: {:?}", any.type_id), + } + } + }; +} + /// Get all registered dispatcher names from the program pub fn get_nodes<C: ProgramCollect<Enum = G>, G: Display>( program: &Program<C, G>, |
