aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-07-24 01:05:34 +0800
committer魏曹先生 <1992414357@qq.com>2026-07-24 01:05:34 +0800
commitd67fec8ef6cb9c53e0480fa91d7387a9f160c2cc (patch)
tree4d5fb1d6f21aee695668ca08c20bd38fda99926e
parentd8d239022e25b74d99a095486fe8cec1c999777b (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.md10
-rw-r--r--mingling_core/src/program/exec.rs177
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: &current.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(&current) {
- // Run hook
- control!(
- program.run_hook_pre_chain(crate::hook::HookPreChainInfo {
- input: &current.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(&current) {
- // Run hook
- control!(
- program.run_hook_pre_render(crate::hook::HookPreRenderInfo {
- input: &current.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);