aboutsummaryrefslogtreecommitdiff
path: root/mingling_core/src/program/hook.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-05-09 16:42:50 +0800
committer魏曹先生 <1992414357@qq.com>2026-05-09 17:13:35 +0800
commit10bc4ca7a4b3f14cfb57bf72a6da8aaa1490acf3 (patch)
tree8b985dad38cfcd4c88af962b3e163131b258a381 /mingling_core/src/program/hook.rs
parent89b5132b8c17b6eba45b1bd49aa18b0c02016387 (diff)
Add lifecycle hooks to program execution
Diffstat (limited to 'mingling_core/src/program/hook.rs')
-rw-r--r--mingling_core/src/program/hook.rs349
1 files changed, 349 insertions, 0 deletions
diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs
new file mode 100644
index 0000000..d422e12
--- /dev/null
+++ b/mingling_core/src/program/hook.rs
@@ -0,0 +1,349 @@
+use std::{any::Any, fmt::Display};
+
+use crate::{AnyOutput, Program, ProgramCollect, RenderResult};
+
+#[derive(Default)]
+pub struct ProgramHook<C>
+where
+ C: ProgramCollect<Enum = C>,
+{
+ /// 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: &C)>,
+
+ /// Executes before the type enters the chain
+ pub pre_chain: Option<fn(input: &C, raw: &dyn Any)>,
+
+ /// Executes after the chain processing for the type ends
+ pub post_chain: Option<fn(output: &AnyOutput<C>)>,
+
+ /// Executes before the type enters the renderer
+ pub pre_render: Option<fn(input: &C, 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>,
+}
+
+#[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()>,
+}
+
+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>) {
+ self.hooks.push(hook);
+ }
+
+ /// 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);
+ }
+
+ pub(crate) fn run_hook_on_begin(&self) {
+ if !self.user_context.run_hook {
+ return;
+ }
+
+ for hook in &self.hooks {
+ if let Some(begin) = hook.begin {
+ 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>) {
+ if !self.user_context.run_hook {
+ return;
+ }
+
+ for hook in &self.hooks {
+ if let Some(pre_dispatch) = hook.pre_dispatch {
+ 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) {
+ if !self.user_context.run_hook {
+ return;
+ }
+
+ for hook in &self.hooks {
+ if let Some(post_dispatch) = hook.post_dispatch {
+ 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) {
+ if !self.user_context.run_hook {
+ return;
+ }
+
+ for hook in &self.hooks {
+ if let Some(pre_chain) = hook.pre_chain {
+ 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>) {
+ if !self.user_context.run_hook {
+ return;
+ }
+
+ for hook in &self.hooks {
+ if let Some(post_chain) = hook.post_chain {
+ 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) {
+ if !self.user_context.run_hook {
+ return;
+ }
+
+ for hook in &self.hooks {
+ if let Some(pre_render) = hook.pre_render {
+ 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) {
+ if !self.user_context.run_hook {
+ return;
+ }
+
+ for hook in &self.hooks {
+ if let Some(post_render) = hook.post_render {
+ 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 {
+ if !self.user_context.run_hook {
+ return 0;
+ }
+
+ let mut exit_code = 0;
+ for hook in &self.hooks {
+ if let Some(finish) = hook.finish {
+ exit_code = finish();
+ if exit_code != 0 {
+ return exit_code;
+ }
+ }
+ }
+ for anonymous_hook in &self.anonymous_hooks {
+ if let Some(finish) = anonymous_hook.finish {
+ finish();
+ }
+ }
+ exit_code
+ }
+}
+
+impl<C> ProgramHook<C>
+where
+ C: ProgramCollect<Enum = C>,
+{
+ /// 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: &C)) -> 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: &C, 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: &AnyOutput<C>)) -> 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: &C, 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
+ }
+}
+
+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()) -> Self {
+ let _ = self.finish.insert(handler);
+ self
+ }
+}