From ab7c5785fb290541ad4361c0d46241817c3ff5f9 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Mon, 18 May 2026 16:02:57 +0800 Subject: Refactor program module into submodules --- mingling_core/src/program/once_exec.rs | 235 +++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 mingling_core/src/program/once_exec.rs (limited to 'mingling_core/src/program/once_exec.rs') diff --git a/mingling_core/src/program/once_exec.rs b/mingling_core/src/program/once_exec.rs new file mode 100644 index 0000000..ac985e2 --- /dev/null +++ b/mingling_core/src/program/once_exec.rs @@ -0,0 +1,235 @@ +use crate::THIS_PROGRAM; +use crate::{ + Program, ProgramCollect, RenderResult, + error::{ProgramExecuteError, ProgramPanic}, +}; + +// Async program +#[cfg(feature = "async")] +impl Program +where + C: ProgramCollect, +{ + async fn exec_wrapper(self, f: F) -> Result + where + C: 'static + Send + Sync, + F: FnOnce(&'static Program) -> Fut + Send + Sync, + Fut: Future + Send, + { + THIS_PROGRAM.get_or_init(|| Some(Box::new(self))); + let program = THIS_PROGRAM + .get() + .unwrap() + .as_ref() + .unwrap() + .downcast_ref::>() + .unwrap(); + + #[cfg(not(panic = "abort"))] + if program.stdout_setting.silence_panic { + std::panic::set_hook(Box::new(|_| {})); + } + + #[cfg(panic = "abort")] + return Ok(f(program)); + + #[cfg(not(panic = "abort"))] + match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(program))) { + Ok(fut) => Ok(fut.await), + Err(panic_info) => { + let panic_payload = ProgramPanic { + payload: panic_info, + }; + program.run_hook_exec_panic(&panic_payload); + Err(panic_payload) + } + } + } + + /// Run the command line program + pub async fn exec_without_render(mut self) -> Result + where + C: 'static + Send + Sync, + { + // Run hooks + self.run_hook_on_begin(); + + self.args = self.args.iter().skip(1).cloned().collect(); + match self + .exec_wrapper(|p| async { crate::exec::exec(p).await.map_err(|e| e.into()) }) + .await + { + Ok(r) => r, + Err(e) => Err(ProgramExecuteError::Panic(e)), + } + } + + /// Run the command line program + pub async fn exec(self) -> i32 + where + C: 'static + Send + Sync, + { + 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 1; + } + ProgramExecuteError::RendererNotFound(renderer_name) => { + eprintln!("Renderer `{}` not found", renderer_name); + return 1; + } + ProgramExecuteError::Other(e) => { + eprintln!("{}", e); + return 1; + } + ProgramExecuteError::Panic(unwinded_error) => { + eprintln!("{}", unwinded_error); + return 1; + } + }, + }; + + // Render result + if stdout_setting.render_output && !result.is_empty() { + let exit_code = result.exit_code; + print!("{}", result); + + if let Err(e) = std::io::Write::flush(&mut std::io::stdout()) + && stdout_setting.error_output + { + eprintln!("{}", e); + 1 + } else { + exit_code + } + } else { + 0 + } + } + + /// Run the command line program, then exit + pub async fn exec_and_exit(self) + where + C: 'static + Send + Sync, + { + std::process::exit(self.exec().await) + } +} + +// Sync program +#[cfg(not(feature = "async"))] +impl Program +where + C: ProgramCollect, +{ + fn exec_wrapper(self, f: F) -> Result + where + C: 'static + Send + Sync, + F: FnOnce(&'static Program) -> R + Send + Sync, + { + THIS_PROGRAM.get_or_init(|| Some(Box::new(self))); + let program = THIS_PROGRAM + .get() + .unwrap() + .as_ref() + .unwrap() + .downcast_ref::>() + .unwrap(); + + #[cfg(not(panic = "abort"))] + if program.stdout_setting.silence_panic { + std::panic::set_hook(Box::new(|_| {})); + } + + #[cfg(panic = "abort")] + return Ok(f(program)); + + #[cfg(not(panic = "abort"))] + match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(program))) { + Ok(result) => Ok(result), + Err(panic_info) => { + use crate::error::ProgramPanic; + + let panic_payload = ProgramPanic { + payload: panic_info, + }; + program.run_hook_exec_panic(&panic_payload); + Err(panic_payload) + } + } + } + + /// Run the command line program + pub fn exec_without_render(mut self) -> Result + where + C: 'static + Send + Sync, + { + // Run hooks + self.run_hook_on_begin(); + + self.args = self.args.iter().skip(1).cloned().collect(); + match self.exec_wrapper(|p| crate::exec::exec(p).map_err(|e| e.into())) { + Ok(r) => r, + Err(e) => Err(ProgramExecuteError::Panic(e)), + } + } + + /// Run the command line program + pub fn exec(self) -> i32 + where + C: 'static + Send + Sync, + { + use crate::error::ProgramExecuteError; + + 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 1; + } + ProgramExecuteError::RendererNotFound(renderer_name) => { + eprintln!("Renderer `{}` not found", renderer_name); + return 1; + } + ProgramExecuteError::Other(e) => { + eprintln!("{}", e); + return 1; + } + ProgramExecuteError::Panic(unwinded_error) => { + eprintln!("{}", unwinded_error); + return 1; + } + }, + }; + + // Render result + if stdout_setting.render_output && !result.is_empty() { + let exit_code = result.exit_code; + print!("{}", result); + + if let Err(e) = std::io::Write::flush(&mut std::io::stdout()) + && stdout_setting.error_output + { + eprintln!("{}", e); + 1 + } else { + exit_code + } + } else { + 0 + } + } + + /// Run the command line program, then exit + pub fn exec_and_exit(self) + where + C: 'static + Send + Sync, + { + std::process::exit(self.exec()) + } +} -- cgit