aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-04-25 19:02:17 +0800
committer魏曹先生 <1992414357@qq.com>2026-04-25 19:02:17 +0800
commitd4634b01e3f33b3ee52b1501f5ade739a1796d08 (patch)
tree778b229f78be7ec67367e8135d0dcc6b1fff5158
parent1d9a65ae06faf4a6329eb07e8c1deab3811c782b (diff)
Remove redundant generic parameter from Program struct
-rw-r--r--Cargo.lock4
-rw-r--r--Cargo.toml2
-rw-r--r--mingling_core/src/asset/dispatcher.rs12
-rw-r--r--mingling_core/src/program.rs56
-rw-r--r--mingling_core/src/program/exec.rs41
-rw-r--r--mingling_core/src/program/flag.rs9
-rw-r--r--mingling_core/src/program/setup.rs8
-rw-r--r--mingling_core/src/program/setup/basic.rs7
-rw-r--r--mingling_core/src/program/setup/general_renderer.rs12
-rw-r--r--mingling_macros/src/lib.rs2
-rw-r--r--mingling_macros/src/program_setup.rs8
11 files changed, 69 insertions, 92 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4306a27..1787d82 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -128,6 +128,10 @@ dependencies = [
]
[[package]]
+name = "example-async"
+version = "0.1.0"
+
+[[package]]
name = "hashbrown"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 3b3876d..ff3ca49 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2024"
[workspace]
-members = ["mingling", "mingling_core", "mingling_macros"]
+members = ["examples/example-async","mingling", "mingling_core", "mingling_macros"]
exclude = [
"mingling_cli",
"dev_tools",
diff --git a/mingling_core/src/asset/dispatcher.rs b/mingling_core/src/asset/dispatcher.rs
index 72b31e9..761c399 100644
--- a/mingling_core/src/asset/dispatcher.rs
+++ b/mingling_core/src/asset/dispatcher.rs
@@ -6,16 +6,16 @@ use crate::{ChainProcess, Program, asset::node::Node};
///
/// Note: If you are using [mingling_macros](https://crates.io/crates/mingling_macros),
/// you can use the `dispatcher!("node.subnode", CommandType => Entry)` macro to declare a `Dispatcher`
-pub trait Dispatcher<G> {
+pub trait Dispatcher<C> {
/// Returns a command node for matching user input
fn node(&self) -> Node;
/// Returns a [ChainProcess](./enum.ChainProcess.html) based on user input arguments,
/// to be sent to the specific invocation
- fn begin(&self, args: Vec<String>) -> ChainProcess<G>;
+ fn begin(&self, args: Vec<String>) -> ChainProcess<C>;
/// Clones the current dispatcher for implementing the `Clone` trait
- fn clone_dispatcher(&self) -> Box<dyn Dispatcher<G>>;
+ fn clone_dispatcher(&self) -> Box<dyn Dispatcher<C>>;
}
impl<G> Clone for Box<dyn Dispatcher<G>>
@@ -27,11 +27,11 @@ where
}
}
-impl<C: crate::program::ProgramCollect, G: Display> Program<C, G> {
+impl<C: crate::program::ProgramCollect> Program<C> {
/// Adds a dispatcher to the program.
pub fn with_dispatcher<Disp>(&mut self, dispatcher: Disp)
where
- Disp: Dispatcher<G> + Send + Sync + 'static,
+ Disp: Dispatcher<C> + Send + Sync + 'static,
{
self.dispatcher.push(Box::new(dispatcher));
}
@@ -39,7 +39,7 @@ impl<C: crate::program::ProgramCollect, G: Display> Program<C, G> {
/// Add some dispatchers to the program.
pub fn with_dispatchers<D>(&mut self, dispatchers: D)
where
- D: Into<Dispatchers<G>>,
+ D: Into<Dispatchers<C>>,
{
let dispatchers = dispatchers.into();
self.dispatcher.extend(dispatchers.dispatcher);
diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs
index a671e9b..c9cffbe 100644
--- a/mingling_core/src/program.rs
+++ b/mingling_core/src/program.rs
@@ -35,7 +35,7 @@ pub use string_vec::*;
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>
+pub fn this<C>() -> &'static Program<C>
where
C: ProgramCollect + 'static,
{
@@ -43,27 +43,23 @@ where
}
/// Returns a reference to the current program instance, if set.
-fn try_get_this_program<C>() -> Option<&'static Program<C, C>>
+fn try_get_this_program<C>() -> Option<&'static Program<C>>
where
C: ProgramCollect + 'static,
{
- THIS_PROGRAM
- .get()?
- .as_ref()?
- .downcast_ref::<Program<C, C>>()
+ THIS_PROGRAM.get()?.as_ref()?.downcast_ref::<Program<C>>()
}
/// Program, used to define the behavior of the entire command-line program
#[derive(Default)]
-pub struct Program<C, G>
+pub struct Program<C>
where
C: ProgramCollect,
{
pub(crate) collect: std::marker::PhantomData<C>,
- pub(crate) group: std::marker::PhantomData<G>,
pub(crate) args: Vec<String>,
- pub(crate) dispatcher: Vec<Box<dyn Dispatcher<G> + Send + Sync>>,
+ pub(crate) dispatcher: Vec<Box<dyn Dispatcher<C> + Send + Sync>>,
pub stdout_setting: ProgramStdoutSetting,
pub user_context: ProgramUserContext,
@@ -72,9 +68,9 @@ where
pub general_renderer_name: GeneralRendererSetting,
}
-impl<C, G> Program<C, G>
+impl<C> Program<C>
where
- C: ProgramCollect<Enum = G>,
+ C: ProgramCollect<Enum = C>,
{
/// Creates a new Program instance, initializing command-line arguments from the environment.
pub fn new() -> Self {
@@ -98,7 +94,6 @@ where
pub fn new_with_args(args: impl Into<StringVec>) -> Self {
Program {
collect: std::marker::PhantomData,
- group: std::marker::PhantomData,
args: args.into().into(),
dispatcher: Vec::new(),
stdout_setting: Default::default(),
@@ -110,22 +105,21 @@ where
}
/// Returns a reference to the current program instance, if set.
- pub fn this_program() -> &'static Program<C, G>
+ pub fn this_program() -> &'static Program<C>
where
C: 'static,
- G: 'static,
{
THIS_PROGRAM
.get()
.unwrap()
.as_ref()
.unwrap()
- .downcast_ref::<Program<C, G>>()
+ .downcast_ref::<Program<C>>()
.unwrap()
}
/// Get all registered dispatcher names from the program
- pub fn get_nodes(&self) -> Vec<(String, &(dyn Dispatcher<G> + Send + Sync))> {
+ pub fn get_nodes(&self) -> Vec<(String, &(dyn Dispatcher<C> + Send + Sync))> {
get_nodes(self)
}
@@ -133,7 +127,7 @@ where
pub fn dispatch_args_dynamic(
&self,
args: impl Into<StringVec>,
- ) -> Result<AnyOutput<G>, ChainProcessError> {
+ ) -> Result<AnyOutput<C>, ChainProcessError> {
match exec::dispatch_args_dynamic(self, args.into().into()) {
Ok(ok) => Ok(ok),
Err(e) => Err(e.into()),
@@ -143,16 +137,15 @@ where
// Async program
#[cfg(feature = "async")]
-impl<C, G> Program<C, G>
+impl<C> Program<C>
where
- C: ProgramCollect<Enum = G>,
+ 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
where
C: 'static + Send + Sync,
- G: 'static + Send + Sync,
- F: FnOnce(&'static Program<C, G>) -> Fut + Send + Sync,
+ F: FnOnce(&'static Program<C>) -> Fut + Send + Sync,
Fut: Future + Send,
{
THIS_PROGRAM.get_or_init(|| Some(Box::new(self)));
@@ -161,7 +154,7 @@ where
.unwrap()
.as_ref()
.unwrap()
- .downcast_ref::<Program<C, G>>()
+ .downcast_ref::<Program<C>>()
.unwrap();
f(program).await
}
@@ -170,7 +163,6 @@ where
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();
self.set_instance_and_run(|p| async { crate::exec::exec(p).await.map_err(|e| e.into()) })
@@ -181,7 +173,6 @@ where
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 {
@@ -216,16 +207,15 @@ where
// Sync program
#[cfg(not(feature = "async"))]
-impl<C, G> Program<C, G>
+impl<C> Program<C>
where
- C: ProgramCollect<Enum = G>,
+ 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
where
C: 'static + Send + Sync,
- G: 'static + Send + Sync,
- F: FnOnce(&'static Program<C, G>) -> R + Send + Sync,
+ F: FnOnce(&'static Program<C>) -> R + Send + Sync,
{
THIS_PROGRAM.get_or_init(|| Some(Box::new(self)));
let program = THIS_PROGRAM
@@ -233,7 +223,7 @@ where
.unwrap()
.as_ref()
.unwrap()
- .downcast_ref::<Program<C, G>>()
+ .downcast_ref::<Program<C>>()
.unwrap();
f(program)
}
@@ -242,7 +232,6 @@ where
pub 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();
self.set_instance_and_run(|p| crate::exec::exec(p).map_err(|e| e.into()))
@@ -252,7 +241,6 @@ where
pub 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() {
@@ -403,9 +391,9 @@ macro_rules! __dispatch_program_chains {
}
/// Get all registered dispatcher names from the program
-pub fn get_nodes<C: ProgramCollect<Enum = G>, G>(
- program: &Program<C, G>,
-) -> Vec<(String, &(dyn Dispatcher<G> + Send + Sync))> {
+pub fn get_nodes<C: ProgramCollect<Enum = C>>(
+ program: &Program<C>,
+) -> Vec<(String, &(dyn Dispatcher<C> + Send + Sync))> {
program
.dispatcher
.iter()
diff --git a/mingling_core/src/program/exec.rs b/mingling_core/src/program/exec.rs
index 68a694e..c1eada5 100644
--- a/mingling_core/src/program/exec.rs
+++ b/mingling_core/src/program/exec.rs
@@ -9,11 +9,9 @@ use crate::{
pub mod error;
#[cfg(feature = "async")]
-pub async fn exec<C, G>(
- program: &Program<C, G>,
-) -> Result<RenderResult, ProgramInternalExecuteError>
+pub async fn exec<C>(program: &Program<C>) -> Result<RenderResult, ProgramInternalExecuteError>
where
- C: ProgramCollect<Enum = G>,
+ C: ProgramCollect<Enum = C>,
{
let mut current = dispatch_args_dynamic(program, program.args.clone())?;
let mut stop_next = false;
@@ -26,7 +24,7 @@ where
if C::has_chain(&current) {
match C::do_chain(current).await {
ChainProcess::Ok((any, Next::Renderer)) => {
- return Ok(render::<C, G>(program, any));
+ return Ok(render::<C>(program, any));
}
ChainProcess::Ok((any, Next::Chain)) => any,
ChainProcess::Err(e) => return Err(e.into()),
@@ -34,7 +32,7 @@ where
}
// If no chain exists, attempt to render
else if C::has_renderer(&current) {
- return Ok(render::<C, G>(program, current));
+ return Ok(render::<C>(program, current));
}
// No renderer exists
else {
@@ -51,9 +49,9 @@ where
}
#[cfg(not(feature = "async"))]
-pub fn exec<C, G>(program: &Program<C, G>) -> Result<RenderResult, ProgramInternalExecuteError>
+pub fn exec<C>(program: &Program<C>) -> Result<RenderResult, ProgramInternalExecuteError>
where
- C: ProgramCollect<Enum = G>,
+ C: ProgramCollect<Enum = C>,
{
let mut current = dispatch_args_dynamic(program, program.args.clone())?;
let mut stop_next = false;
@@ -66,7 +64,7 @@ where
if C::has_chain(&current) {
match C::do_chain(current) {
ChainProcess::Ok((any, Next::Renderer)) => {
- return Ok(render::<C, G>(program, any));
+ return Ok(render::<C>(program, any));
}
ChainProcess::Ok((any, Next::Chain)) => any,
ChainProcess::Err(e) => return Err(e.into()),
@@ -74,7 +72,7 @@ where
}
// If no chain exists, attempt to render
else if C::has_renderer(&current) {
- return Ok(render::<C, G>(program, current));
+ return Ok(render::<C>(program, current));
}
// No renderer exists
else {
@@ -91,12 +89,12 @@ where
}
/// Dynamically dispatch input arguments to registered entry types
-pub(crate) fn dispatch_args_dynamic<C, G>(
- program: &Program<C, G>,
+pub(crate) fn dispatch_args_dynamic<C>(
+ program: &Program<C>,
args: Vec<String>,
-) -> Result<AnyOutput<G>, ProgramInternalExecuteError>
+) -> Result<AnyOutput<C>, ProgramInternalExecuteError>
where
- C: ProgramCollect<Enum = G>,
+ C: ProgramCollect<Enum = C>,
{
let next = match match_user_input(program, args) {
Ok((dispatcher, args)) => {
@@ -117,18 +115,18 @@ where
/// Match user input against registered dispatchers and return the matched dispatcher and remaining arguments.
#[allow(clippy::type_complexity)]
-pub(crate) fn match_user_input<C, G>(
- program: &Program<C, G>,
+pub(crate) fn match_user_input<C>(
+ program: &Program<C>,
args: Vec<String>,
-) -> Result<(&(dyn Dispatcher<G> + Send + Sync), Vec<String>), ProgramInternalExecuteError>
+) -> Result<(&(dyn Dispatcher<C> + Send + Sync), Vec<String>), ProgramInternalExecuteError>
where
- C: ProgramCollect<Enum = G>,
+ C: ProgramCollect<Enum = C>,
{
let nodes = program.get_nodes();
let command = format!("{} ", args.join(" "));
// Find all nodes that match the command prefix
- let matching_nodes: Vec<&(String, &(dyn Dispatcher<G> + Send + Sync))> = nodes
+ let matching_nodes: Vec<&(String, &(dyn Dispatcher<C> + 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)))
@@ -162,10 +160,7 @@ where
#[inline(always)]
#[allow(unused_variables)]
-fn render<C: ProgramCollect<Enum = G>, G>(
- program: &Program<C, G>,
- any: AnyOutput<G>,
-) -> RenderResult {
+fn render<C: ProgramCollect<Enum = C>>(program: &Program<C>, any: AnyOutput<C>) -> RenderResult {
#[cfg(not(feature = "general_renderer"))]
{
let mut render_result = RenderResult::default();
diff --git a/mingling_core/src/program/flag.rs b/mingling_core/src/program/flag.rs
index f44cf33..0ab8d1c 100644
--- a/mingling_core/src/program/flag.rs
+++ b/mingling_core/src/program/flag.rs
@@ -1,5 +1,3 @@
-use std::fmt::Display;
-
use crate::{Program, ProgramCollect};
/// A wrapper for a collection of static string slices representing command-line flags or arguments.
@@ -474,15 +472,14 @@ mod tests {
}
}
-impl<C, G> Program<C, G>
+impl<C> Program<C>
where
C: ProgramCollect,
- G: Display,
{
/// Registers a global argument (with value) and its handler.
pub fn global_argument<F, A>(&mut self, arguments: A, mut do_fn: F)
where
- F: FnMut(&mut Program<C, G>, String),
+ F: FnMut(&mut Program<C>, String),
A: Into<Flag>,
{
let flag = arguments.into();
@@ -498,7 +495,7 @@ where
/// Registers a global flag (boolean) and its handler.
pub fn global_flag<F, A>(&mut self, flag: A, mut do_fn: F)
where
- F: FnMut(&mut Program<C, G>),
+ F: FnMut(&mut Program<C>),
A: Into<Flag>,
{
let flag = flag.into();
diff --git a/mingling_core/src/program/setup.rs b/mingling_core/src/program/setup.rs
index f095ed3..86228b9 100644
--- a/mingling_core/src/program/setup.rs
+++ b/mingling_core/src/program/setup.rs
@@ -8,19 +8,19 @@ mod general_renderer;
#[cfg(feature = "general_renderer")]
pub use general_renderer::*;
-pub trait ProgramSetup<C, G>
+pub trait ProgramSetup<C>
where
C: ProgramCollect,
{
- fn setup(&mut self, program: &mut Program<C, G>);
+ fn setup(&mut self, program: &mut Program<C>);
}
-impl<C, G> Program<C, G>
+impl<C> Program<C>
where
C: ProgramCollect,
{
/// Load and execute init logic
- pub fn with_setup<S: ProgramSetup<C, G> + 'static>(&mut self, mut setup: S) -> S {
+ pub fn with_setup<S: ProgramSetup<C> + 'static>(&mut self, mut setup: S) -> S {
S::setup(&mut setup, self);
setup
}
diff --git a/mingling_core/src/program/setup/basic.rs b/mingling_core/src/program/setup/basic.rs
index 8316a33..43c14b9 100644
--- a/mingling_core/src/program/setup/basic.rs
+++ b/mingling_core/src/program/setup/basic.rs
@@ -1,5 +1,3 @@
-use std::fmt::Display;
-
use crate::{
ProgramCollect,
program::{Program, setup::ProgramSetup},
@@ -12,12 +10,11 @@ use crate::{
/// - Collects `--confirm` flag to skip user confirmation
pub struct BasicProgramSetup;
-impl<C, G> ProgramSetup<C, G> for BasicProgramSetup
+impl<C> ProgramSetup<C> for BasicProgramSetup
where
C: ProgramCollect,
- G: Display,
{
- fn setup(&mut self, program: &mut Program<C, G>) {
+ fn setup(&mut self, program: &mut Program<C>) {
program.global_flag(["--quiet", "-q"], |p| {
p.stdout_setting.render_output = false;
p.stdout_setting.error_output = false;
diff --git a/mingling_core/src/program/setup/general_renderer.rs b/mingling_core/src/program/setup/general_renderer.rs
index 035f813..2d2ee79 100644
--- a/mingling_core/src/program/setup/general_renderer.rs
+++ b/mingling_core/src/program/setup/general_renderer.rs
@@ -1,5 +1,3 @@
-use std::fmt::Display;
-
use crate::{
ProgramCollect,
program::{Program, setup::ProgramSetup},
@@ -10,12 +8,11 @@ use crate::{
/// - Adds a `--renderer` global argument to specify the renderer type
pub struct GeneralRendererSimpleSetup;
-impl<C, G> ProgramSetup<C, G> for GeneralRendererSimpleSetup
+impl<C> ProgramSetup<C> for GeneralRendererSimpleSetup
where
C: ProgramCollect,
- G: Display,
{
- fn setup(&mut self, program: &mut Program<C, G>) {
+ fn setup(&mut self, program: &mut Program<C>) {
program.global_argument("--renderer", |p, renderer| {
p.general_renderer_name = renderer.into();
});
@@ -33,12 +30,11 @@ where
/// * `--ron-pretty` for pretty-printed RON output
pub struct GeneralRendererSetup;
-impl<C, G> ProgramSetup<C, G> for GeneralRendererSetup
+impl<C> ProgramSetup<C> for GeneralRendererSetup
where
C: ProgramCollect,
- G: Display,
{
- fn setup(&mut self, program: &mut Program<C, G>) {
+ fn setup(&mut self, program: &mut Program<C>) {
program.global_flag("--json", |p| {
p.general_renderer_name = crate::GeneralRendererSetting::Json
});
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index 5a3b04a..5ee53a1 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -349,7 +349,7 @@ pub fn program_final_gen(input: TokenStream) -> TokenStream {
}
impl #name {
- pub fn new() -> ::mingling::Program<#name, #name> {
+ pub fn new() -> ::mingling::Program<#name> {
::mingling::Program::new()
}
}
diff --git a/mingling_macros/src/program_setup.rs b/mingling_macros/src/program_setup.rs
index cdfbf92..f68ea40 100644
--- a/mingling_macros/src/program_setup.rs
+++ b/mingling_macros/src/program_setup.rs
@@ -111,8 +111,8 @@ pub fn setup_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
#[doc(hidden)]
#vis struct #struct_name;
- impl ::mingling::setup::ProgramSetup<ThisProgram, ThisProgram> for #struct_name {
- fn setup(&mut self, program: &mut ::mingling::Program<ThisProgram, ThisProgram>) {
+ impl ::mingling::setup::ProgramSetup<ThisProgram> for #struct_name {
+ fn setup(&mut self, program: &mut ::mingling::Program<ThisProgram>) {
// Call the original function with the actual Program type
#fn_name(program);
}
@@ -129,8 +129,8 @@ pub fn setup_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
#(#fn_attrs)*
#vis struct #struct_name;
- impl ::mingling::setup::ProgramSetup<#program_name, #program_name> for #struct_name {
- fn setup(&mut self, program: &mut ::mingling::Program<#program_name, #program_name>) {
+ impl ::mingling::setup::ProgramSetup<#program_name> for #struct_name {
+ fn setup(&mut self, program: &mut ::mingling::Program<#program_name>) {
// Call the original function with the actual Program type
#fn_name(program);
}