From bd4b09b06181093c95e865b04d4a9cdda7dd0728 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Tue, 19 May 2026 21:38:58 +0800 Subject: Conditionally disable panic unwind support for async feature --- mingling_core/src/program/hook.rs | 17 +++++++---- mingling_core/src/program/once_exec.rs | 37 +++--------------------- mingling_core/src/program/repl_exec.rs | 53 +++++++++++++++++++++++++++++----- 3 files changed, 62 insertions(+), 45 deletions(-) (limited to 'mingling_core/src') diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs index 65f3f0b..8e231f1 100644 --- a/mingling_core/src/program/hook.rs +++ b/mingling_core/src/program/hook.rs @@ -2,7 +2,10 @@ use std::any::Any; -use crate::{AnyOutput, Program, ProgramCollect, RenderResult, error::ProgramPanic}; +use crate::{AnyOutput, Program, ProgramCollect, RenderResult}; + +#[cfg(not(feature = "async"))] +use crate::error::ProgramPanic; #[derive(Default)] pub struct ProgramHook @@ -34,6 +37,7 @@ where pub finish: Option i32>, /// Executes when the program panics + #[cfg(not(feature = "async"))] pub exec_panic: Option, /// Executes when the REPL starts (only available with `repl` feature) @@ -53,7 +57,7 @@ where pub repl_on_receive_result: Option, /// Executes when the REPL panics (only available with `repl` feature) - #[cfg(feature = "repl")] + #[cfg(all(feature = "repl", not(feature = "async")))] pub repl_on_panic: Option, } @@ -152,6 +156,7 @@ where } #[allow(dead_code)] + #[cfg(not(feature = "async"))] pub(crate) fn run_hook_exec_panic(&self, panic_info: &ProgramPanic) { if !self.user_context.run_hook { return; @@ -238,7 +243,7 @@ where } /// Runs the REPL panic hooks (only available with `repl` feature) - #[cfg(feature = "repl")] + #[cfg(all(feature = "repl", not(feature = "async")))] pub(crate) fn run_hook_repl_on_panic(&self, panic_info: &ProgramPanic) { if !self.user_context.run_hook { return; @@ -267,6 +272,7 @@ where pre_render: None, post_render: None, finish: None, + #[cfg(not(feature = "async"))] exec_panic: None, #[cfg(feature = "repl")] repl_on_begin: None, @@ -276,7 +282,7 @@ where repl_post_readline: None, #[cfg(feature = "repl")] repl_on_receive_result: None, - #[cfg(feature = "repl")] + #[cfg(all(feature = "repl", not(feature = "async")))] repl_on_panic: None, } } @@ -330,6 +336,7 @@ where } /// Sets the handler for the `exec_panic` event. + #[cfg(not(feature = "async"))] pub fn on_exec_panic(mut self, handler: fn(&ProgramPanic)) -> Self { let _ = self.exec_panic.insert(handler); self @@ -366,7 +373,7 @@ where } /// Sets the handler for the REPL panic event (only available with `repl` feature). - #[cfg(feature = "repl")] + #[cfg(all(feature = "repl", not(feature = "async")))] pub fn on_repl_panic(mut self, handler: fn(panic: &ProgramPanic)) -> Self { let _ = self.repl_on_panic.insert(handler); self diff --git a/mingling_core/src/program/once_exec.rs b/mingling_core/src/program/once_exec.rs index b68eb01..e1c0956 100644 --- a/mingling_core/src/program/once_exec.rs +++ b/mingling_core/src/program/once_exec.rs @@ -1,8 +1,8 @@ use crate::THIS_PROGRAM; -use crate::{ - Program, ProgramCollect, RenderResult, - error::{ProgramExecuteError, ProgramPanic}, -}; +use crate::{Program, ProgramCollect, RenderResult, error::ProgramExecuteError}; + +#[cfg(not(feature = "async"))] +use crate::error::ProgramPanic; // Async program #[cfg(feature = "async")] @@ -25,11 +25,6 @@ where .downcast_ref::>() .unwrap(); - #[cfg(not(panic = "abort"))] - if program.stdout_setting.silence_panic { - std::panic::set_hook(Box::new(|_| {})); - } - f(program).await } @@ -43,33 +38,9 @@ where self.args = self.args.iter().skip(1).cloned().collect(); - #[cfg(panic = "abort")] return self .exec_wrapper(|p| async { crate::exec::exec(p).await.map_err(|e| e.into()) }) .await; - - #[cfg(not(panic = "abort"))] - match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { - self.exec_wrapper(|p| async { crate::exec::exec(p).await.map_err(|e| e.into()) }) - })) { - Ok(fut) => fut.await, - Err(panic_info) => { - let panic_payload = ProgramPanic { - payload: panic_info, - }; - - let program = THIS_PROGRAM - .get() - .unwrap() - .as_ref() - .unwrap() - .downcast_ref::>() - .unwrap(); - - program.run_hook_exec_panic(&panic_payload); - Err(ProgramExecuteError::Panic(panic_payload)) - } - } } /// Run the command line program diff --git a/mingling_core/src/program/repl_exec.rs b/mingling_core/src/program/repl_exec.rs index f3dd9f7..5246ece 100644 --- a/mingling_core/src/program/repl_exec.rs +++ b/mingling_core/src/program/repl_exec.rs @@ -18,13 +18,6 @@ where /// /// This method starts an infinite loop that continuously reads user input, parses commands, executes them, /// and displays the execution result or error message. It is suitable for scenarios requiring command-line interaction with the user. - /// - /// # Important - /// - /// **REPL mode is currently only available when the `async` feature is disabled; it does not support async.** - /// - /// If the `async` feature is enabled, this method will be unavailable (as it is protected by `#[cfg(not(feature = "async"))]` conditional compilation). - /// Future versions may support asynchronous REPL, but currently only synchronous mode is supported. pub fn exec_repl(self) { self.run_hook_repl_on_begin(); @@ -50,6 +43,41 @@ where } } +#[cfg(feature = "async")] +impl Program +where + C: ProgramCollect + Send + Sync + 'static, +{ + /// Executes the REPL interactive CLI mode. + /// + /// This method starts an infinite loop that continuously reads user input, parses commands, executes them, + /// and displays the execution result or error message. It is suitable for scenarios requiring command-line interaction with the user. + /// + /// **Note:** When the `async` feature is enabled, panic unwinding is not supported. + /// Any panics during command execution will result in an abort rather than being caught and handled gracefully. + pub async fn exec_repl(self) { + self.run_hook_repl_on_begin(); + + self.exec_wrapper(async |p| -> ! { + loop { + p.run_hook_repl_pre_readline(); + let readline = readline_or_empty(); + p.run_hook_repl_post_readline(&readline); + + let args = split_input_string(readline.clone()); + + match exec_once(p, args).await { + Ok(r) => { + p.run_hook_repl_on_receive_result(&r); + } + _ => {} + } + } + }) + .await; + } +} + fn readline() -> Result { let mut input = String::new(); std::io::stdout().flush()?; @@ -99,3 +127,14 @@ where exec_result } + +#[cfg(feature = "async")] +async fn exec_once( + p: &'static Program, + args: Vec, +) -> Result +where + C: ProgramCollect + Send + Sync + 'static, +{ + super::exec::exec_with_args(p, args).await +} -- cgit