From c28028c69d02b723745167b23fdaf25db673a2e9 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Fri, 24 Jul 2026 01:27:33 +0800 Subject: refactor(once_exec, repl_exec): unify sync and async execution paths --- mingling_core/src/program/once_exec.rs | 194 ++++++++++++--------------------- 1 file changed, 68 insertions(+), 126 deletions(-) (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 index a846d04..96723fd 100644 --- a/mingling_core/src/program/once_exec.rs +++ b/mingling_core/src/program/once_exec.rs @@ -1,28 +1,10 @@ use crate::THIS_PROGRAM; use crate::{Program, ProgramCollect, RenderResult, error::ProgramExecuteError}; -// Async program -#[cfg(feature = "async")] impl Program where C: ProgramCollect, { - pub(crate) async fn exec_wrapper(self, f: F) -> Fut::Output - where - C: 'static + Send + Sync, - F: FnOnce(&'static Program) -> Fut + Send + Sync, - Fut: Future + Send, - { - THIS_PROGRAM.set(Box::new(self)); - let program = THIS_PROGRAM - .get_raw() - .unwrap() - .downcast_ref::>() - .unwrap(); - - f(program).await - } - /// Run the command line program /// /// # Errors @@ -33,7 +15,8 @@ where /// # Panics /// /// Panics if the program encounters a non-recoverable internal error. - pub async fn exec_without_render(mut self) -> Result + #[might_be_async::func] + pub fn exec_without_render(mut self) -> Result where C: 'static + Send + Sync, { @@ -42,21 +25,56 @@ where self.args = self.args.iter().skip(1).cloned().collect(); - return self - .exec_wrapper(|p| async { crate::exec::exec(p).await.map_err(|e| e.into()) }) - .await; + #[cfg(not(feature = "async"))] + { + #[cfg(panic = "abort")] + return self.exec_wrapper(|p| crate::exec::exec(p).map_err(|e| e.into())); + + #[cfg(not(panic = "abort"))] + match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + self.exec_wrapper(|p| crate::exec::exec(p).map_err(std::convert::Into::into)) + })) { + Ok(result) => result, + Err(panic_info) => { + let panic_payload = crate::error::ProgramPanic { + payload: panic_info, + }; + + let program = THIS_PROGRAM + .get_raw() + .unwrap() + .downcast_ref::>() + .unwrap(); + + #[cfg(not(feature = "async"))] + program.run_hook_exec_panic(crate::hook::HookPanicInfo { + panic: &panic_payload, + }); + + Err(ProgramExecuteError::Panic(panic_payload)) + } + } + } + + #[cfg(feature = "async")] + { + return self + .exec_wrapper(|p| async { crate::exec::exec(p).await.map_err(|e| e.into()) }) + .await; + } } /// Run the command line program #[must_use] - pub async fn exec(self) -> i32 + #[might_be_async::func] + 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().await { + let result = match might_be_async::invoke!(self.exec_without_render()) { Ok(r) => r, Err(e) => match e { ProgramExecuteError::DispatcherNotFound => { @@ -88,11 +106,12 @@ where } /// Run the command line program, then exit - pub async fn exec_and_exit(self) + #[might_be_async::func] + pub fn exec_and_exit(self) where C: 'static + Send + Sync, { - let exit_code = self.exec().await; + let exit_code = might_be_async::invoke!(self.exec()); // SAFETY: exec() is synchronous — it returns only after all // chain handlers and renderers have finished. No code still // holds references from get_raw() at this point. @@ -101,6 +120,29 @@ where } } +// Async program +#[cfg(feature = "async")] +impl Program +where + C: ProgramCollect, +{ + pub(crate) async fn exec_wrapper(self, f: F) -> Fut::Output + where + C: 'static + Send + Sync, + F: FnOnce(&'static Program) -> Fut + Send + Sync, + Fut: Future + Send, + { + THIS_PROGRAM.set(Box::new(self)); + let program = THIS_PROGRAM + .get_raw() + .unwrap() + .downcast_ref::>() + .unwrap(); + + f(program).await + } +} + // Sync program #[cfg(not(feature = "async"))] impl Program @@ -126,104 +168,4 @@ where f(program) } - - /// Run the command line program - /// - /// # Errors - /// - /// Returns `Err(ProgramExecuteError)` if execution fails, - /// e.g., if no dispatcher is found or a chain error occurs. - /// - /// # Panics - /// - /// Panics if the program encounters a non-recoverable internal error. - pub fn exec_without_render(mut self) -> Result - where - C: 'static + Send + Sync, - { - // Run hooks - self.run_hook_on_begin(crate::hook::HookBeginInfo {}); - - self.args = self.args.iter().skip(1).cloned().collect(); - - #[cfg(panic = "abort")] - return self.exec_wrapper(|p| crate::exec::exec(p).map_err(|e| e.into())); - - #[cfg(not(panic = "abort"))] - match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { - self.exec_wrapper(|p| crate::exec::exec(p).map_err(std::convert::Into::into)) - })) { - Ok(result) => result, - Err(panic_info) => { - let panic_payload = crate::error::ProgramPanic { - payload: panic_info, - }; - - let program = THIS_PROGRAM - .get_raw() - .unwrap() - .downcast_ref::>() - .unwrap(); - - program.run_hook_exec_panic(crate::hook::HookPanicInfo { - panic: &panic_payload, - }); - - Err(ProgramExecuteError::Panic(panic_payload)) - } - } - } - - /// Run the command line program - #[must_use] - 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 `{renderer_name}` not found"); - return 1; - } - ProgramExecuteError::Other(e) => { - eprintln!("{e}"); - return 1; - } - ProgramExecuteError::Panic(unwinded_error) => { - eprintln!("{unwinded_error}"); - return 1; - } - }, - }; - - // Read exit code - // Render result - if stdout_setting.render_output { - result.std_print(); - } - - result.exit_code - } - - /// Run the command line program, then exit - pub fn exec_and_exit(self) - where - C: 'static + Send + Sync, - { - let exit_code = self.exec(); - // SAFETY: exec() is synchronous — it returns only after all - // chain handlers and renderers have finished. No code still - // holds references from get_raw() at this point. - drop(unsafe { THIS_PROGRAM.take() }); - std::process::exit(exit_code) - } } -- cgit