diff options
| author | Weicao-CatilGrass <1992414357@qq.com> | 2026-05-13 07:28:02 +0800 |
|---|---|---|
| committer | Weicao-CatilGrass <1992414357@qq.com> | 2026-05-13 07:28:02 +0800 |
| commit | 95c6b979ca399671eed8bf9c72f53cfe5d46f431 (patch) | |
| tree | 8225b39bee4ad3b7ebc8a36ab978d1329f667eb8 | |
| parent | fef888b75b2544765aa06808c14490a2af827313 (diff) | |
Migrate exit code control to resource-based system
| -rw-r--r-- | CHANGELOG.md | 13 | ||||
| -rw-r--r-- | examples/example-exit-code/Cargo.lock | 105 | ||||
| -rw-r--r-- | examples/example-exit-code/Cargo.toml | 7 | ||||
| -rw-r--r-- | examples/example-exit-code/src/main.rs | 42 | ||||
| -rw-r--r-- | mingling/src/lib.rs | 8 | ||||
| -rw-r--r-- | mingling/src/res.rs | 2 | ||||
| -rw-r--r-- | mingling/src/res/exit_code.rs | 4 | ||||
| -rw-r--r-- | mingling/src/setups.rs | 11 | ||||
| -rw-r--r-- | mingling/src/setups/basic.rs (renamed from mingling_core/src/program/setup/basic.rs) | 5 | ||||
| -rw-r--r-- | mingling/src/setups/exit_code.rs | 40 | ||||
| -rw-r--r-- | mingling/src/setups/general_renderer.rs (renamed from mingling_core/src/program/setup/general_renderer.rs) | 5 | ||||
| -rw-r--r-- | mingling_core/src/lib.rs | 10 | ||||
| -rw-r--r-- | mingling_core/src/program.rs | 11 | ||||
| -rw-r--r-- | mingling_core/src/program/exec.rs | 4 | ||||
| -rw-r--r-- | mingling_core/src/program/hook.rs | 147 | ||||
| -rw-r--r-- | mingling_core/src/program/setup.rs | 13 | ||||
| -rw-r--r-- | mingling_core/src/program/setup/exit_code_control.rs | 35 |
17 files changed, 242 insertions, 220 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 499161e..96db9ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,13 +46,22 @@ if mingling::feature::MINGLING_ASYNC { } ``` -5. **\[core\]** Added `with_hook` and `with_hook_anonymous` functions to embed callback events into the program lifecycle +5. **\[core\]** Added `with_hook` functions to embed callback events into the program lifecycle 6. **\[core\]** Added `user_context.run_hook` configuration item to control whether the program runs hooks 7. **\[core\]** Added `exec_and_exit`, which will return an `i32` exit code after the program ends -8. **\[core\]** Added `ExitCodeSetup`, now you can use `mingling::update_exit_code(i32)` to control the exit code +8. **\[core\]** Added `ExitCodeSetup`, you can control the program's exit code by modifying the `mingling::res::ExitCode` resource + +```rust +#[chain] +fn your_chain(_prev: Prev) -> NextProcess { + // Use `modify_res` to modify the value of `ExitCode` + this::<ThisProgram>().modify_res(|r: &mut ExitCode| r.exit_code = 1); + // ... +} +``` 9. **\[core\]** `RenderResult` now carries new data `exit_code` diff --git a/examples/example-exit-code/Cargo.lock b/examples/example-exit-code/Cargo.lock new file mode 100644 index 0000000..efe8f6e --- /dev/null +++ b/examples/example-exit-code/Cargo.lock @@ -0,0 +1,105 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "example-exit-code" +version = "0.1.0" +dependencies = [ + "mingling", +] + +[[package]] +name = "just_fmt" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5454cda0d57db59778608d7a47bff5b16c6705598265869fb052b657f66cf05e" + +[[package]] +name = "mingling" +version = "0.1.8" +dependencies = [ + "mingling_core", + "mingling_macros", +] + +[[package]] +name = "mingling_core" +version = "0.1.8" +dependencies = [ + "just_fmt", + "once_cell", + "thiserror", +] + +[[package]] +name = "mingling_macros" +version = "0.1.8" +dependencies = [ + "just_fmt", + "once_cell", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" diff --git a/examples/example-exit-code/Cargo.toml b/examples/example-exit-code/Cargo.toml new file mode 100644 index 0000000..a6c9c7c --- /dev/null +++ b/examples/example-exit-code/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "example-exit-code" +version = "0.1.0" +edition = "2024" + +[dependencies] +mingling = { path = "../../mingling" } diff --git a/examples/example-exit-code/src/main.rs b/examples/example-exit-code/src/main.rs new file mode 100644 index 0000000..f138fb3 --- /dev/null +++ b/examples/example-exit-code/src/main.rs @@ -0,0 +1,42 @@ +//! `Mingling` Example - Exit Code +//! +//! This example demonstrates how to modify the program's exit code using `ExitCodeSetup`. +//! By default, the program exits with code 0. This example shows: +//! 1. Using `dispatcher!` to define an error command, +//! 2. Using `chain!` to handle errors and set a custom exit code via `ProgramExitCode`, +//! 3. Using `renderer!` to print an error message. +//! +//! # How to Run +//! ```bash +//! cargo run --manifest-path ./examples/example-exit-code/Cargo.toml -- error +//! ``` + +use mingling::{ + macros::{chain, dispatcher, gen_program, pack, r_println, renderer}, + res::ExitCode, + setup::ExitCodeSetup, + this, +}; + +fn main() { + let mut program = ThisProgram::new(); + program.with_dispatcher(ErrorCommand); + program.with_setup(ExitCodeSetup::<ThisProgram>::default()); + program.exec(); +} + +dispatcher!("error", ErrorCommand => ErrorEntry); +pack!(ResultError = ()); + +#[chain] +fn handle_error_entry(_prev: ErrorEntry) -> NextProcess { + this::<ThisProgram>().modify_res(|r: &mut ExitCode| r.exit_code = 1); + return ResultError::default(); +} + +#[renderer] +fn render_error(_prev: ResultError) { + r_println!("Error!"); +} + +gen_program!(); diff --git a/mingling/src/lib.rs b/mingling/src/lib.rs index 79d5b19..41a9ec1 100644 --- a/mingling/src/lib.rs +++ b/mingling/src/lib.rs @@ -167,3 +167,11 @@ pub mod feature { /// Whether the `repl` feature is enabled pub use crate::features::MINGLING_REPL; } + +mod setups; + +pub mod setup { + pub use crate::setups::*; +} + +pub mod res; diff --git a/mingling/src/res.rs b/mingling/src/res.rs new file mode 100644 index 0000000..d625f8f --- /dev/null +++ b/mingling/src/res.rs @@ -0,0 +1,2 @@ +mod exit_code; +pub use exit_code::*; diff --git a/mingling/src/res/exit_code.rs b/mingling/src/res/exit_code.rs new file mode 100644 index 0000000..388a6f1 --- /dev/null +++ b/mingling/src/res/exit_code.rs @@ -0,0 +1,4 @@ +#[derive(Debug, Default, Clone, Copy)] +pub struct ExitCode { + pub exit_code: i32, +} diff --git a/mingling/src/setups.rs b/mingling/src/setups.rs new file mode 100644 index 0000000..351112b --- /dev/null +++ b/mingling/src/setups.rs @@ -0,0 +1,11 @@ +mod basic; +pub use basic::*; + +mod exit_code; +pub use exit_code::*; + +#[cfg(feature = "general_renderer")] +mod general_renderer; + +#[cfg(feature = "general_renderer")] +pub use general_renderer::*; diff --git a/mingling_core/src/program/setup/basic.rs b/mingling/src/setups/basic.rs index 9bd4056..6164c64 100644 --- a/mingling_core/src/program/setup/basic.rs +++ b/mingling/src/setups/basic.rs @@ -1,7 +1,4 @@ -use crate::{ - ProgramCollect, - program::{Program, setup::ProgramSetup}, -}; +use mingling_core::{Program, ProgramCollect, setup::ProgramSetup}; /// Performs basic program initialization: /// diff --git a/mingling/src/setups/exit_code.rs b/mingling/src/setups/exit_code.rs new file mode 100644 index 0000000..3267f85 --- /dev/null +++ b/mingling/src/setups/exit_code.rs @@ -0,0 +1,40 @@ +use std::marker::PhantomData; + +use mingling_core::{ProgramCollect, hook::ProgramHook, setup::ProgramSetup, this}; + +use crate::res::ExitCode; + +/// Provides the ability to control the program's exit code, which is returned when the program ends. +/// +/// - Use `mingling::update_exit_code` to update the exit code. +/// - Use `mingling::current_exit_code` to query the current exit code. +pub struct ExitCodeSetup<C> { + _collect: PhantomData<C>, +} + +impl<C> Default for ExitCodeSetup<C> +where + C: ProgramCollect<Enum = C> + 'static, +{ + fn default() -> Self { + Self { + _collect: Default::default(), + } + } +} + +impl<C> ProgramSetup<C> for ExitCodeSetup<C> +where + C: ProgramCollect<Enum = C> + 'static, +{ + fn setup(&mut self, program: &mut crate::Program<C>) { + // Insert resource + program.with_resource(ExitCode { exit_code: 0 }); + + // Insert hook to override exit code before program ends + program.with_hook(ProgramHook::empty().on_finish(|| { + let this = this::<C>().res_or_default(); + *this + })); + } +} diff --git a/mingling_core/src/program/setup/general_renderer.rs b/mingling/src/setups/general_renderer.rs index d2666da..a1d1f06 100644 --- a/mingling_core/src/program/setup/general_renderer.rs +++ b/mingling/src/setups/general_renderer.rs @@ -1,7 +1,4 @@ -use crate::{ - ProgramCollect, - program::{Program, setup::ProgramSetup}, -}; +use mingling_core::{Program, ProgramCollect, setup::ProgramSetup}; /// Sets up the general renderer for the program: /// diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs index e1c188f..817cc7a 100644 --- a/mingling_core/src/lib.rs +++ b/mingling_core/src/lib.rs @@ -46,11 +46,6 @@ pub use crate::program::*; pub use crate::renderer::render_result::*; -/// `Mingling`'s Program initialization system -pub mod setup { - pub use crate::program::setup::*; -} - #[cfg(feature = "builds")] #[doc(hidden)] pub mod builds; @@ -72,5 +67,6 @@ pub mod comp; #[cfg(feature = "comp")] pub use crate::comp::*; -pub use crate::setup::exit_code_control::current_exit_code; -pub use crate::setup::exit_code_control::update_exit_code; +pub mod setup { + pub use crate::program::setup::ProgramSetup; +} diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs index b8a409e..0d8506a 100644 --- a/mingling_core/src/program.rs +++ b/mingling_core/src/program.rs @@ -11,11 +11,10 @@ use crate::{ AnyOutput, ChainProcess, GlobalResources, Groupped, RenderResult, asset::dispatcher::Dispatcher, error::{ChainProcessError, ProgramExecuteError}, - hook::{ProgramAnonymousHook, ProgramHook}, + hook::ProgramHook, }; use std::{ collections::HashMap, - fmt::Display, sync::{Arc, Mutex, OnceLock}, }; @@ -77,7 +76,6 @@ where pub general_renderer_name: GeneralRendererSetting, pub(crate) hooks: Vec<ProgramHook<C>>, - pub(crate) anonymous_hooks: Vec<ProgramAnonymousHook>, pub(crate) resources: GlobalResources, } @@ -120,7 +118,6 @@ where general_renderer_name: GeneralRendererSetting::Disable, hooks: Vec::new(), - anonymous_hooks: Vec::new(), resources: Arc::new(Mutex::new(HashMap::new())), } @@ -176,7 +173,7 @@ where #[cfg(feature = "async")] impl<C> Program<C> where - C: ProgramCollect<Enum = C> + std::fmt::Display, + C: ProgramCollect<Enum = C>, { /// Sets the current program instance and runs the provided async function. async fn set_instance_and_run<F, Fut>(self, f: F) -> Fut::Output @@ -261,7 +258,7 @@ where #[cfg(not(feature = "async"))] impl<C> Program<C> where - C: ProgramCollect<Enum = C> + Display, + C: ProgramCollect<Enum = C>, { /// Sets the current program instance and runs the provided function. fn set_instance_and_run<F, R>(self, f: F) -> R @@ -345,7 +342,7 @@ where /// Note: It is recommended to use the `gen_program!()` macro from [mingling_macros](https://crates.io/crates/mingling_macros) to automatically create this type pub trait ProgramCollect { /// Enum type representing internal IDs for the program - type Enum: Display; + type Enum; type DispatcherNotFound: Groupped<Self::Enum>; type RendererNotFound: Groupped<Self::Enum>; diff --git a/mingling_core/src/program/exec.rs b/mingling_core/src/program/exec.rs index acd1bd6..c5ba628 100644 --- a/mingling_core/src/program/exec.rs +++ b/mingling_core/src/program/exec.rs @@ -13,7 +13,7 @@ pub async fn exec<C>( program: &'static Program<C>, ) -> Result<RenderResult, ProgramInternalExecuteError> where - C: ProgramCollect<Enum = C> + std::fmt::Display, + C: ProgramCollect<Enum = C>, { // Run hooks program.run_hook_on_begin(); @@ -105,7 +105,7 @@ where #[cfg(not(feature = "async"))] pub fn exec<C>(program: &'static Program<C>) -> Result<RenderResult, ProgramInternalExecuteError> where - C: ProgramCollect<Enum = C> + std::fmt::Display, + C: ProgramCollect<Enum = C>, { // Run hooks program.run_hook_on_begin(); diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs index a5c5d38..afc253c 100644 --- a/mingling_core/src/program/hook.rs +++ b/mingling_core/src/program/hook.rs @@ -1,4 +1,4 @@ -use std::{any::Any, fmt::Display}; +use std::any::Any; use crate::{AnyOutput, Program, ProgramCollect, RenderResult}; @@ -32,48 +32,10 @@ where pub finish: Option<fn() -> i32>, } -#[derive(Default)] -pub struct ProgramAnonymousHook { - /// Executes when the program starts running - pub begin: Option<fn()>, - - /// Executes before the program dispatches - pub pre_dispatch: Option<fn(args: &Vec<String>)>, - - /// Executes after the program dispatches - pub post_dispatch: Option<fn(entry_name: &str)>, - - /// Executes before the type enters the chain - pub pre_chain: Option<fn(input_name: &str, raw: &dyn Any)>, - - /// Executes after the chain processing for the type ends - pub post_chain: Option<fn(output_name: &str)>, - - /// Executes before the type enters the renderer - pub pre_render: Option<fn(input_name: &str, raw: &dyn Any)>, - - /// Executes after the type enters the renderer - pub post_render: Option<fn(result: &RenderResult)>, - - /// Executes before the program ends - pub finish: Option<fn() -> i32>, -} - impl<C> Program<C> where C: ProgramCollect<Enum = C>, { - /// Adds an anonymous hook to the program. The hook will be called at the appropriate - /// lifecycle events, but receives string representations instead of typed references. - pub fn with_hook_anonymous(&mut self, hook: ProgramAnonymousHook) { - self.anonymous_hooks.push(hook); - } -} - -impl<C> Program<C> -where - C: ProgramCollect<Enum = C> + Display, -{ /// Adds a typed hook to the program. The hook will be called at the appropriate /// lifecycle events. pub fn with_hook(&mut self, hook: ProgramHook<C>) { @@ -90,11 +52,6 @@ where begin() } } - for anonymous_hook in &self.anonymous_hooks { - if let Some(begin) = anonymous_hook.begin { - begin() - } - } } pub(crate) fn run_hook_pre_dispatch(&self, args: &Vec<String>) { @@ -107,11 +64,6 @@ where pre_dispatch(args) } } - for anonymous_hook in &self.anonymous_hooks { - if let Some(pre_dispatch) = anonymous_hook.pre_dispatch { - pre_dispatch(args) - } - } } pub(crate) fn run_hook_post_dispatch(&self, entry: &C) { @@ -124,11 +76,6 @@ where post_dispatch(entry) } } - for anonymous_hook in &self.anonymous_hooks { - if let Some(post_dispatch) = anonymous_hook.post_dispatch { - post_dispatch(entry.to_string().as_str()) - } - } } pub(crate) fn run_hook_pre_chain(&self, input: &C, raw: &dyn Any) { @@ -141,11 +88,6 @@ where pre_chain(input, raw) } } - for anonymous_hook in &self.anonymous_hooks { - if let Some(pre_chain) = anonymous_hook.pre_chain { - pre_chain(input.to_string().as_str(), raw) - } - } } pub(crate) fn run_hook_post_chain(&self, output: &AnyOutput<C>) { @@ -158,11 +100,6 @@ where post_chain(output) } } - for anonymous_hook in &self.anonymous_hooks { - if let Some(post_chain) = anonymous_hook.post_chain { - post_chain(output.member_id.to_string().as_str()) - } - } } pub(crate) fn run_hook_pre_render(&self, input: &C, raw: &dyn Any) { @@ -175,11 +112,6 @@ where pre_render(input, raw) } } - for anonymous_hook in &self.anonymous_hooks { - if let Some(pre_render) = anonymous_hook.pre_render { - pre_render(input.to_string().as_str(), raw) - } - } } pub(crate) fn run_hook_post_render(&self, result: &RenderResult) { @@ -192,11 +124,6 @@ where post_render(result) } } - for anonymous_hook in &self.anonymous_hooks { - if let Some(post_render) = anonymous_hook.post_render { - post_render(result) - } - } } pub(crate) fn run_hook_finish(&self) -> i32 { @@ -213,14 +140,6 @@ where } } } - for anonymous_hook in &self.anonymous_hooks { - if let Some(finish) = anonymous_hook.finish { - exit_code = finish(); - if exit_code != 0 { - return exit_code; - } - } - } exit_code } } @@ -291,67 +210,3 @@ where self } } - -impl ProgramAnonymousHook { - /// Creates a new empty hook set with no handlers. - pub fn empty() -> Self { - Self { - begin: None, - pre_dispatch: None, - post_dispatch: None, - pre_chain: None, - post_chain: None, - pre_render: None, - post_render: None, - finish: None, - } - } - - /// Sets the handler for the `begin` event. - pub fn on_begin(mut self, handler: fn()) -> Self { - let _ = self.begin.insert(handler); - self - } - - /// Sets the handler for the `pre_dispatch` event. - pub fn on_pre_dispatch(mut self, handler: fn(args: &Vec<String>)) -> Self { - let _ = self.pre_dispatch.insert(handler); - self - } - - /// Sets the handler for the `post_dispatch` event. - pub fn on_post_dispatch(mut self, handler: fn(entry_name: &str)) -> Self { - let _ = self.post_dispatch.insert(handler); - self - } - - /// Sets the handler for the `pre_chain` event. - pub fn on_pre_chain(mut self, handler: fn(input_name: &str, raw: &dyn Any)) -> Self { - let _ = self.pre_chain.insert(handler); - self - } - - /// Sets the handler for the `post_chain` event. - pub fn on_post_chain(mut self, handler: fn(output_name: &str)) -> Self { - let _ = self.post_chain.insert(handler); - self - } - - /// Sets the handler for the `pre_render` event. - pub fn on_pre_render(mut self, handler: fn(input_name: &str, raw: &dyn Any)) -> Self { - let _ = self.pre_render.insert(handler); - self - } - - /// Sets the handler for the `post_render` event. - pub fn on_post_render(mut self, handler: fn(result: &RenderResult)) -> Self { - let _ = self.post_render.insert(handler); - self - } - - /// Sets the handler for the `finish` event. - pub fn on_finish(mut self, handler: fn() -> i32) -> Self { - let _ = self.finish.insert(handler); - self - } -} diff --git a/mingling_core/src/program/setup.rs b/mingling_core/src/program/setup.rs index 289dfee..0fe8070 100644 --- a/mingling_core/src/program/setup.rs +++ b/mingling_core/src/program/setup.rs @@ -1,18 +1,5 @@ use crate::{ProgramCollect, program::Program}; -mod basic; -pub use basic::*; - -#[doc(hidden)] -pub mod exit_code_control; -pub use exit_code_control::ExitCodeSetup; - -#[cfg(feature = "general_renderer")] -mod general_renderer; - -#[cfg(feature = "general_renderer")] -pub use general_renderer::*; - pub trait ProgramSetup<C> where C: ProgramCollect<Enum = C>, diff --git a/mingling_core/src/program/setup/exit_code_control.rs b/mingling_core/src/program/setup/exit_code_control.rs deleted file mode 100644 index 20cd9b2..0000000 --- a/mingling_core/src/program/setup/exit_code_control.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::sync::atomic::{AtomicI32, Ordering}; - -use crate::{ProgramCollect, hook::ProgramAnonymousHook, setup::ProgramSetup}; - -static EXIT_CODE: AtomicI32 = AtomicI32::new(0); - -/// Provides the ability to control the program's exit code, which is returned when the program ends. -/// -/// - Use `mingling::update_exit_code` to update the exit code. -/// - Use `mingling::current_exit_code` to query the current exit code. -pub struct ExitCodeSetup; - -impl<C> ProgramSetup<C> for ExitCodeSetup -where - C: ProgramCollect<Enum = C>, -{ - fn setup(&mut self, program: &mut crate::Program<C>) { - program.with_hook_anonymous(ProgramAnonymousHook::empty().on_finish(current_exit_code)); - } -} - -/// Updates the program's exit code. -/// -/// This function sets the value that will be returned when the program exits. -/// The new code will take effect immediately and be used when the program finishes. -pub fn update_exit_code(code: i32) { - EXIT_CODE.store(code, Ordering::SeqCst); -} - -/// Returns the current exit code. -/// -/// This function queries the value that will be returned when the program exits. -pub fn current_exit_code() -> i32 { - EXIT_CODE.load(Ordering::SeqCst) -} |
