summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-04-08 22:48:31 +0800
committer魏曹先生 <1992414357@qq.com>2026-04-08 22:53:52 +0800
commit240361b240d638363346013160b0943b47769c37 (patch)
treedbe2316a670faf961fffe3c6764eff440e5230a2
parent6e2d660e310a44d441266ae32a5800db52d48049 (diff)
Implement mingling::this functionmain
-rw-r--r--Cargo.lock1
-rw-r--r--mingling_core/Cargo.toml2
-rw-r--r--mingling_core/src/asset/dispatcher.rs72
-rw-r--r--mingling_core/src/program.rs75
-rw-r--r--mingling_core/src/program/exec.rs10
5 files changed, 115 insertions, 45 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 41acf1d..caa3def 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -173,6 +173,7 @@ name = "mingling_core"
version = "0.1.4"
dependencies = [
"just_fmt",
+ "once_cell",
"ron",
"serde",
"serde_json",
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<C: crate::program::ProgramCollect, G: Display> Program<C, G> {
/// Adds a dispatcher to the program.
pub fn with_dispatcher<Disp>(&mut self, dispatcher: Disp)
where
- Disp: Dispatcher<G> + 'static,
+ Disp: Dispatcher<G> + Send + Sync + 'static,
{
self.dispatcher.push(Box::new(dispatcher));
}
@@ -60,17 +60,17 @@ impl<C: crate::program::ProgramCollect, G: Display> Program<C, G> {
/// allowing multiple dispatchers to be grouped together and passed
/// to the program via `Program::with_dispatchers`.
pub struct Dispatchers<G> {
- dispatcher: Vec<Box<dyn Dispatcher<G> + 'static>>,
+ dispatcher: Vec<Box<dyn Dispatcher<G> + Send + Sync + 'static>>,
}
-impl<G> From<Vec<Box<dyn Dispatcher<G>>>> for Dispatchers<G> {
- fn from(dispatcher: Vec<Box<dyn Dispatcher<G>>>) -> Self {
+impl<G> From<Vec<Box<dyn Dispatcher<G> + Send + Sync>>> for Dispatchers<G> {
+ fn from(dispatcher: Vec<Box<dyn Dispatcher<G> + Send + Sync>>) -> Self {
Self { dispatcher }
}
}
-impl<G> From<Box<dyn Dispatcher<G>>> for Dispatchers<G> {
- fn from(dispatcher: Box<dyn Dispatcher<G>>) -> Self {
+impl<G> From<Box<dyn Dispatcher<G> + Send + Sync>> for Dispatchers<G> {
+ fn from(dispatcher: Box<dyn Dispatcher<G> + Send + Sync>) -> Self {
Self {
dispatcher: vec![dispatcher],
}
@@ -79,7 +79,7 @@ impl<G> From<Box<dyn Dispatcher<G>>> for Dispatchers<G> {
impl<D, G> From<(D,)> for Dispatchers<G>
where
- D: Dispatcher<G> + 'static,
+ D: Dispatcher<G> + Send + Sync + 'static,
G: Display,
{
fn from(dispatcher: (D,)) -> Self {
@@ -91,8 +91,8 @@ where
impl<D1, D2, G> From<(D1, D2)> for Dispatchers<G>
where
- D1: Dispatcher<G> + 'static,
- D2: Dispatcher<G> + 'static,
+ D1: Dispatcher<G> + Send + Sync + 'static,
+ D2: Dispatcher<G> + Send + Sync + 'static,
G: Display,
{
fn from(dispatchers: (D1, D2)) -> Self {
@@ -104,9 +104,9 @@ where
impl<D1, D2, D3, G> From<(D1, D2, D3)> for Dispatchers<G>
where
- D1: Dispatcher<G> + 'static,
- D2: Dispatcher<G> + 'static,
- D3: Dispatcher<G> + 'static,
+ D1: Dispatcher<G> + Send + Sync + 'static,
+ D2: Dispatcher<G> + Send + Sync + 'static,
+ D3: Dispatcher<G> + Send + Sync + 'static,
G: Display,
{
fn from(dispatchers: (D1, D2, D3)) -> Self {
@@ -122,10 +122,10 @@ where
impl<D1, D2, D3, D4, G> From<(D1, D2, D3, D4)> for Dispatchers<G>
where
- D1: Dispatcher<G> + 'static,
- D2: Dispatcher<G> + 'static,
- D3: Dispatcher<G> + 'static,
- D4: Dispatcher<G> + 'static,
+ D1: Dispatcher<G> + Send + Sync + 'static,
+ D2: Dispatcher<G> + Send + Sync + 'static,
+ D3: Dispatcher<G> + Send + Sync + 'static,
+ D4: Dispatcher<G> + Send + Sync + 'static,
G: Display,
{
fn from(dispatchers: (D1, D2, D3, D4)) -> Self {
@@ -142,11 +142,11 @@ where
impl<D1, D2, D3, D4, D5, G> From<(D1, D2, D3, D4, D5)> for Dispatchers<G>
where
- D1: Dispatcher<G> + 'static,
- D2: Dispatcher<G> + 'static,
- D3: Dispatcher<G> + 'static,
- D4: Dispatcher<G> + 'static,
- D5: Dispatcher<G> + 'static,
+ D1: Dispatcher<G> + Send + Sync + 'static,
+ D2: Dispatcher<G> + Send + Sync + 'static,
+ D3: Dispatcher<G> + Send + Sync + 'static,
+ D4: Dispatcher<G> + Send + Sync + 'static,
+ D5: Dispatcher<G> + Send + Sync + 'static,
G: Display,
{
fn from(dispatchers: (D1, D2, D3, D4, D5)) -> Self {
@@ -164,12 +164,12 @@ where
impl<D1, D2, D3, D4, D5, D6, G> From<(D1, D2, D3, D4, D5, D6)> for Dispatchers<G>
where
- D1: Dispatcher<G> + 'static,
- D2: Dispatcher<G> + 'static,
- D3: Dispatcher<G> + 'static,
- D4: Dispatcher<G> + 'static,
- D5: Dispatcher<G> + 'static,
- D6: Dispatcher<G> + 'static,
+ D1: Dispatcher<G> + Send + Sync + 'static,
+ D2: Dispatcher<G> + Send + Sync + 'static,
+ D3: Dispatcher<G> + Send + Sync + 'static,
+ D4: Dispatcher<G> + Send + Sync + 'static,
+ D5: Dispatcher<G> + Send + Sync + 'static,
+ D6: Dispatcher<G> + Send + Sync + 'static,
G: Display,
{
fn from(dispatchers: (D1, D2, D3, D4, D5, D6)) -> Self {
@@ -188,13 +188,13 @@ where
impl<D1, D2, D3, D4, D5, D6, D7, G> From<(D1, D2, D3, D4, D5, D6, D7)> for Dispatchers<G>
where
- D1: Dispatcher<G> + 'static,
- D2: Dispatcher<G> + 'static,
- D3: Dispatcher<G> + 'static,
- D4: Dispatcher<G> + 'static,
- D5: Dispatcher<G> + 'static,
- D6: Dispatcher<G> + 'static,
- D7: Dispatcher<G> + 'static,
+ D1: Dispatcher<G> + Send + Sync + 'static,
+ D2: Dispatcher<G> + Send + Sync + 'static,
+ D3: Dispatcher<G> + Send + Sync + 'static,
+ D4: Dispatcher<G> + Send + Sync + 'static,
+ D5: Dispatcher<G> + Send + Sync + 'static,
+ D6: Dispatcher<G> + Send + Sync + 'static,
+ D7: Dispatcher<G> + Send + Sync + 'static,
G: Display,
{
fn from(dispatchers: (D1, D2, D3, D4, D5, D6, D7)) -> Self {
@@ -213,14 +213,14 @@ where
}
impl<G> std::ops::Deref for Dispatchers<G> {
- type Target = Vec<Box<dyn Dispatcher<G> + 'static>>;
+ type Target = Vec<Box<dyn Dispatcher<G> + Send + Sync + 'static>>;
fn deref(&self) -> &Self::Target {
&self.dispatcher
}
}
-impl<G> From<Dispatchers<G>> for Vec<Box<dyn Dispatcher<G> + 'static>> {
+impl<G> From<Dispatchers<G>> for Vec<Box<dyn Dispatcher<G> + Send + Sync + 'static>> {
fn from(val: Dispatchers<G>) -> 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<Option<Box<dyn std::any::Any + Send + Sync>>> = OnceLock::new();
+
+/// Returns a reference to the current program instance, panics if not set.
+pub fn this<C>() -> &'static Program<C, C>
+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<C>() -> Option<&'static Program<C, C>>
+where
+ C: ProgramCollect + Display + 'static,
+{
+ THIS_PROGRAM
+ .get()?
+ .as_ref()?
+ .downcast_ref::<Program<C, C>>()
+}
+
/// Program, used to define the behavior of the entire command-line program
#[derive(Default)]
pub struct Program<C, G>
@@ -29,7 +51,7 @@ where
pub(crate) group: std::marker::PhantomData<G>,
pub(crate) args: Vec<String>,
- pub(crate) dispatcher: Vec<Box<dyn Dispatcher<G>>>,
+ pub(crate) dispatcher: Vec<Box<dyn Dispatcher<G> + 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<C, G>
+ where
+ C: 'static,
+ G: 'static,
+ {
+ THIS_PROGRAM
+ .get()
+ .unwrap()
+ .as_ref()
+ .unwrap()
+ .downcast_ref::<Program<C, G>>()
+ .unwrap()
+ }
+
+ /// Sets the current program instance and runs the provided async function.
+ async fn set_instance_and_run<F, Fut>(self, f: F) -> Fut::Output
+ where
+ C: 'static + Send + Sync,
+ G: 'static + Send + Sync,
+ F: FnOnce(&'static Program<C, G>) -> 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::<Program<C, G>>()
+ .unwrap();
+ f(program).await
+ }
+
/// Run the command line program
- pub async fn exec_without_render(mut self) -> Result<RenderResult, ProgramExecuteError> {
+ pub async fn exec_without_render(mut self) -> Result<RenderResult, ProgramExecuteError>
+ 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<C, G>(program: Program<C, G>) -> Result<RenderResult, ProgramInternalExecuteError>
+pub async fn exec<C, G>(
+ program: &Program<C, G>,
+) -> Result<RenderResult, ProgramInternalExecuteError>
where
C: ProgramCollect<Enum = G>,
G: Display,
@@ -73,7 +75,7 @@ where
#[allow(clippy::type_complexity)]
fn match_user_input<C, G>(
program: &Program<C, G>,
-) -> Result<(&Box<dyn Dispatcher<G>>, Vec<String>), ProgramInternalExecuteError>
+) -> Result<(&Box<dyn Dispatcher<G> + Send + Sync>, Vec<String>), ProgramInternalExecuteError>
where
C: ProgramCollect<Enum = G>,
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<dyn Dispatcher<G>>)> = nodes
+ let matching_nodes: Vec<&(String, &Box<dyn Dispatcher<G> + 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<C: ProgramCollect<Enum = G>, G: Display>(
// Get all registered dispatcher names from the program
fn get_nodes<C: ProgramCollect<Enum = G>, G: Display>(
program: &Program<C, G>,
-) -> Vec<(String, &Box<dyn Dispatcher<G>>)> {
+) -> Vec<(String, &Box<dyn Dispatcher<G> + Send + Sync>)> {
program
.dispatcher
.iter()