diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-07-24 01:05:34 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-07-24 01:05:34 +0800 |
| commit | d67fec8ef6cb9c53e0480fa91d7387a9f160c2cc (patch) | |
| tree | 4d5fb1d6f21aee695668ca08c20bd38fda99926e | |
| parent | d8d239022e25b74d99a095486fe8cec1c999777b (diff) | |
feat(core): consolidate sync/async exec pipeline with `might_be_async`
Replace manual `#[cfg(feature = "async")]` code duplication in `exec`
and
`exec_with_args` with `#[might_be_async::func]` annotations and
`might_be_async::invoke!()` wrappers, reducing two code paths to one.
| -rw-r--r-- | CHANGELOG.md | 10 | ||||
| -rw-r--r-- | mingling_core/src/program/exec.rs | 177 |
2 files changed, 14 insertions, 173 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d813098..da1c26a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -188,6 +188,16 @@ None A new module `mingling_core::asset::core_invokes` has been added to provide a centralized location for internal invocation helpers. +9. **[`core:exec`]** Refactored the program execution pipeline (`exec` and `exec_with_args`) to use the `might_be_async` crate instead of manual `#[cfg(feature = "async")]` duplication. The previously separate sync and async implementations have been consolidated into a single `#[might_be_async::func]`-annotated function, with `might_be_async::invoke!()` wrapping the `C::do_chain(current)` call inside `exec_with_args` and the delegation from `exec` to `exec_with_args`. + + The `exec` function no longer contains the full execution loop inline. Instead, it delegates to `exec_with_args` (which now also carries the `#[might_be_async::func]` annotation), reducing code duplication and centralizing the execution logic. + + - **`exec`**: Changed from separate `#[cfg(feature = "async")]` and `#[cfg(not(feature = "async"))]` implementations to a single `#[might_be_async::func]` function that calls `might_be_async::invoke!(exec_with_args(program, &program.args))`. + - **`exec_with_args`**: Changed from separate implementations to a single `#[might_be_async::func]` function. The `C::do_chain(current)` call is now wrapped with `might_be_async::invoke!(C::do_chain(current))` to support both sync and async chain execution. + - **Removed**: The `error.rs` submodule import remains, but the separate sync/async code blocks in the function bodies have been eliminated. + + _No behavioral changes. All existing functionality — hooks, help handling, chain execution, renderer dispatch, and exit code management — is preserved identically._ + #### Features: 1. **[`core`]** Added `RenderResult::new()` method for creating a new `RenderResult` with default values (empty text and exit code 0). This provides a more explicit and discoverable constructor compared to `RenderResult::default()`, making it clearer when a fresh result is being created for use with `write!`/`writeln!`. diff --git a/mingling_core/src/program/exec.rs b/mingling_core/src/program/exec.rs index f5bdc2b..f0322a5 100644 --- a/mingling_core/src/program/exec.rs +++ b/mingling_core/src/program/exec.rs @@ -8,184 +8,15 @@ use crate::{ #[doc(hidden)] pub mod error; -#[cfg(feature = "async")] -pub async fn exec<C>( - program: &'static Program<C>, -) -> Result<RenderResult, ProgramInternalExecuteError> -where - C: ProgramCollect<Enum = C>, -{ - exec_with_args(program, &program.args).await -} - -#[cfg(not(feature = "async"))] +#[might_be_async::func] pub fn exec<C>(program: &'static Program<C>) -> Result<RenderResult, ProgramInternalExecuteError> where C: ProgramCollect<Enum = C>, { - exec_with_args(program, &program.args) -} - -#[cfg(feature = "async")] -pub async fn exec_with_args<C>( - program: &'static Program<C>, - args: &[String], -) -> Result<RenderResult, ProgramInternalExecuteError> -where - C: ProgramCollect<Enum = C>, -{ - // Exit code - let mut exit_code: i32 = 0; - - macro_rules! control { - ($hook_call:expr, $current:expr) => { - let __ccc = $hook_call; - if let Some(r) = - handle_program_control(program, __ccc, Some(&mut $current), &mut exit_code) - { - return Ok(r); - } - }; - ($hook_call:expr) => { - let __ccc = $hook_call; - if let Some(r) = handle_program_control(program, __ccc, None, &mut exit_code) { - return Ok(r); - } - }; - } - - // Current - let mut current = C::build_dispatcher_not_found(vec![]); - - // Run hooks - control!( - program.run_hook_pre_dispatch(crate::hook::HookPreDispatchInfo { arguments: args }), - current - ); - - // Dispatch args - either via dynamic dispatch or trie dispatch based on feature flag - let mut current = if cfg!(not(feature = "dispatch_tree")) { - dispatch_args_dynamic(program, args)? - } else { - C::dispatch_args_trie(args)? - }; - - // Run hook - control!( - program.run_hook_post_dispatch(crate::hook::HookPostDispatchInfo { - entry: ¤t.member_id, - }), - current - ); - - let mut stop_next = false; - - // If the program has Help enabled, skip actual logic and jump to Help - if program.user_context.help { - let mut render_result = render_help::<C>(program, current); - - // Run hook - control!(program.run_hook_finish(crate::hook::HookFinishInfo {})); - render_result.exit_code = exit_code; - - return Ok(render_result); - } - - loop { - let final_exec = stop_next; - - current = { - // If a chain exists, execute as a chain - if C::has_chain(¤t) { - // Run hook - control!( - program.run_hook_pre_chain(crate::hook::HookPreChainInfo { - input: ¤t.member_id, - raw: current.inner.as_ref(), - }), - current - ); - - match C::do_chain(current).await { - ChainProcess::Ok((any, NextProcess::Renderer)) => { - { - let mut render_result = render::<C>(program, any); - - // Run hook - control!(program.run_hook_finish(crate::hook::HookFinishInfo {})); - render_result.exit_code = exit_code; - - return Ok(render_result); - }; - } - ChainProcess::Ok((mut any, NextProcess::Chain)) => { - // Run hook - control!( - program.run_hook_post_chain(crate::hook::HookPostChainInfo { - output: &any - }), - any - ); - any - } - ChainProcess::Err(e) => { - // Run hook - control!( - program.run_hook_finish(crate::hook::HookFinishInfo {}), - &mut C::build_empty_result() - ); - return Err(e.into()); - } - } - } - // If no chain exists, attempt to render - else if C::has_renderer(¤t) { - // Run hook - control!( - program.run_hook_pre_render(crate::hook::HookPreRenderInfo { - input: ¤t.member_id, - raw: current.inner.as_ref(), - }), - current - ); - - let mut render_result = render::<C>(program, current); - - // Run hooks - control!( - program.run_hook_post_render(crate::hook::HookPostRenderInfo { - result: &render_result, - }) - ); - - control!(program.run_hook_finish(crate::hook::HookFinishInfo {})); - - render_result.exit_code = exit_code; - return Ok(render_result); - } - // No renderer exists - else { - stop_next = true; - C::build_renderer_not_found(current.member_id) - } - }; - - if final_exec && stop_next { - break; - } - } - let mut render_result = RenderResult::default(); - - // Run hook - control!( - program.run_hook_finish(crate::hook::HookFinishInfo {}), - current - ); - render_result.exit_code = exit_code; - Ok(render_result) + might_be_async::invoke!(exec_with_args(program, &program.args)) } -#[cfg(not(feature = "async"))] +#[might_be_async::func] pub fn exec_with_args<C>( program: &'static Program<C>, args: &[String], @@ -265,7 +96,7 @@ where current ); - match C::do_chain(current) { + match might_be_async::invoke!(C::do_chain(current)) { ChainProcess::Ok((any, NextProcess::Renderer)) => { { let mut render_result = render::<C>(program, any); |
