aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-06-20 01:54:57 +0800
committer魏曹先生 <1992414357@qq.com>2026-06-20 01:54:57 +0800
commitfcfe66875f46e8652170fd190416d796ae30aabc (patch)
tree2af968ac8cabcb06337e36c35133313781cd1071 /mingling_macros
parent78330940bd0fcab6ffbb8b930a1ae88d313a9437 (diff)
Remove all explicit program name modes from macrosremoved-shit
Diffstat (limited to 'mingling_macros')
-rw-r--r--mingling_macros/src/chain.rs45
-rw-r--r--mingling_macros/src/dispatcher.rs190
-rw-r--r--mingling_macros/src/dispatcher_clap.rs121
-rw-r--r--mingling_macros/src/group_impl.rs48
-rw-r--r--mingling_macros/src/groupped.rs24
-rw-r--r--mingling_macros/src/lib.rs124
-rw-r--r--mingling_macros/src/pack.rs144
-rw-r--r--mingling_macros/src/program_setup.rs57
-rw-r--r--mingling_macros/src/renderer.rs14
9 files changed, 176 insertions, 591 deletions
diff --git a/mingling_macros/src/chain.rs b/mingling_macros/src/chain.rs
index b0ea8ae..fb5999a 100644
--- a/mingling_macros/src/chain.rs
+++ b/mingling_macros/src/chain.rs
@@ -9,20 +9,6 @@ use quote::{ToTokens, quote};
use syn::spanned::Spanned;
use syn::{Ident, ItemFn, Pat, ReturnType, Signature, Type, TypePath, parse_macro_input};
-/// Parses the `#[chain(...)]` attribute arguments.
-///
-/// Returns:
-/// - `program_path`: the token stream representing the program type
-/// - `use_crate_prefix`: whether to use the default crate-defined program path
-fn parse_chain_attr_args(attr: TokenStream) -> (proc_macro2::TokenStream, bool) {
- if attr.is_empty() {
- (crate::default_program_path(), true)
- } else {
- let path: syn::Path = syn::parse(attr).expect("#[chain(..)] argument must be a path");
- (quote! { #path }, false)
- }
-}
-
/// Validates that the return type of the function is `Next`.
/// Checks whether the return type is `()` (unit).
fn is_unit_return_type(sig: &Signature) -> bool {
@@ -226,18 +212,10 @@ fn generate_struct_and_impl(
struct_name: &Ident,
previous_type: &TypePath,
previous_type_str: &proc_macro2::TokenStream,
- group_name: &proc_macro2::TokenStream,
program_type: &proc_macro2::TokenStream,
- use_crate_prefix: bool,
proc_fn: &proc_macro2::TokenStream,
origin_proc_fn: &proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
- let chain_type = if use_crate_prefix {
- program_type
- } else {
- group_name
- };
-
quote! {
#(#fn_attrs)*
#[doc(hidden)]
@@ -246,7 +224,7 @@ fn generate_struct_and_impl(
::mingling::macros::register_chain!(#previous_type_str, #struct_name);
- impl ::mingling::Chain<#chain_type> for #struct_name {
+ impl ::mingling::Chain<#program_type> for #struct_name {
type Previous = #previous_type;
#proc_fn
@@ -284,8 +262,15 @@ fn reject_mut_in_async(resources: &[ResourceInjection]) -> Result<(), proc_macro
}
pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
- // Parse attribute arguments
- let (group_name, use_crate_prefix) = parse_chain_attr_args(attr);
+ // Reject non-empty attribute arguments; #[chain] must be bare
+ if !attr.is_empty() {
+ return syn::Error::new(
+ attr.into_iter().next().unwrap().span().into(),
+ "#[chain] does not accept arguments",
+ )
+ .to_compile_error()
+ .into();
+ }
// Parse the function item
let input_fn = parse_macro_input!(item as ItemFn);
@@ -340,12 +325,8 @@ pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
);
let struct_name = Ident::new(&internal_name, fn_name.span());
- // Determine the program type for the return type
- let program_type = if use_crate_prefix {
- crate::default_program_path()
- } else {
- group_name.clone()
- };
+ // Always use the default crate-defined program path
+ let program_type = crate::default_program_path();
// Generate the `proc` function
let proc_fn = generate_proc_fn(
@@ -386,9 +367,7 @@ pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
&struct_name,
&previous_type,
&previous_type_str,
- &group_name,
&program_type,
- use_crate_prefix,
&proc_fn,
&origin_proc_fn,
);
diff --git a/mingling_macros/src/dispatcher.rs b/mingling_macros/src/dispatcher.rs
index 6bf10f1..51dce95 100644
--- a/mingling_macros/src/dispatcher.rs
+++ b/mingling_macros/src/dispatcher.rs
@@ -8,14 +8,6 @@ use syn::{Attribute, Ident, LitStr, Result as SynResult, Token};
use crate::COMPILE_TIME_DISPATCHERS;
enum DispatcherChainInput {
- Explicit {
- cmd_attrs: Vec<Attribute>,
- entry_attrs: Vec<Attribute>,
- group_name: syn::Path,
- command_name: syn::LitStr,
- command_struct: Ident,
- pack: Ident,
- },
Default {
cmd_attrs: Vec<Attribute>,
entry_attrs: Vec<Attribute>,
@@ -35,27 +27,7 @@ impl Parse for DispatcherChainInput {
// Collect outer attributes for the CMD struct
let cmd_attrs = input.call(Attribute::parse_outer)?;
- if (input.peek(Ident) || input.peek(Token![crate]))
- && (input.peek2(Token![::]) || input.peek2(Token![,]))
- {
- let group_name = input.parse::<syn::Path>()?;
- input.parse::<Token![,]>()?;
- let command_name = input.parse()?;
- input.parse::<Token![,]>()?;
- let command_struct = input.parse()?;
- input.parse::<Token![=>]>()?;
- let entry_attrs = input.call(Attribute::parse_outer)?;
- let pack = input.parse()?;
-
- Ok(DispatcherChainInput::Explicit {
- cmd_attrs,
- entry_attrs,
- group_name,
- command_name,
- command_struct,
- pack,
- })
- } else if input.peek(syn::LitStr) {
+ if input.peek(syn::LitStr) {
// Parse the command name string first
let command_name: LitStr = input.parse()?;
@@ -97,12 +69,8 @@ impl Parse for DispatcherChainInput {
}
}
-// NOTICE: This implementation contains significant code duplication between the explicit
-// and default cases in both `dispatcher_chain` and `dispatcher_render` functions.
-// The logic for handling default vs explicit group names and generating the appropriate
-// code should be extracted into common helper functions to reduce redundancy.
-// Additionally, the token stream generation patterns are nearly identical between
-// the two main functions and could benefit from refactoring.
+// NOTICE: The token stream generation patterns in `dispatcher_chain` and `dispatcher_render`
+// are nearly identical and could benefit from refactoring into common helper functions.
#[allow(clippy::too_many_lines)]
pub fn dispatcher(input: TokenStream) -> TokenStream {
@@ -110,94 +78,36 @@ pub fn dispatcher(input: TokenStream) -> TokenStream {
let dispatcher_input = syn::parse_macro_input!(input as DispatcherChainInput);
#[cfg(not(feature = "extra_macros"))]
- let (command_name, command_struct, pack, cmd_attrs, entry_attrs, _use_default, group_path) =
- match dispatcher_input {
- DispatcherChainInput::Explicit {
- cmd_attrs,
- entry_attrs,
- group_name,
- command_name,
- command_struct,
- pack,
- } => (
- command_name,
- command_struct,
- pack,
- cmd_attrs,
- entry_attrs,
- false,
- quote! { #group_name },
- ),
- DispatcherChainInput::Default {
- cmd_attrs,
- entry_attrs,
- command_name,
- command_struct,
- pack,
- } => (
- command_name,
- command_struct,
- pack,
- cmd_attrs,
- entry_attrs,
- true,
- crate::default_program_path(),
- ),
- };
+ let (command_name, command_struct, pack, cmd_attrs, entry_attrs) = match dispatcher_input {
+ DispatcherChainInput::Default {
+ cmd_attrs,
+ entry_attrs,
+ command_name,
+ command_struct,
+ pack,
+ } => (command_name, command_struct, pack, cmd_attrs, entry_attrs),
+ };
#[cfg(feature = "extra_macros")]
- let (command_name, command_struct, pack, cmd_attrs, entry_attrs, _use_default, group_path) =
- match dispatcher_input {
- DispatcherChainInput::Explicit {
- cmd_attrs,
- entry_attrs,
- group_name,
- command_name,
- command_struct,
- pack,
- } => (
- command_name,
- command_struct,
- pack,
- cmd_attrs,
- entry_attrs,
- false,
- quote! { #group_name },
- ),
- DispatcherChainInput::Default {
- cmd_attrs,
- entry_attrs,
- command_name,
- command_struct,
- pack,
- } => (
- command_name,
- command_struct,
- pack,
- cmd_attrs,
- entry_attrs,
- true,
- crate::default_program_path(),
- ),
- DispatcherChainInput::Auto {
- cmd_attrs,
- command_name,
- } => {
- let command_name_str = command_name.value();
- let pascal = dotted_to_pascal_case(&command_name_str);
- let command_struct = Ident::new(&format!("CMD{pascal}"), command_name.span());
- let pack = Ident::new(&format!("Entry{pascal}"), command_name.span());
- (
- command_name,
- command_struct,
- pack,
- cmd_attrs,
- Vec::new(),
- true,
- crate::default_program_path(),
- )
- }
- };
+ let (command_name, command_struct, pack, cmd_attrs, entry_attrs) = match dispatcher_input {
+ DispatcherChainInput::Default {
+ cmd_attrs,
+ entry_attrs,
+ command_name,
+ command_struct,
+ pack,
+ } => (command_name, command_struct, pack, cmd_attrs, entry_attrs),
+ DispatcherChainInput::Auto {
+ cmd_attrs,
+ command_name,
+ } => {
+ let command_name_str = command_name.value();
+ let pascal = dotted_to_pascal_case(&command_name_str);
+ let command_struct = Ident::new(&format!("CMD{pascal}"), command_name.span());
+ let pack = Ident::new(&format!("Entry{pascal}"), command_name.span());
+ (command_name, command_struct, pack, cmd_attrs, Vec::new())
+ }
+ };
let command_name_str = command_name.value();
@@ -205,30 +115,28 @@ pub fn dispatcher(input: TokenStream) -> TokenStream {
let dispatch_tree_entry = get_dispatch_tree_entry(&command_name_str, &command_struct, &pack);
- let expanded = {
- let program_path = group_path;
+ let program_type = crate::default_program_path();
- quote! {
- #(#cmd_attrs)*
- #[derive(Debug, Default)]
- pub struct #command_struct;
+ let expanded = quote! {
+ #(#cmd_attrs)*
+ #[derive(Debug, Default)]
+ pub struct #command_struct;
- ::mingling::macros::pack!(#(#entry_attrs)* #program_path, #pack = Vec<String>);
+ ::mingling::macros::pack!(#(#entry_attrs)* #pack = Vec<String>);
- #comp_entry
- #dispatch_tree_entry
+ #comp_entry
+ #dispatch_tree_entry
- impl ::mingling::Dispatcher<#program_path> for #command_struct {
- fn node(&self) -> ::mingling::Node {
- ::mingling::macros::node!(#command_name_str)
- }
- fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess<#program_path> {
- use ::mingling::Groupped;
- #pack::new(args).to_chain()
- }
- fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher<#program_path>> {
- Box::new(#command_struct)
- }
+ impl ::mingling::Dispatcher<#program_type> for #command_struct {
+ fn node(&self) -> ::mingling::Node {
+ ::mingling::macros::node!(#command_name_str)
+ }
+ fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess<#program_type> {
+ use ::mingling::Groupped;
+ #pack::new(args).to_chain()
+ }
+ fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher<#program_type>> {
+ Box::new(#command_struct)
}
}
};
diff --git a/mingling_macros/src/dispatcher_clap.rs b/mingling_macros/src/dispatcher_clap.rs
index 34d146c..1c9db4b 100644
--- a/mingling_macros/src/dispatcher_clap.rs
+++ b/mingling_macros/src/dispatcher_clap.rs
@@ -61,74 +61,34 @@ impl Parse for ClapOptions {
}
/// Input for the dispatcher_clap attribute
-enum DispatcherClapInput {
+struct DispatcherClapInput {
/// `("cmd", Disp, ...)`
- Default {
- command_name: LitStr,
- dispatcher_struct: Ident,
- options: ClapOptions,
- },
- /// `(Program, "cmd", Disp, ...)`
- Explicit {
- group_name: syn::Path,
- command_name: LitStr,
- dispatcher_struct: Ident,
- options: ClapOptions,
- },
+ command_name: LitStr,
+ dispatcher_struct: Ident,
+ options: ClapOptions,
}
impl Parse for DispatcherClapInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
- let lookahead = input.lookahead1();
+ // Format: "cmd", Disp, ...
+ let command_name: LitStr = input.parse()?;
+ input.parse::<Token![,]>()?;
+ let dispatcher_struct: Ident = input.parse()?;
- if (input.peek(Ident) || input.peek(Token![crate]))
- && (input.peek2(Token![::]) || input.peek2(Token![,]))
- {
- // Explicit format: Program, "cmd", Disp, ...
- let group_name: syn::Path = input.parse()?;
- input.parse::<Token![,]>()?;
- let command_name: LitStr = input.parse()?;
- input.parse::<Token![,]>()?;
- let dispatcher_struct: Ident = input.parse()?;
-
- let options = if input.is_empty() {
- ClapOptions {
- error_struct: None,
- help_enabled: false,
- }
- } else {
- input.parse::<ClapOptions>()?
- };
-
- Ok(DispatcherClapInput::Explicit {
- group_name,
- command_name,
- dispatcher_struct,
- options,
- })
- } else if lookahead.peek(syn::LitStr) {
- // Default format: "cmd", Disp, ...
- let command_name: LitStr = input.parse()?;
- input.parse::<Token![,]>()?;
- let dispatcher_struct: Ident = input.parse()?;
-
- let options = if input.is_empty() {
- ClapOptions {
- error_struct: None,
- help_enabled: false,
- }
- } else {
- input.parse::<ClapOptions>()?
- };
-
- Ok(DispatcherClapInput::Default {
- command_name,
- dispatcher_struct,
- options,
- })
+ let options = if input.is_empty() {
+ ClapOptions {
+ error_struct: None,
+ help_enabled: false,
+ }
} else {
- Err(lookahead.error())
- }
+ input.parse::<ClapOptions>()?
+ };
+
+ Ok(DispatcherClapInput {
+ command_name,
+ dispatcher_struct,
+ options,
+ })
}
}
@@ -138,36 +98,11 @@ pub fn dispatcher_clap_attr(attr: TokenStream, item: TokenStream) -> TokenStream
let input_struct = parse_macro_input!(item as ItemStruct);
let struct_name = &input_struct.ident;
- // Determine the program name and other fields
- let (command_name_str, dispatcher_struct, options, program_path) = match &attr_input {
- DispatcherClapInput::Default {
- command_name,
- dispatcher_struct,
- options,
- } => (
- command_name.value(),
- dispatcher_struct.clone(),
- ClapOptions {
- error_struct: options.error_struct.clone(),
- help_enabled: options.help_enabled,
- },
- crate::default_program_path(),
- ),
- DispatcherClapInput::Explicit {
- group_name,
- command_name,
- dispatcher_struct,
- options,
- } => (
- command_name.value(),
- dispatcher_struct.clone(),
- ClapOptions {
- error_struct: options.error_struct.clone(),
- help_enabled: options.help_enabled,
- },
- quote! { #group_name },
- ),
- };
+ let program_path = crate::default_program_path();
+
+ let command_name_str = attr_input.command_name.value();
+ let dispatcher_struct = &attr_input.dispatcher_struct;
+ let options = &attr_input.options;
// Generate the `begin` method body
let begin_body = if let Some(ref error_struct) = options.error_struct {
@@ -196,7 +131,7 @@ pub fn dispatcher_clap_attr(attr: TokenStream, item: TokenStream) -> TokenStream
// Generate the error pack type
let error_pack = options.error_struct.as_ref().map(|error_struct| {
quote! {
- ::mingling::macros::pack!(#program_path, #error_struct = String);
+ ::mingling::macros::pack!(#error_struct = String);
}
});
@@ -233,7 +168,7 @@ pub fn dispatcher_clap_attr(attr: TokenStream, item: TokenStream) -> TokenStream
};
let dispatch_tree_entry =
- get_dispatch_tree_entry(&command_name_str, &dispatcher_struct, &struct_name);
+ get_dispatch_tree_entry(&command_name_str, dispatcher_struct, &struct_name);
let expanded = quote! {
// Keep the original struct definition
diff --git a/mingling_macros/src/group_impl.rs b/mingling_macros/src/group_impl.rs
index 499fd1c..a7bc84f 100644
--- a/mingling_macros/src/group_impl.rs
+++ b/mingling_macros/src/group_impl.rs
@@ -1,52 +1,25 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
-use syn::{Ident, Path, Result as SynResult, Token, TypePath};
+use syn::{Ident, Result as SynResult, TypePath};
/// Input for the `group!` macro
///
/// # Syntax
///
/// ```rust,ignore
-/// // Explicit mode: specify both program path and type path
-/// group!(crate::ThisProgram, std::io::Error);
-///
-/// // Implicit mode: only type path, uses default `crate::ThisProgram` as program
+/// /// Only a type path — uses default `crate::ThisProgram` as program
/// group!(std::io::Error);
/// group!(ParseIntError);
/// ```
-enum GroupInput {
- Explicit {
- program_path: Path,
- type_path: TypePath,
- },
- Implicit {
- type_path: TypePath,
- },
+struct GroupInput {
+ type_path: TypePath,
}
impl Parse for GroupInput {
fn parse(input: ParseStream) -> SynResult<Self> {
- // Parse the first path (could be program path or type path)
- let first_path: Path = input.parse()?;
-
- // If followed by a comma, it's explicit mode: Path, TypePath
- if input.peek(Token![,]) {
- input.parse::<Token![,]>()?;
- let type_path: TypePath = input.parse()?;
- Ok(GroupInput::Explicit {
- program_path: first_path,
- type_path,
- })
- } else {
- // Otherwise it's implicit mode: just a type path
- Ok(GroupInput::Implicit {
- type_path: TypePath {
- qself: None,
- path: first_path,
- },
- })
- }
+ let type_path: TypePath = input.parse()?;
+ Ok(GroupInput { type_path })
}
}
@@ -96,14 +69,9 @@ fn gen_type_use(type_path: &TypePath) -> proc_macro2::TokenStream {
pub fn group_macro(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as GroupInput);
+ let type_path = input.type_path;
- let (program_path, type_path) = match input {
- GroupInput::Explicit {
- program_path,
- type_path,
- } => (quote! { #program_path }, type_path),
- GroupInput::Implicit { type_path } => (crate::default_program_path(), type_path),
- };
+ let program_path = crate::default_program_path();
// Use the type's simple name as the enum variant identifier
let type_name = type_simple_name(&type_path);
diff --git a/mingling_macros/src/groupped.rs b/mingling_macros/src/groupped.rs
index 03f0b9c..1459522 100644
--- a/mingling_macros/src/groupped.rs
+++ b/mingling_macros/src/groupped.rs
@@ -1,29 +1,13 @@
use proc_macro::TokenStream;
use quote::quote;
-use syn::{Attribute, DeriveInput, Ident, parse_macro_input};
-
-/// Parses the `#[group(...)]` attribute to extract the group type
-fn parse_group_attribute(attrs: &[Attribute]) -> Option<Ident> {
- for attr in attrs {
- if attr.path().is_ident("group")
- && let Ok(meta) = attr.parse_args::<syn::Meta>()
- && let syn::Meta::Path(path) = meta
- && let Some(segment) = path.segments.last()
- {
- return Some(segment.ident.clone());
- }
- }
- None
-}
+use syn::{DeriveInput, Ident, parse_macro_input};
pub fn derive_groupped(input: TokenStream) -> TokenStream {
// Parse the input struct/enum
let input = parse_macro_input!(input as DeriveInput);
let struct_name = input.ident;
- // Parse attributes to find #[group(...)]
- let group_ident: proc_macro2::TokenStream = parse_group_attribute(&input.attrs)
- .map_or_else(crate::default_program_path, |ident| quote! { #ident });
+ let group_ident: proc_macro2::TokenStream = crate::default_program_path();
let any_output_convert_impls =
proc_macro2::TokenStream::from(build_any_output_convert_impls(&struct_name, &group_ident));
@@ -50,9 +34,7 @@ pub fn derive_groupped_serialize(input: TokenStream) -> TokenStream {
let input_parsed = parse_macro_input!(input as DeriveInput);
let struct_name = input_parsed.ident.clone();
- // Parse attributes to find #[group(...)]
- let group_ident: proc_macro2::TokenStream = parse_group_attribute(&input_parsed.attrs)
- .map_or_else(crate::default_program_path, |ident| quote! { #ident });
+ let group_ident: proc_macro2::TokenStream = crate::default_program_path();
let any_output_convert_impls =
proc_macro2::TokenStream::from(build_any_output_convert_impls(&struct_name, &group_ident));
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index bb296ef..e774335 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -135,7 +135,6 @@
//! ```
use proc_macro::TokenStream;
-use proc_macro2::Ident;
use quote::quote;
use std::collections::BTreeSet;
use std::sync::Mutex;
@@ -169,13 +168,6 @@ mod res_injection;
#[cfg(feature = "comp")]
mod suggest;
-pub(crate) const DEFAULT_PROGRAM_NAME: &str = "ThisProgram";
-
-#[allow(dead_code)]
-pub(crate) fn default_program_ident() -> Ident {
- Ident::new(DEFAULT_PROGRAM_NAME, proc_macro2::Span::call_site())
-}
-
pub(crate) fn default_program_path() -> proc_macro2::TokenStream {
quote::quote! { crate::ThisProgram }
}
@@ -240,16 +232,13 @@ pub(crate) fn check_single_segment_type(
///
/// # Syntax
///
-/// Two forms are supported:
-///
/// ```rust,ignore
-/// // Explicit mode — specify both program path and outside-type:
-/// group!(crate::ThisProgram, std::io::Error);
-///
-/// // Implicit mode — uses default `crate::ThisProgram` as the program:
/// group!(std::io::Error);
+/// group!(ParseIntError);
/// ```
///
+/// The type is registered under the default program (`crate::ThisProgram`).
+///
/// # How it works
///
/// The macro generates a module containing:
@@ -267,9 +256,6 @@ pub(crate) fn check_single_segment_type(
///
/// // Register std::io::Error as a group member
/// group!(std::io::Error);
-///
-/// // With explicit program path:
-/// group!(crate::MyProgram, serde_json::Error);
/// ```
///
/// After expansion, the type can be used in chains and renderers like any
@@ -722,18 +708,11 @@ pub fn r_println(input: TokenStream) -> TokenStream {
/// # Syntax
///
/// ```rust,ignore
-/// // Default program (ThisProgram):
/// #[chain]
/// fn my_step(prev: InputType) -> Next {
/// // transform `prev`...
/// OutputType::new(result)
/// }
-///
-/// // Explicit program name:
-/// #[chain(MyProgram)]
-/// fn my_step(prev: InputType) -> Next {
-/// // ...
-/// }
/// ```
///
/// # Resource Injection
@@ -891,7 +870,6 @@ pub fn chain(attr: TokenStream, item: TokenStream) -> TokenStream {
/// # Syntax
///
/// ```rust,ignore
-/// // Default program (ThisProgram):
/// #[renderer]
/// fn render_my_type(prev: MyType) {
/// r_println!("Output: {:?}", *prev);
@@ -1004,17 +982,10 @@ pub fn completion(attr: TokenStream, item: TokenStream) -> TokenStream {
/// # Syntax
///
/// ```rust,ignore
-/// // Default program (ThisProgram):
/// #[program_setup]
/// fn setup_my_program(program: &mut Program<ThisProgram>) {
/// program.stdout_setting.render_output = false;
/// }
-///
-/// // Explicit program name:
-/// #[program_setup(MyProgram)]
-/// fn setup_my_program(program: &mut Program<MyProgram>) {
-/// // ...
-/// }
/// ```
///
/// # Example
@@ -1063,11 +1034,6 @@ pub fn program_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
/// #[derive(clap::Parser)]
/// #[dispatcher_clap("cmd", Disp, error = ParseError, help = true)]
/// struct CmdEntry { /* ... */ }
-///
-/// // With explicit program name:
-/// #[derive(clap::Parser)]
-/// #[dispatcher_clap(MyProgram, "cmd", Disp)]
-/// struct CmdEntry { /* ... */ }
/// ```
///
/// # Example
@@ -1257,7 +1223,7 @@ pub fn help(_attr: TokenStream, item: TokenStream) -> TokenStream {
/// Derive macro for automatically implementing the `Groupped` trait on a struct.
///
/// The `#[derive(Groupped)]` macro:
-/// 1. Implements `Groupped<Group>` where the group is specified via `#[group(GroupName)]`.
+/// 1. Implements `Groupped<crate::ThisProgram>`.
/// 2. Registers the type via `register_type!` so it's included in the program enum.
/// 3. Generates `Into<AnyOutput<Group>>` and `Into<ChainProcess<Group>>` conversions.
/// 4. Adds `to_chain()` and `to_render()` methods to the struct.
@@ -1266,19 +1232,17 @@ pub fn help(_attr: TokenStream, item: TokenStream) -> TokenStream {
///
/// ```rust,ignore
/// #[derive(Groupped)]
-/// #[group(MyProgram)] // optional; defaults to `ThisProgram`
/// struct MyStruct {
-/// field: String,
+/// // ...
/// }
/// ```
///
/// # Example
///
/// ```rust,ignore
-/// use mingling::{Groupped, macros::{chain, gen_program, renderer, r_println}};
+/// use mingling::macros::Groupped;
///
/// #[derive(Groupped)]
-/// #[group(ThisProgram)]
/// struct Greeting {
/// name: String,
/// }
@@ -1345,7 +1309,6 @@ pub fn derive_enum_tag(input: TokenStream) -> TokenStream {
///
/// ```rust,ignore
/// #[derive(GrouppedSerialize)]
-/// #[group(MyProgram)]
/// struct Info {
/// name: String,
/// age: i32,
@@ -1379,11 +1342,7 @@ pub fn derive_groupped_serialize(input: TokenStream) -> TokenStream {
/// # Syntax
///
/// ```rust,ignore
-/// // Default program name (uses `ThisProgram`):
/// gen_program!();
-///
-/// // Explicit program name:
-/// gen_program!(MyProgram);
/// ```
///
/// # What it generates
@@ -1420,26 +1379,21 @@ pub fn derive_groupped_serialize(input: TokenStream) -> TokenStream {
/// gen_program!();
/// ```
#[proc_macro]
-pub fn gen_program(input: TokenStream) -> TokenStream {
- let name = read_name(&input);
-
+pub fn gen_program(_input: TokenStream) -> TokenStream {
#[cfg(feature = "comp")]
let comp_gen = quote! {
- ::mingling::macros::program_comp_gen!(#name);
+ ::mingling::macros::program_comp_gen!();
};
#[cfg(not(feature = "comp"))]
let comp_gen = quote! {};
TokenStream::from(quote! {
- // Shit, this feature is unstable
- // TODO :: This logic will be implemented when Rust's Impl In Type Alias feature becomes stable
- // pub type Next = impl Into<::mingling::ChainProcess<#name>>;
- pub type Next = ::mingling::ChainProcess<#name>;
+ pub type Next = ::mingling::ChainProcess<crate::ThisProgram>;
#comp_gen
- ::mingling::macros::program_fallback_gen!(#name);
- ::mingling::macros::program_final_gen!(#name);
+ ::mingling::macros::program_fallback_gen!();
+ ::mingling::macros::program_final_gen!();
})
}
@@ -1457,20 +1411,18 @@ pub fn gen_program(input: TokenStream) -> TokenStream {
/// - A `__render_completion` renderer that outputs completion suggestions
#[proc_macro]
#[cfg(feature = "comp")]
-pub fn program_comp_gen(input: TokenStream) -> TokenStream {
- let name = read_name(&input);
-
+pub fn program_comp_gen(_input: TokenStream) -> TokenStream {
#[cfg(feature = "async")]
let fn_exec_comp = quote! {
#[doc(hidden)]
- #[::mingling::macros::chain(#name)]
+ #[::mingling::macros::chain]
pub async fn __exec_completion(prev: CompletionContext) -> Next {
use ::mingling::Groupped;
let read_ctx = ::mingling::ShellContext::try_from(prev.inner);
match read_ctx {
Ok(ctx) => {
- let suggest = ::mingling::CompletionHelper::exec_completion::<#name>(&ctx);
+ let suggest = ::mingling::CompletionHelper::exec_completion::<crate::ThisProgram>(&ctx);
crate::CompletionSuggest::new((ctx, suggest)).to_render()
}
Err(_) => std::process::exit(1),
@@ -1481,14 +1433,14 @@ pub fn program_comp_gen(input: TokenStream) -> TokenStream {
#[cfg(not(feature = "async"))]
let fn_exec_comp = quote! {
#[doc(hidden)]
- #[::mingling::macros::chain(#name)]
+ #[::mingling::macros::chain]
pub fn __exec_completion(prev: CompletionContext) -> Next {
use ::mingling::Groupped;
let read_ctx = ::mingling::ShellContext::try_from(prev.inner);
match read_ctx {
Ok(ctx) => {
- let suggest = ::mingling::CompletionHelper::exec_completion::<#name>(&ctx);
+ let suggest = ::mingling::CompletionHelper::exec_completion::<crate::ThisProgram>(&ctx);
crate::CompletionSuggest::new((ctx, suggest)).to_render()
}
Err(_) => std::process::exit(1),
@@ -1507,11 +1459,9 @@ pub fn program_comp_gen(input: TokenStream) -> TokenStream {
let comp_dispatcher = quote! {
#[doc(hidden)]
mod __internal_completion_mod {
- use super::#name;
use ::mingling::Groupped;
- ::mingling::macros::dispatcher!(#name, "__comp", CMDCompletion => CompletionContext);
+ ::mingling::macros::dispatcher!("__comp", CMDCompletion => CompletionContext);
::mingling::macros::pack!(
- #name,
CompletionSuggest = (::mingling::ShellContext, ::mingling::Suggest)
);
}
@@ -1526,10 +1476,10 @@ pub fn program_comp_gen(input: TokenStream) -> TokenStream {
#[allow(unused)]
#[doc(hidden)]
- #[::mingling::macros::renderer(#name)]
+ #[::mingling::macros::renderer]
pub fn __render_completion(prev: CompletionSuggest) {
let (ctx, suggest) = prev.inner;
- ::mingling::CompletionHelper::render_suggest::<#name>(ctx, suggest);
+ ::mingling::CompletionHelper::render_suggest::<crate::ThisProgram>(ctx, suggest);
}
};
@@ -1630,25 +1580,22 @@ pub fn register_renderer(input: TokenStream) -> TokenStream {
///
/// ```rust,ignore
/// // Called internally by gen_program!:
-/// program_fallback_gen!(ThisProgram);
-/// program_fallback_gen!(MyProgram);
+/// program_fallback_gen!();
/// ```
///
/// # Generated code equivalent
///
/// ```rust,ignore
-/// pack!(ProgramName, ErrorRendererNotFound = String);
-/// pack!(ProgramName, ErrorDispatcherNotFound = Vec<String>);
-/// pack!(ProgramName, ResultEmpty = ());
+/// pack!(ErrorRendererNotFound = String);
+/// pack!(ErrorDispatcherNotFound = Vec<String>);
+/// pack!(ResultEmpty = ());
/// ```
#[proc_macro]
-pub fn program_fallback_gen(input: TokenStream) -> TokenStream {
- let name = read_name(&input);
-
+pub fn program_fallback_gen(_input: TokenStream) -> TokenStream {
let expanded = quote! {
- ::mingling::macros::pack!(#name, ErrorRendererNotFound = String);
- ::mingling::macros::pack!(#name, ErrorDispatcherNotFound = Vec<String>);
- ::mingling::macros::pack!(#name, ResultEmpty = ());
+ ::mingling::macros::pack!(ErrorRendererNotFound = String);
+ ::mingling::macros::pack!(ErrorDispatcherNotFound = Vec<String>);
+ ::mingling::macros::pack!(ResultEmpty = ());
};
TokenStream::from(expanded)
}
@@ -1673,15 +1620,14 @@ pub fn program_fallback_gen(input: TokenStream) -> TokenStream {
/// # Syntax
///
/// ```rust,ignore
-/// program_final_gen!(ThisProgram);
-/// program_final_gen!(MyProgram);
+/// program_final_gen!();
/// ```
///
/// # Generated code structure
///
/// ```rust,ignore
/// #[repr(u8)]
-/// pub enum MyProgram {
+/// pub enum ThisProgram {
/// TypeA,
/// TypeB,
/// // ...
@@ -1710,8 +1656,8 @@ pub fn program_fallback_gen(input: TokenStream) -> TokenStream {
/// are poisoned.
#[proc_macro]
#[allow(clippy::too_many_lines)]
-pub fn program_final_gen(input: TokenStream) -> TokenStream {
- let name = read_name(&input);
+pub fn program_final_gen(_input: TokenStream) -> TokenStream {
+ let name = syn::Ident::new("ThisProgram", proc_macro2::Span::call_site());
let packed_types = get_global_set(&PACKED_TYPES).lock().unwrap().clone();
@@ -2045,11 +1991,3 @@ pub fn suggest(input: TokenStream) -> TokenStream {
pub fn suggest_enum(input: TokenStream) -> TokenStream {
suggest::suggest_enum(input)
}
-
-fn read_name(input: &TokenStream) -> Ident {
- if input.is_empty() {
- Ident::new(DEFAULT_PROGRAM_NAME, proc_macro2::Span::call_site())
- } else {
- syn::parse(input.clone()).unwrap()
- }
-}
diff --git a/mingling_macros/src/pack.rs b/mingling_macros/src/pack.rs
index bf2536d..ffb07f2 100644
--- a/mingling_macros/src/pack.rs
+++ b/mingling_macros/src/pack.rs
@@ -3,86 +3,35 @@ use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{Attribute, Ident, Result as SynResult, Token, Type};
-enum PackInput {
- Explicit {
- attrs: Vec<Attribute>,
- group_name: syn::Path,
- type_name: Ident,
- inner_type: Type,
- },
- Default {
- attrs: Vec<Attribute>,
- type_name: Ident,
- inner_type: Type,
- },
+struct PackInput {
+ attrs: Vec<Attribute>,
+ type_name: Ident,
+ inner_type: Type,
}
impl Parse for PackInput {
fn parse(input: ParseStream) -> SynResult<Self> {
- // First, collect any outer attributes (`#[...]` and `///...`) before the main syntax.
let attrs = input.call(Attribute::parse_outer)?;
+ let type_name: Ident = input.parse()?;
+ input.parse::<Token![=]>()?;
+ let inner_type: Type = input.parse()?;
- // Now determine the format:
- // - `Path, TypeName = InnerType` → Explicit
- // - `TypeName = InnerType` → Default
-
- if (input.peek(Ident) || input.peek(Token![crate]))
- && (input.peek2(Token![,]) || input.peek2(Token![::]))
- {
- // Explicit format: Path, TypeName = InnerType
- let group_name = input.parse::<syn::Path>()?;
- input.parse::<Token![,]>()?;
- let type_name = input.parse()?;
- input.parse::<Token![=]>()?;
- let inner_type = input.parse()?;
-
- Ok(PackInput::Explicit {
- attrs,
- group_name,
- type_name,
- inner_type,
- })
- } else if input.peek(Ident) && input.peek2(Token![=]) {
- // Default format: TypeName = InnerType
- let type_name = input.parse()?;
- input.parse::<Token![=]>()?;
- let inner_type = input.parse()?;
-
- Ok(PackInput::Default {
- attrs,
- type_name,
- inner_type,
- })
- } else {
- Err(input.lookahead1().error())
- }
+ Ok(PackInput {
+ attrs,
+ type_name,
+ inner_type,
+ })
}
}
#[allow(clippy::too_many_lines)]
pub fn pack(input: TokenStream) -> TokenStream {
- // Parse the input
let pack_input = syn::parse_macro_input!(input as PackInput);
- let (group_name, type_name, inner_type, attrs, use_default) = match pack_input {
- PackInput::Explicit {
- attrs,
- group_name,
- type_name,
- inner_type,
- } => (quote! { #group_name }, type_name, inner_type, attrs, false),
- PackInput::Default {
- attrs,
- type_name,
- inner_type,
- } => (
- crate::default_program_path(),
- type_name,
- inner_type,
- attrs,
- true,
- ),
- };
+ let group_name = crate::default_program_path();
+ let type_name = pack_input.type_name;
+ let inner_type = pack_input.inner_type;
+ let attrs = pack_input.attrs;
// Generate the struct definition
#[cfg(not(feature = "general_renderer"))]
@@ -175,7 +124,16 @@ pub fn pack(input: TokenStream) -> TokenStream {
::mingling::macros::register_type!(#type_name);
};
- let any_out_impl = quote! {
+ let expanded = quote! {
+ #struct_def
+
+ #new_impl
+ #from_into_impl
+ #as_ref_impl
+ #deref_impl
+ #default_impl
+ #register_impl
+
impl Into<mingling::AnyOutput<#group_name>> for #type_name {
fn into(self) -> mingling::AnyOutput<#group_name> {
mingling::AnyOutput::new(self)
@@ -187,9 +145,7 @@ pub fn pack(input: TokenStream) -> TokenStream {
mingling::AnyOutput::new(self).route_chain()
}
}
- };
- let group_impl = quote! {
impl ::mingling::Groupped<#group_name> for #type_name {
fn member_id() -> #group_name {
#group_name::#type_name
@@ -197,53 +153,5 @@ pub fn pack(input: TokenStream) -> TokenStream {
}
};
- // Combine all implementations
- let expanded = if use_default {
- // For default case, use ThisProgram
- quote! {
- #struct_def
-
- #new_impl
- #from_into_impl
- #as_ref_impl
- #deref_impl
- #default_impl
- #register_impl
-
- impl Into<mingling::AnyOutput<#group_name>> for #type_name {
- fn into(self) -> mingling::AnyOutput<#group_name> {
- mingling::AnyOutput::new(self)
- }
- }
-
- impl From<#type_name> for mingling::ChainProcess<#group_name> {
- fn from(value: #type_name) -> Self {
- mingling::AnyOutput::new(value).route_chain()
- }
- }
-
- impl ::mingling::Groupped<#group_name> for #type_name {
- fn member_id() -> #group_name {
- #group_name::#type_name
- }
- }
- }
- } else {
- // For explicit case, use the provided group_name
- quote! {
- #struct_def
-
- #new_impl
- #from_into_impl
- #as_ref_impl
- #deref_impl
- #default_impl
- #register_impl
-
- #any_out_impl
- #group_impl
- }
- };
-
expanded.into()
}
diff --git a/mingling_macros/src/program_setup.rs b/mingling_macros/src/program_setup.rs
index d8f9507..7fd9d16 100644
--- a/mingling_macros/src/program_setup.rs
+++ b/mingling_macros/src/program_setup.rs
@@ -48,14 +48,9 @@ fn extract_return_type(sig: &Signature) -> syn::Result<()> {
}
pub fn setup_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
- // Parse the attribute arguments (e.g., MyProgram from #[program_setup(MyProgram)])
- // If no argument is provided, use ThisProgram
- let (program_name, use_crate_prefix) = if attr.is_empty() {
- (crate::default_program_path(), true)
- } else {
- let path: syn::Path = parse_macro_input!(attr as syn::Path);
- (quote! { #path }, false)
- };
+ // #[program_setup] takes no arguments; always use the default program path
+ let _ = attr;
+ let program_path = crate::default_program_path();
// Parse the function item
let input_fn = parse_macro_input!(item as ItemFn);
@@ -98,42 +93,22 @@ pub fn setup_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
let struct_name = Ident::new(&pascal_case_name, fn_name.span());
// Generate the struct and implementation
- let expanded = if use_crate_prefix {
- quote! {
- #(#fn_attrs)*
- #[doc(hidden)]
- #vis struct #struct_name;
-
- impl ::mingling::setup::ProgramSetup<#program_name> for #struct_name {
- fn setup(self, program: &mut ::mingling::Program<#program_name>) {
- // Call the original function with the actual Program type
- #fn_name(program);
- }
- }
-
- // Keep the original function for internal use
- #(#fn_attrs)*
- #vis fn #fn_name(#program_param: #program_type) {
- #fn_body
+ let expanded = quote! {
+ #(#fn_attrs)*
+ #[doc(hidden)]
+ #vis struct #struct_name;
+
+ impl ::mingling::setup::ProgramSetup<#program_path> for #struct_name {
+ fn setup(self, program: &mut ::mingling::Program<#program_path>) {
+ // Call the original function with the actual Program type
+ #fn_name(program);
}
}
- } else {
- quote! {
- #(#fn_attrs)*
- #vis struct #struct_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);
- }
- }
- // Keep the original function for internal use
- #(#fn_attrs)*
- #vis fn #fn_name(#program_param: #program_type) {
- #fn_body
- }
+ // Keep the original function for internal use
+ #(#fn_attrs)*
+ #vis fn #fn_name(#program_param: #program_type) {
+ #fn_body
}
};
diff --git a/mingling_macros/src/renderer.rs b/mingling_macros/src/renderer.rs
index 4cf9fc1..ac82799 100644
--- a/mingling_macros/src/renderer.rs
+++ b/mingling_macros/src/renderer.rs
@@ -23,8 +23,9 @@ fn extract_return_type(sig: &Signature) -> Option<syn::Type> {
#[allow(clippy::too_many_lines)]
pub fn renderer_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
- // Parse attribute arguments for program path (e.g. #[renderer(my_crate::Program)])
- let (program_path, _use_crate_prefix) = parse_renderer_attr_args(attr);
+ // #[renderer] takes no arguments; always use the default program path
+ let _ = attr;
+ let program_path = crate::default_program_path();
let program_type = &program_path;
// Parse the function item
@@ -167,15 +168,6 @@ pub fn renderer_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
expanded.into()
}
-fn parse_renderer_attr_args(attr: TokenStream) -> (proc_macro2::TokenStream, bool) {
- if attr.is_empty() {
- (crate::default_program_path(), true)
- } else {
- let path: syn::Path =
- syn::parse(attr).expect("Expected a path argument for #[renderer(path)]");
- (quote! { #path }, false)
- }
-}
/// Builds the renderer entry for the global renderers list
pub fn build_renderer_entry(