From 240361b240d638363346013160b0943b47769c37 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Wed, 8 Apr 2026 22:48:31 +0800 Subject: Implement mingling::this function --- mingling_core/Cargo.toml | 2 + mingling_core/src/asset/dispatcher.rs | 72 ++++++++++++++++----------------- mingling_core/src/program.rs | 75 ++++++++++++++++++++++++++++++++--- mingling_core/src/program/exec.rs | 10 +++-- 4 files changed, 114 insertions(+), 45 deletions(-) (limited to 'mingling_core') diff --git a/mingling_core/Cargo.toml b/mingling_core/Cargo.toml index d8e7c8e..e978401 100644 --- a/mingling_core/Cargo.toml +++ b/mingling_core/Cargo.toml @@ -23,6 +23,8 @@ serde = { version = "1.0", features = ["derive"], optional = true } thiserror = "2" tokio = { version = "1", features = ["io-std", "io-util"] } +once_cell = "1.21.4" + ron = { version = "0.12.1", optional = true } serde_json = { version = "1", optional = true } serde_yaml = { version = "0.9", optional = true } diff --git a/mingling_core/src/asset/dispatcher.rs b/mingling_core/src/asset/dispatcher.rs index 86dfe7c..0f4675c 100644 --- a/mingling_core/src/asset/dispatcher.rs +++ b/mingling_core/src/asset/dispatcher.rs @@ -34,7 +34,7 @@ impl Program { /// Adds a dispatcher to the program. pub fn with_dispatcher(&mut self, dispatcher: Disp) where - Disp: Dispatcher + 'static, + Disp: Dispatcher + Send + Sync + 'static, { self.dispatcher.push(Box::new(dispatcher)); } @@ -60,17 +60,17 @@ impl Program { /// allowing multiple dispatchers to be grouped together and passed /// to the program via `Program::with_dispatchers`. pub struct Dispatchers { - dispatcher: Vec + 'static>>, + dispatcher: Vec + Send + Sync + 'static>>, } -impl From>>> for Dispatchers { - fn from(dispatcher: Vec>>) -> Self { +impl From + Send + Sync>>> for Dispatchers { + fn from(dispatcher: Vec + Send + Sync>>) -> Self { Self { dispatcher } } } -impl From>> for Dispatchers { - fn from(dispatcher: Box>) -> Self { +impl From + Send + Sync>> for Dispatchers { + fn from(dispatcher: Box + Send + Sync>) -> Self { Self { dispatcher: vec![dispatcher], } @@ -79,7 +79,7 @@ impl From>> for Dispatchers { impl From<(D,)> for Dispatchers where - D: Dispatcher + 'static, + D: Dispatcher + Send + Sync + 'static, G: Display, { fn from(dispatcher: (D,)) -> Self { @@ -91,8 +91,8 @@ where impl From<(D1, D2)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, + D1: Dispatcher + Send + Sync + 'static, + D2: Dispatcher + Send + Sync + 'static, G: Display, { fn from(dispatchers: (D1, D2)) -> Self { @@ -104,9 +104,9 @@ where impl From<(D1, D2, D3)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, + D1: Dispatcher + Send + Sync + 'static, + D2: Dispatcher + Send + Sync + 'static, + D3: Dispatcher + Send + Sync + 'static, G: Display, { fn from(dispatchers: (D1, D2, D3)) -> Self { @@ -122,10 +122,10 @@ where impl From<(D1, D2, D3, D4)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, + D1: Dispatcher + Send + Sync + 'static, + D2: Dispatcher + Send + Sync + 'static, + D3: Dispatcher + Send + Sync + 'static, + D4: Dispatcher + Send + Sync + 'static, G: Display, { fn from(dispatchers: (D1, D2, D3, D4)) -> Self { @@ -142,11 +142,11 @@ where impl From<(D1, D2, D3, D4, D5)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, - D5: Dispatcher + 'static, + D1: Dispatcher + Send + Sync + 'static, + D2: Dispatcher + Send + Sync + 'static, + D3: Dispatcher + Send + Sync + 'static, + D4: Dispatcher + Send + Sync + 'static, + D5: Dispatcher + Send + Sync + 'static, G: Display, { fn from(dispatchers: (D1, D2, D3, D4, D5)) -> Self { @@ -164,12 +164,12 @@ where impl From<(D1, D2, D3, D4, D5, D6)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, - D5: Dispatcher + 'static, - D6: Dispatcher + 'static, + D1: Dispatcher + Send + Sync + 'static, + D2: Dispatcher + Send + Sync + 'static, + D3: Dispatcher + Send + Sync + 'static, + D4: Dispatcher + Send + Sync + 'static, + D5: Dispatcher + Send + Sync + 'static, + D6: Dispatcher + Send + Sync + 'static, G: Display, { fn from(dispatchers: (D1, D2, D3, D4, D5, D6)) -> Self { @@ -188,13 +188,13 @@ where impl From<(D1, D2, D3, D4, D5, D6, D7)> for Dispatchers where - D1: Dispatcher + 'static, - D2: Dispatcher + 'static, - D3: Dispatcher + 'static, - D4: Dispatcher + 'static, - D5: Dispatcher + 'static, - D6: Dispatcher + 'static, - D7: Dispatcher + 'static, + D1: Dispatcher + Send + Sync + 'static, + D2: Dispatcher + Send + Sync + 'static, + D3: Dispatcher + Send + Sync + 'static, + D4: Dispatcher + Send + Sync + 'static, + D5: Dispatcher + Send + Sync + 'static, + D6: Dispatcher + Send + Sync + 'static, + D7: Dispatcher + Send + Sync + 'static, G: Display, { fn from(dispatchers: (D1, D2, D3, D4, D5, D6, D7)) -> Self { @@ -213,14 +213,14 @@ where } impl std::ops::Deref for Dispatchers { - type Target = Vec + 'static>>; + type Target = Vec + Send + Sync + 'static>>; fn deref(&self) -> &Self::Target { &self.dispatcher } } -impl From> for Vec + 'static>> { +impl From> for Vec + Send + Sync + 'static>> { fn from(val: Dispatchers) -> Self { val.dispatcher } diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs index 0a24001..8c8b4cb 100644 --- a/mingling_core/src/program.rs +++ b/mingling_core/src/program.rs @@ -4,7 +4,7 @@ use crate::{ AnyOutput, ChainProcess, RenderResult, asset::dispatcher::Dispatcher, error::ProgramExecuteError, }; -use std::{env, fmt::Display, pin::Pin}; +use std::{env, fmt::Display, pin::Pin, sync::OnceLock}; #[doc(hidden)] pub mod exec; @@ -18,6 +18,28 @@ mod flag; pub use flag::*; use tokio::io::AsyncWriteExt; +/// Global static reference to the current program instance +static THIS_PROGRAM: OnceLock>> = OnceLock::new(); + +/// Returns a reference to the current program instance, panics if not set. +pub fn this() -> &'static Program +where + C: ProgramCollect + Display + 'static, +{ + try_get_this_program().expect("Program not initialized") +} + +/// Returns a reference to the current program instance, if set. +fn try_get_this_program() -> Option<&'static Program> +where + C: ProgramCollect + Display + 'static, +{ + THIS_PROGRAM + .get()? + .as_ref()? + .downcast_ref::>() +} + /// Program, used to define the behavior of the entire command-line program #[derive(Default)] pub struct Program @@ -29,7 +51,7 @@ where pub(crate) group: std::marker::PhantomData, pub(crate) args: Vec, - pub(crate) dispatcher: Vec>>, + pub(crate) dispatcher: Vec + Send + Sync>>, pub stdout_setting: ProgramStdoutSetting, pub user_context: ProgramUserContext, @@ -58,14 +80,57 @@ where } } + /// Returns a reference to the current program instance, if set. + pub async fn this_program() -> &'static Program + where + C: 'static, + G: 'static, + { + THIS_PROGRAM + .get() + .unwrap() + .as_ref() + .unwrap() + .downcast_ref::>() + .unwrap() + } + + /// Sets the current program instance and runs the provided async function. + async fn set_instance_and_run(self, f: F) -> Fut::Output + where + C: 'static + Send + Sync, + G: 'static + Send + Sync, + F: FnOnce(&'static Program) -> Fut + Send + Sync, + Fut: Future + Send, + { + THIS_PROGRAM.get_or_init(|| Some(Box::new(self))); + let program = THIS_PROGRAM + .get() + .unwrap() + .as_ref() + .unwrap() + .downcast_ref::>() + .unwrap(); + f(program).await + } + /// Run the command line program - pub async fn exec_without_render(mut self) -> Result { + pub async fn exec_without_render(mut self) -> Result + where + C: 'static + Send + Sync, + G: 'static + Send + Sync, + { self.args = self.args.iter().skip(1).cloned().collect(); - crate::exec::exec(self).await.map_err(|e| e.into()) + self.set_instance_and_run(|p| async { crate::exec::exec(p).await.map_err(|e| e.into()) }) + .await } /// Run the command line program - pub async fn exec(self) { + pub async fn exec(self) + where + C: 'static + Send + Sync, + G: 'static + Send + Sync, + { let stdout_setting = self.stdout_setting.clone(); let result = match self.exec_without_render().await { Ok(r) => r, diff --git a/mingling_core/src/program/exec.rs b/mingling_core/src/program/exec.rs index 1a4f6ff..f578064 100644 --- a/mingling_core/src/program/exec.rs +++ b/mingling_core/src/program/exec.rs @@ -10,7 +10,9 @@ use crate::{ #[doc(hidden)] pub mod error; -pub async fn exec(program: Program) -> Result +pub async fn exec( + program: &Program, +) -> Result where C: ProgramCollect, G: Display, @@ -73,7 +75,7 @@ where #[allow(clippy::type_complexity)] fn match_user_input( program: &Program, -) -> Result<(&Box>, Vec), ProgramInternalExecuteError> +) -> Result<(&Box + Send + Sync>, Vec), ProgramInternalExecuteError> where C: ProgramCollect, G: Display, @@ -82,7 +84,7 @@ where let command = format!("{} ", program.args.join(" ")); // Find all nodes that match the command prefix - let matching_nodes: Vec<&(String, &Box>)> = nodes + let matching_nodes: Vec<&(String, &Box + Send + Sync>)> = nodes .iter() // Also add a space to the node string to ensure consistent matching logic .filter(|(node_str, _)| command.starts_with(&format!("{} ", node_str))) @@ -142,7 +144,7 @@ fn render, G: Display>( // Get all registered dispatcher names from the program fn get_nodes, G: Display>( program: &Program, -) -> Vec<(String, &Box>)> { +) -> Vec<(String, &Box + Send + Sync>)> { program .dispatcher .iter() -- cgit