From ec6c87d12062576271231b88364a4aa00765ae65 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Sat, 15 Aug 2026 03:28:02 +0800 Subject: feat(core): allow pre_dispatch hooks to mutate arguments Change `HookPreDispatchInfo.arguments` from `&[String]` to `&mut Vec` so hooks can rewrite command-line arguments before dispatch. --- mingling_core/src/program/hook.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'mingling_core/src/program/hook.rs') diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs index 8fd2ba1..92106f9 100644 --- a/mingling_core/src/program/hook.rs +++ b/mingling_core/src/program/hook.rs @@ -64,8 +64,9 @@ where pub begin: Option>, /// Executes before the program dispatches - pub pre_dispatch: - Option Fn(&HookPreDispatchInfo<'a>) -> ProgramControls + Send + Sync>>, + pub pre_dispatch: Option< + Box Fn(&mut HookPreDispatchInfo<'a>) -> ProgramControls + Send + Sync>, + >, /// Executes after the program dispatches pub post_dispatch: Option< @@ -162,7 +163,10 @@ where } } - pub(crate) fn run_hook_pre_dispatch(&self, info: &HookPreDispatchInfo) -> ProgramControls { + pub(crate) fn run_hook_pre_dispatch( + &self, + info: &mut HookPreDispatchInfo, + ) -> ProgramControls { if !self.user_context.run_hook { return ProgramControls::Empty; } @@ -475,7 +479,7 @@ where #[must_use] pub fn on_pre_dispatch(mut self, handler: F) -> Self where - F: for<'a> Fn(&HookPreDispatchInfo<'a>) -> R + 'static + Send + Sync, + F: for<'a> Fn(&mut HookPreDispatchInfo<'a>) -> R + 'static + Send + Sync, R: Into>, { self.pre_dispatch = Some(Box::new(move |info| handler(info).into())); @@ -801,16 +805,21 @@ mod tests { #[test] fn test_hook_on_pre_dispatch() { static CALLED: AtomicBool = AtomicBool::new(false); - let hook = - ProgramHook::::empty().on_pre_dispatch(|info: &HookPreDispatchInfo| { - assert_eq!(info.arguments, &["a", "b"]); + let mut args = vec!["a".to_string(), "b".to_string()]; + let hook = ProgramHook::::empty().on_pre_dispatch( + |info: &mut HookPreDispatchInfo| { + assert_eq!(info.arguments.as_slice(), &["a", "b"]); + // The hook may rewrite the arguments before dispatch + info.arguments.push("c".to_string()); CALLED.store(true, Ordering::SeqCst); - }); + }, + ); assert!(hook.pre_dispatch.is_some()); - (hook.pre_dispatch.as_ref().unwrap())(&HookPreDispatchInfo { - arguments: &["a".to_string(), "b".to_string()], + (hook.pre_dispatch.as_ref().unwrap())(&mut HookPreDispatchInfo { + arguments: &mut args, }); assert!(CALLED.load(Ordering::SeqCst)); + assert_eq!(args.as_slice(), &["a", "b", "c"]); } #[test] @@ -910,7 +919,7 @@ mod tests { fn test_hook_builder_chaining() { let hook = ProgramHook::::empty() .on_begin::<_, ()>(|_: &HookBeginInfo| ()) - .on_pre_dispatch(|_: &HookPreDispatchInfo| ()) + .on_pre_dispatch(|_: &mut HookPreDispatchInfo| ()) .on_post_dispatch(|_: &HookPostDispatchInfo| ()) .on_pre_chain(|_: &HookPreChainInfo| ()) .on_post_chain(|_: &HookPostChainInfo| ()) -- cgit