diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-17 05:49:19 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-17 05:49:19 +0800 |
| commit | 57c53affe3542cb6bd4e79ee4c18f20a1bd76b2d (patch) | |
| tree | 1cd4aef44cb7a45a8cd9d520b598f5f181e24c76 /mingling_macros/src | |
| parent | ef23cd944402939605c78a4a853ef6e33af02c21 (diff) | |
refactor!: replace pack! macros with derive-based pipeline types
Remove the `pack!`, `pack_err!`, `pack_structural!`, and
`pack_err_structural!` macros, replacing all pipeline type definitions
with `#[derive(Grouped)]` and `#[derive(Grouped, Wrap)]` attributes.
This changes the generated struct shape from named-field structs with an
`inner` field to tuple structs accessed via `.0`, and removes the
auto-generated `name` and `info` fields from error types.
Diffstat (limited to 'mingling_macros/src')
| -rw-r--r-- | mingling_macros/src/attr/dispatcher_clap.rs | 7 | ||||
| -rw-r--r-- | mingling_macros/src/func.rs | 7 | ||||
| -rw-r--r-- | mingling_macros/src/func/dispatcher.rs | 10 | ||||
| -rw-r--r-- | mingling_macros/src/func/entry.rs | 2 | ||||
| -rw-r--r-- | mingling_macros/src/func/gen_program.rs | 3 | ||||
| -rw-r--r-- | mingling_macros/src/func/pack.rs | 154 | ||||
| -rw-r--r-- | mingling_macros/src/func/pack_err.rs | 108 | ||||
| -rw-r--r-- | mingling_macros/src/func/pack_err_structural.rs | 121 | ||||
| -rw-r--r-- | mingling_macros/src/func/pack_structural.rs | 170 | ||||
| -rw-r--r-- | mingling_macros/src/func/program_comp_gen.rs | 15 | ||||
| -rw-r--r-- | mingling_macros/src/func/program_fallback_gen.rs | 8 | ||||
| -rw-r--r-- | mingling_macros/src/func/program_final_gen.rs | 4 | ||||
| -rw-r--r-- | mingling_macros/src/lib.rs | 238 | ||||
| -rw-r--r-- | mingling_macros/src/systems.rs | 5 | ||||
| -rw-r--r-- | mingling_macros/src/systems/structural_data.rs | 7 |
15 files changed, 76 insertions, 783 deletions
diff --git a/mingling_macros/src/attr/dispatcher_clap.rs b/mingling_macros/src/attr/dispatcher_clap.rs index 46238d6..c2dd952 100644 --- a/mingling_macros/src/attr/dispatcher_clap.rs +++ b/mingling_macros/src/attr/dispatcher_clap.rs @@ -133,7 +133,7 @@ pub(crate) fn dispatcher_clap_attr(attr: TokenStream, item: TokenStream) -> Toke match <#struct_name as ::clap::Parser>::try_parse_from(clap_args) { Ok(parsed) => ::mingling::Routable::<#program_path>::to_chain(parsed), Err(e) => { - return ::mingling::Routable::<#program_path>::to_render(#error_struct::new(format!("{}", e.render().ansi()))) + return ::mingling::Routable::<#program_path>::to_render(#error_struct(format!("{}", e.render().ansi()))) }, } } @@ -143,7 +143,8 @@ pub(crate) fn dispatcher_clap_attr(attr: TokenStream, item: TokenStream) -> Toke // Generate the error pack type let error_pack = options.error_struct.as_ref().map(|error_struct| { quote! { - ::mingling::macros::pack!(#error_struct = String); + #[derive(::mingling::Grouped, ::mingling::Wrap, Default)] + pub struct #error_struct(pub ::std::string::String); } }); @@ -188,7 +189,7 @@ pub(crate) fn dispatcher_clap_attr(attr: TokenStream, item: TokenStream) -> Toke // Keep the original struct definition #input_struct - // Generate the error wrapper type via pack! + // Generate the error wrapper type #error_pack // Generate the help block if enabled diff --git a/mingling_macros/src/func.rs b/mingling_macros/src/func.rs index 57d0ec5..baa23db 100644 --- a/mingling_macros/src/func.rs +++ b/mingling_macros/src/func.rs @@ -9,13 +9,6 @@ pub(crate) mod gen_program; pub(crate) mod group; #[cfg(all(feature = "structural_renderer", feature = "extras"))] pub(crate) mod group_structural; -pub(crate) mod pack; -#[cfg(feature = "extras")] -pub(crate) mod pack_err; -#[cfg(all(feature = "structural_renderer", feature = "extras"))] -pub(crate) mod pack_err_structural; -#[cfg(feature = "structural_renderer")] -pub(crate) mod pack_structural; #[cfg(feature = "comp")] pub(crate) mod program_comp_gen; pub(crate) mod program_fallback_gen; diff --git a/mingling_macros/src/func/dispatcher.rs b/mingling_macros/src/func/dispatcher.rs index c4d67a9..41dd2d0 100644 --- a/mingling_macros/src/func/dispatcher.rs +++ b/mingling_macros/src/func/dispatcher.rs @@ -115,7 +115,9 @@ pub(crate) fn dispatcher(input: TokenStream) -> TokenStream { let program_type = crate::default_program_path(); let expanded = quote! { - ::mingling::macros::pack!(#(#entry_attrs)* #pack = Vec<String>); + #[derive(::mingling::Grouped, ::mingling::Wrap, Default)] + #(#entry_attrs)* + pub struct #pack(pub ::std::vec::Vec<::std::string::String>); #(#cmd_attrs)* #[doc(hidden)] @@ -127,7 +129,7 @@ pub(crate) fn dispatcher(input: TokenStream) -> TokenStream { impl From<#pack> for crate::Entry { fn from(value: #pack) -> Self { - crate::Entry::new(value.inner) + crate::Entry(value.0) } } @@ -136,7 +138,7 @@ pub(crate) fn dispatcher(input: TokenStream) -> TokenStream { impl ::mingling::Dispatcher<#program_type> for #hidden_dispatcher { fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess<#program_type> { use ::mingling::Grouped; - ::mingling::Routable::to_chain(#pack::new(args)) + ::mingling::Routable::to_chain(#pack(args)) } } }; @@ -149,7 +151,7 @@ fn get_comp_entry(entry_name: &Ident) -> TokenStream2 { let comp_entry = quote! { impl ::mingling::CompletionEntry for #entry_name { fn get_input(self) -> Vec<String> { - self.inner.clone() + self.0.clone() } } }; diff --git a/mingling_macros/src/func/entry.rs b/mingling_macros/src/func/entry.rs index 82dfd3e..18e485f 100644 --- a/mingling_macros/src/func/entry.rs +++ b/mingling_macros/src/func/entry.rs @@ -57,7 +57,7 @@ pub(crate) fn entry(input: TokenStream) -> TokenStream { let expanded = match parsed { EntryInput::Typed { ident, .. } => { quote! { - #ident::new(vec![#(#string_exprs),*]) + #ident(vec![#(#string_exprs),*]) } } EntryInput::Untyped { .. } => { diff --git a/mingling_macros/src/func/gen_program.rs b/mingling_macros/src/func/gen_program.rs index a53f86f..c0a7ea8 100644 --- a/mingling_macros/src/func/gen_program.rs +++ b/mingling_macros/src/func/gen_program.rs @@ -57,7 +57,8 @@ pub(crate) fn gen_program_impl(_input: TokenStream) -> TokenStream { /// Alias for the current program type `ThisProgram` pub type Next = ::mingling::ChainProcess<ThisProgram>; - ::mingling::macros::pack!(Entry = Vec<String>); + #[derive(::mingling::Grouped, ::mingling::Wrap, Default)] + pub struct Entry(pub ::std::vec::Vec<::std::string::String>); impl ::mingling::Routable<ThisProgram> for ::mingling::ChainProcess<ThisProgram> { diff --git a/mingling_macros/src/func/pack.rs b/mingling_macros/src/func/pack.rs deleted file mode 100644 index d4fcb60..0000000 --- a/mingling_macros/src/func/pack.rs +++ /dev/null @@ -1,154 +0,0 @@ -// Doc Not Optimize -use proc_macro::TokenStream; -use quote::quote; -use syn::parse::{Parse, ParseStream}; -use syn::{Attribute, Ident, Result as SynResult, Token, Type}; - -struct PackInput { - attrs: Vec<Attribute>, - type_name: Ident, - inner_type: Type, -} - -impl Parse for PackInput { - fn parse(input: ParseStream) -> SynResult<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let type_name: Ident = input.parse()?; - input.parse::<Token![=]>()?; - let inner_type: Type = input.parse()?; - - Ok(Self { - attrs, - type_name, - inner_type, - }) - } -} - -#[allow(clippy::too_many_lines)] -pub(crate) fn pack(input: TokenStream) -> TokenStream { - let pack_input = syn::parse_macro_input!(input as PackInput); - - 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 - // Note: No longer derives Serialize under structural_renderer. - // Use pack_structual! for structured output support. - let struct_def = quote! { - #(#attrs)* - pub struct #type_name { - pub(crate) inner: #inner_type, - } - }; - - // Generate the new() method - let new_impl = quote! { - impl #type_name { - /// Creates a new instance of the wrapper type - pub fn new(inner: #inner_type) -> Self { - Self { inner } - } - } - }; - - // Generate From and Into implementations - let from_into_impl = quote! { - impl From<#inner_type> for #type_name { - fn from(inner: #inner_type) -> Self { - Self::new(inner) - } - } - - impl From<#type_name> for #inner_type { - fn from(wrapper: #type_name) -> #inner_type { - wrapper.inner - } - } - }; - - // Generate AsRef and AsMut implementations - let as_ref_impl = quote! { - impl ::std::convert::AsRef<#inner_type> for #type_name { - fn as_ref(&self) -> &#inner_type { - &self.inner - } - } - - impl ::std::convert::AsMut<#inner_type> for #type_name { - fn as_mut(&mut self) -> &mut #inner_type { - &mut self.inner - } - } - }; - - // Generate Deref and DerefMut implementations - let deref_impl = quote! { - impl ::std::ops::Deref for #type_name { - type Target = #inner_type; - - fn deref(&self) -> &Self::Target { - &self.inner - } - } - - impl ::std::ops::DerefMut for #type_name { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } - } - }; - - // Check if the inner type implements Default by generating conditional code - let default_impl = quote! { - impl ::std::default::Default for #type_name - where - #inner_type: ::std::default::Default, - { - fn default() -> Self { - Self::new(::std::default::Default::default()) - } - } - }; - - let register_impl = quote! { - ::mingling::macros::register_type!(#type_name); - }; - - 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) - } - } - - impl Into<mingling::ChainProcess<#group_name>> for #type_name { - fn into(self) -> mingling::ChainProcess<#group_name> { - mingling::AnyOutput::new(self).route_chain() - } - } - - /// SAFETY: This is an internal implementation of the `pack!` macro, - /// guaranteeing that the enum value registered by the `register_type!` macro - /// is exactly the same as the actual return value, - /// which can be confirmed via the `Ident` in the `quote!` block. - unsafe impl ::mingling::Grouped<#group_name> for #type_name { - fn member_id() -> #group_name { - #group_name::#type_name - } - } - }; - - expanded.into() -} diff --git a/mingling_macros/src/func/pack_err.rs b/mingling_macros/src/func/pack_err.rs deleted file mode 100644 index e925b82..0000000 --- a/mingling_macros/src/func/pack_err.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Doc Not Optimize -use just_fmt::snake_case; -use proc_macro::TokenStream; -use quote::quote; -use syn::{Ident, Token, Type, parse_macro_input}; - -enum PackErrInput { - /// `pack_err!(ErrorNotFound)` - Simple { type_name: Ident }, - /// `pack_err!(ErrorNotDir = PathBuf)` - Typed { - type_name: Ident, - inner_type: Box<Type>, - }, -} - -impl syn::parse::Parse for PackErrInput { - fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { - let type_name: Ident = input.parse()?; - - if input.peek(Token![=]) { - input.parse::<Token![=]>()?; - let inner_type: Type = input.parse()?; - Ok(Self::Typed { - type_name, - inner_type: Box::new(inner_type), - }) - } else { - Ok(Self::Simple { type_name }) - } - } -} - -#[allow(clippy::too_many_lines)] -pub(crate) fn pack_err(input: TokenStream) -> TokenStream { - let parsed = parse_macro_input!(input as PackErrInput); - - match parsed { - PackErrInput::Simple { type_name } => { - let name_str = type_name.to_string(); - let snake_name = snake_case!(&name_str); - - // Note: No longer derives Serialize under structural_renderer. - // Use pack_err_structural for structured output support. - let derive = quote! { - #[derive(::mingling::Grouped)] - }; - - let expanded = quote! { - #derive - pub struct #type_name { - /// The snake_case name of this error, automatically set at compile time. - pub name: String, - } - - impl ::std::default::Default for #type_name { - fn default() -> Self { - Self { - name: #snake_name.into(), - } - } - } - - ::mingling::macros::register_type!(#type_name); - }; - - expanded.into() - } - PackErrInput::Typed { - type_name, - inner_type, - } => { - let name_str = type_name.to_string(); - let snake_name = snake_case!(&name_str); - - // Note: No longer derives Serialize under structural_renderer. - // Use pack_err_structural for structured output support. - let derive = quote! { - #[derive(::mingling::Grouped)] - }; - - let expanded = quote! { - #derive - pub struct #type_name { - /// The snake_case name of this error, automatically set at compile time. - pub name: String, - /// Additional context info for this error. - pub info: #inner_type, - } - - impl #type_name { - /// Creates a new error with the given info. - /// The `name` field is automatically set to the snake_case of the struct name. - pub fn new(info: #inner_type) -> Self { - Self { - name: #snake_name.into(), - info, - } - } - } - - ::mingling::macros::register_type!(#type_name); - }; - - expanded.into() - } - } -} diff --git a/mingling_macros/src/func/pack_err_structural.rs b/mingling_macros/src/func/pack_err_structural.rs deleted file mode 100644 index 950b8dc..0000000 --- a/mingling_macros/src/func/pack_err_structural.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Doc Not Optimize -use just_fmt::snake_case; -use proc_macro::TokenStream; -use quote::quote; -use syn::{Ident, Token, Type, parse_macro_input}; - -/// `pack_err_structural!` — like `pack_err!` but also marks the type as -/// supporting structured output via `StructuralData`. -pub(crate) fn pack_err_structural(input: TokenStream) -> TokenStream { - let parsed = parse_macro_input!(input as PackErrInput); - - let type_name = match &parsed { - PackErrInput::Simple { type_name } | PackErrInput::Typed { type_name, .. } => { - type_name.clone() - } - }; - - // Register in STRUCTURED_TYPES - let type_name_str = type_name.to_string(); - crate::get_global_set(&crate::STRUCTURED_TYPES) - .lock() - .unwrap() - .insert(type_name_str); - - let structural_data = quote! { - impl ::mingling::__private::StructuralDataSealed<crate::ThisProgram> for #type_name {} - impl ::mingling::__private::StructuralData<crate::ThisProgram> for #type_name {} - }; - - // Generate the struct + impls (same as pack_err! but with Serialize derive + sealed) - match parsed { - PackErrInput::Simple { type_name } => { - let name_str = type_name.to_string(); - let snake_name = snake_case!(&name_str); - - let expanded = quote! { - #[derive(::mingling::Grouped, ::serde::Serialize)] - pub struct #type_name { - /// The snake_case name of this error, automatically set at compile time. - pub name: String, - } - - impl ::std::default::Default for #type_name { - fn default() -> Self { - Self { - name: #snake_name.into(), - } - } - } - - ::mingling::macros::register_type!(#type_name); - - #structural_data - }; - - expanded.into() - } - PackErrInput::Typed { - type_name, - inner_type, - } => { - let name_str = type_name.to_string(); - let snake_name = snake_case!(&name_str); - - let expanded = quote! { - #[derive(::mingling::Grouped, ::serde::Serialize)] - pub struct #type_name { - /// The snake_case name of this error, automatically set at compile time. - pub name: String, - /// Additional context info for this error. - pub info: #inner_type, - } - - impl #type_name { - /// Creates a new error with the given info. - /// The `name` field is automatically set to the snake_case of the struct name. - pub fn new(info: #inner_type) -> Self { - Self { - name: #snake_name.into(), - info, - } - } - } - - ::mingling::macros::register_type!(#type_name); - - #structural_data - }; - - expanded.into() - } - } -} - -// Re-use pack_err's input parser -enum PackErrInput { - Simple { - type_name: Ident, - }, - Typed { - type_name: Ident, - inner_type: Box<Type>, - }, -} - -impl syn::parse::Parse for PackErrInput { - fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { - let type_name: Ident = input.parse()?; - - if input.peek(Token![=]) { - input.parse::<Token![=]>()?; - let inner_type: Type = input.parse()?; - Ok(Self::Typed { - type_name, - inner_type: Box::new(inner_type), - }) - } else { - Ok(Self::Simple { type_name }) - } - } -} diff --git a/mingling_macros/src/func/pack_structural.rs b/mingling_macros/src/func/pack_structural.rs deleted file mode 100644 index fb13fbf..0000000 --- a/mingling_macros/src/func/pack_structural.rs +++ /dev/null @@ -1,170 +0,0 @@ -// Doc Not Optimize -use proc_macro::TokenStream; -use quote::quote; -use syn::Ident; - -use crate::get_global_set; - -/// `pack_structural!` — like `pack!` but also marks the type as supporting -/// structured output via `StructuralData`. -#[allow(clippy::too_many_lines)] -pub(crate) fn pack_structural(input: TokenStream) -> TokenStream { - // Parse same input format as `pack!` - let input_parsed = syn::parse_macro_input!(input as PackStructuralInput); - let type_name = input_parsed.type_name; - let inner_type = input_parsed.inner_type; - let attrs = input_parsed.attrs; - let program_path = crate::default_program_path(); - - // Register in STRUCTURED_TYPES - let type_name_str = type_name.to_string(); - get_global_set(&crate::STRUCTURED_TYPES) - .lock() - .unwrap() - .insert(type_name_str); - - // Struct definition (with Serialize derive, same as pack! under structural_renderer) - #[cfg(not(feature = "structural_renderer"))] - let struct_def = quote! { - #(#attrs)* - pub struct #type_name { - pub inner: #inner_type, - } - }; - - #[cfg(feature = "structural_renderer")] - let struct_def = quote! { - #(#attrs)* - #[derive(serde::Serialize)] - pub struct #type_name { - pub inner: #inner_type, - } - }; - - // Helper impls (same as pack!) - let new_impl = quote! { - impl #type_name { - pub fn new(inner: #inner_type) -> Self { - Self { inner } - } - } - }; - - let from_into_impl = quote! { - impl From<#inner_type> for #type_name { - fn from(inner: #inner_type) -> Self { - Self::new(inner) - } - } - impl From<#type_name> for #inner_type { - fn from(wrapper: #type_name) -> #inner_type { - wrapper.inner - } - } - }; - - let as_ref_impl = quote! { - impl ::std::convert::AsRef<#inner_type> for #type_name { - fn as_ref(&self) -> &#inner_type { - &self.inner - } - } - impl ::std::convert::AsMut<#inner_type> for #type_name { - fn as_mut(&mut self) -> &mut #inner_type { - &mut self.inner - } - } - }; - - let deref_impl = quote! { - impl ::std::ops::Deref for #type_name { - type Target = #inner_type; - fn deref(&self) -> &Self::Target { - &self.inner - } - } - impl ::std::ops::DerefMut for #type_name { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } - } - }; - - let default_impl = quote! { - impl ::std::default::Default for #type_name - where - #inner_type: ::std::default::Default, - { - fn default() -> Self { - Self::new(::std::default::Default::default()) - } - } - }; - - let register_impl = quote! { - ::mingling::macros::register_type!(#type_name); - }; - - // StructuralData impl + sealed + registration - let structural_impl = quote! { - impl ::mingling::__private::StructuralDataSealed<crate::ThisProgram> for #type_name {} - impl ::mingling::__private::StructuralData<crate::ThisProgram> for #type_name {} - }; - - let expanded = quote! { - #struct_def - - #new_impl - #from_into_impl - #as_ref_impl - #deref_impl - #default_impl - #register_impl - #structural_impl - - impl Into<::mingling::AnyOutput<#program_path>> for #type_name { - fn into(self) -> ::mingling::AnyOutput<#program_path> { - ::mingling::AnyOutput::new(self) - } - } - - impl Into<::mingling::ChainProcess<#program_path>> for #type_name { - fn into(self) -> ::mingling::ChainProcess<#program_path> { - ::mingling::AnyOutput::new(self).route_chain() - } - } - - /// SAFETY: This is an internal implementation of the `pack_structural!` macro, - /// guaranteeing that the enum value registered by the `register_type!` macro - /// is exactly the same as the actual return value, - /// which can be confirmed via the `Ident` in the `quote!` block. - unsafe impl ::mingling::Grouped<#program_path> for #type_name { - fn member_id() -> #program_path { - #program_path::#type_name - } - } - }; - - expanded.into() -} - -/// Input for `pack_structural!` — same format as `pack!`. -struct PackStructuralInput { - attrs: Vec<syn::Attribute>, - type_name: Ident, - inner_type: syn::Type, -} - -impl syn::parse::Parse for PackStructuralInput { - fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { - let attrs = input.call(syn::Attribute::parse_outer)?; - let type_name: Ident = input.parse()?; - input.parse::<syn::Token![=]>()?; - let inner_type: syn::Type = input.parse()?; - Ok(Self { - attrs, - type_name, - inner_type, - }) - } -} diff --git a/mingling_macros/src/func/program_comp_gen.rs b/mingling_macros/src/func/program_comp_gen.rs index ed04379..cdd2597 100644 --- a/mingling_macros/src/func/program_comp_gen.rs +++ b/mingling_macros/src/func/program_comp_gen.rs @@ -11,11 +11,11 @@ pub(crate) fn program_comp_gen_impl(_input: TokenStream) -> TokenStream { pub async fn __exec_completion(prev: CompletionContext) -> Next { use ::mingling::Grouped; - let read_ctx = ::mingling::ShellContext::try_from(prev.inner); + let read_ctx = ::mingling::ShellContext::try_from(prev.0); match read_ctx { Ok(ctx) => { let suggest = ::mingling::CompletionHelper::exec_completion::<crate::ThisProgram>(&ctx); - ::mingling::Routable::<crate::ThisProgram>::to_render(CompletionSuggest::new((ctx, suggest))) + ::mingling::Routable::<crate::ThisProgram>::to_render(CompletionSuggest((ctx, suggest))) } Err(_) => std::process::exit(1), } @@ -29,11 +29,11 @@ pub(crate) fn program_comp_gen_impl(_input: TokenStream) -> TokenStream { pub fn __exec_completion(prev: CompletionContext) -> Next { use ::mingling::Grouped; - let read_ctx = ::mingling::ShellContext::try_from(prev.inner); + let read_ctx = ::mingling::ShellContext::try_from(prev.0); match read_ctx { Ok(ctx) => { let suggest = ::mingling::CompletionHelper::exec_completion::<crate::ThisProgram>(&ctx); - ::mingling::Routable::<crate::ThisProgram>::to_render(CompletionSuggest::new((ctx, suggest))) + ::mingling::Routable::<crate::ThisProgram>::to_render(CompletionSuggest((ctx, suggest))) } Err(_) => std::process::exit(1), } @@ -50,9 +50,8 @@ pub(crate) fn program_comp_gen_impl(_input: TokenStream) -> TokenStream { mod __internal_completion_mod { use ::mingling::Grouped; ::mingling::macros::dispatcher!("__comp", CompletionContext); - ::mingling::macros::pack!( - CompletionSuggest = (::mingling::ShellContext, ::mingling::Suggest) - ); + #[derive(::mingling::Grouped, ::mingling::Wrap)] + pub struct CompletionSuggest(pub (::mingling::ShellContext, ::mingling::Suggest)); } #internal_dispatcher_comp use __internal_completion_mod::CompletionContext; @@ -67,7 +66,7 @@ pub(crate) fn program_comp_gen_impl(_input: TokenStream) -> TokenStream { #[::mingling::macros::renderer] pub fn __render_completion(prev: CompletionSuggest) -> ::mingling::RenderResult { let result = ::mingling::RenderResult::default(); - let (ctx, suggest) = prev.inner; + let (ctx, suggest) = prev.0; ::mingling::CompletionHelper::render_suggest::<crate::ThisProgram>(&ctx, suggest); result } diff --git a/mingling_macros/src/func/program_fallback_gen.rs b/mingling_macros/src/func/program_fallback_gen.rs index df53c60..1f3fdce 100644 --- a/mingling_macros/src/func/program_fallback_gen.rs +++ b/mingling_macros/src/func/program_fallback_gen.rs @@ -16,8 +16,12 @@ pub(crate) fn program_fallback_gen_impl(_input: TokenStream) -> TokenStream { }; let expanded = quote! { - ::mingling::macros::pack!(ErrorRendererNotFound = String); - ::mingling::macros::pack!(EntryFallback = Vec<String>); + #[derive(::mingling::Grouped, ::mingling::Wrap, Default)] + pub struct ErrorRendererNotFound(pub ::std::string::String); + + #[derive(::mingling::Grouped, ::mingling::Wrap, Default)] + pub struct EntryFallback(pub ::std::vec::Vec<::std::string::String>); + #pack_empty }; TokenStream::from(expanded) diff --git a/mingling_macros/src/func/program_final_gen.rs b/mingling_macros/src/func/program_final_gen.rs index d549a2b..8123eaf 100644 --- a/mingling_macros/src/func/program_final_gen.rs +++ b/mingling_macros/src/func/program_final_gen.rs @@ -376,10 +376,10 @@ pub(crate) fn program_final_gen_impl(_input: TokenStream) -> TokenStream { type ResultEmpty = ResultEmpty; fn build_renderer_not_found(member_id: Self::Enum) -> ::mingling::AnyOutput<Self::Enum> { - ::mingling::AnyOutput::new(ErrorRendererNotFound::new(member_id.to_string())) + ::mingling::AnyOutput::new(ErrorRendererNotFound(member_id.to_string())) } fn build_entry_fallback(args: Vec<String>) -> ::mingling::AnyOutput<Self::Enum> { - ::mingling::AnyOutput::new(EntryFallback::new(args)) + ::mingling::AnyOutput::new(EntryFallback(args)) } fn build_empty_result() -> ::mingling::AnyOutput<Self::Enum> { ::mingling::AnyOutput::new(ResultEmpty) diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs index 7da7db3..d0556dc 100644 --- a/mingling_macros/src/lib.rs +++ b/mingling_macros/src/lib.rs @@ -34,15 +34,13 @@ use attr::dispatcher_clap; use attr::program_setup; use attr::{chain, help, metadata, renderer}; use derive::{enum_tag, grouped, wrap}; +use func::dispatcher; #[cfg(feature = "extras")] use func::entry; #[cfg(feature = "extras")] pub(crate) use func::group as group_impl; -#[cfg(feature = "extras")] -use func::pack_err; #[cfg(feature = "comp")] use func::suggest; -use func::{dispatcher, pack}; use systems::res_injection; pub(crate) fn default_program_path() -> proc_macro2::TokenStream { quote::quote! { crate::ThisProgram } @@ -60,7 +58,7 @@ pub(crate) type Registry = OnceLock<Mutex<BTreeSet<String>>>; pub(crate) static STRUCTURAL_RENDERERS: Registry = OnceLock::new(); /// Types explicitly marked with `#[derive(StructuralData)]` or created via -/// `pack_structural!` / `group_structural!`. +/// `group_structural!`. #[cfg(feature = "structural_renderer")] pub(crate) static STRUCTURED_TYPES: Registry = OnceLock::new(); @@ -183,163 +181,6 @@ pub fn group_structural(input: TokenStream) -> TokenStream { func::group_structural::group_structural(input) } -/// Creates a type-safe wrapper struct around an inner type, with automatic -/// trait implementations for use in the Mingling chain/render pipeline. -/// -/// The generated struct implements: `From`/`Into`, `AsRef`/`AsMut`, `Deref`/`DerefMut`, -/// `Default` (conditional on inner type), and conversion into `AnyOutput` / -/// `ChainProcess` for routing. -/// -/// # Syntax -/// -/// ```rust,ignore -/// // Default program name (uses `ThisProgram`): -/// pack!(TypeName = InnerType); -/// -/// // Explicit program name: -/// pack!(MyProgram, TypeName = InnerType); -/// ``` -/// -/// # Example -/// -/// ```rust,ignore -/// use mingling::macros::pack; -/// -/// // Creates `Hello` wrapping `String`, registered under `ThisProgram`: -/// pack!(Hello = String); -/// -/// // Creates `Greeting` wrapping `String`, registered under `MyApp`: -/// pack!(MyApp, Greeting = String); -/// ``` -/// -/// After expansion, `Hello` has: -/// - `Hello::new(String)` — constructor -/// - `Hello::to_chain()` — routes to the next chain processor -/// - `Hello::to_render()` — routes to a renderer -/// - `From<String> for Hello`, `From<Hello> for String` -/// - `Deref<Target = String>`, `DerefMut` -/// - `AsRef<String>`, `AsMut<String>` -/// - `Default` if `String: Default` -/// - `Into<AnyOutput<ThisProgram>>`, `Into<ChainProcess<ThisProgram>>` -/// - Implements `Grouped<ThisProgram>` with `member_id()` returning the enum variant -/// -/// The struct is also registered via `register_type!` so that `gen_program!` -/// can include it in the program enum. -/// -/// When the `structural_renderer` feature is enabled, the struct also gets -/// `#[derive(serde::Serialize)]`. -#[proc_macro] -pub fn pack(input: TokenStream) -> TokenStream { - pack::pack(input) -} - -/// Like `pack!` but also marks the type as supporting structured output -/// (JSON / YAML / TOML / RON) via `StructuralData`. -/// -/// # Syntax -/// -/// ```rust,ignore -/// pack_structural!(Info = (String, i32)); -/// ``` -/// -/// This is equivalent to: -/// ```rust,ignore -/// pack!(Info = (String, i32)); -/// impl ::mingling::StructuralData for Info {} -/// ``` -/// -/// Requires the `structural_renderer` feature. -#[cfg(feature = "structural_renderer")] -#[proc_macro] -pub fn pack_structural(input: TokenStream) -> TokenStream { - func::pack_structural::pack_structural(input) -} - -/// Creates an error struct with a `name: String` field and optional `info: Type` field. -/// -/// This macro provides a concise way to define error types that implement `Grouped` -/// and are registered for inclusion in the program enum. -/// -/// The `name` field is automatically set to the `snake_case` version of the struct name -/// at compile time. -/// -/// # Syntax -/// -/// Two forms are supported: -/// -/// ```rust,ignore -/// // Simple form — generates a struct with only `name: String` and a `Default` impl: -/// pack_err!(ErrorNotFound); -/// -/// // Typed form — generates a struct with `name: String` + `info: Type` and a `new(info)` constructor: -/// pack_err!(ErrorNotDir = PathBuf); -/// ``` -/// -/// # Generated code -/// -/// For `pack_err!(ErrorNotFound)`: -/// -/// ```rust,ignore -/// #[derive(::mingling::Grouped)] -/// pub struct ErrorNotFound { -/// name: String, -/// } -/// -/// impl Default for ErrorNotFound { -/// fn default() -> Self { -/// Self { -/// name: "error_not_found".into(), -/// } -/// } -/// } -/// ``` -/// -/// For `pack_err!(ErrorNotDir = PathBuf)`: -/// -/// ```rust,ignore -/// #[derive(::mingling::Grouped)] -/// pub struct ErrorNotDir { -/// name: String, -/// info: PathBuf, -/// } -/// -/// impl ErrorNotDir { -/// pub fn new(info: PathBuf) -> Self { -/// Self { -/// name: "error_not_dir".into(), -/// info, -/// } -/// } -/// } -/// ``` -/// -/// When the `structural_renderer` feature is enabled, the struct also gets -/// `#[derive(serde::Serialize)]`. -/// -/// This macro is only available with the `extras` feature. -#[cfg(feature = "extras")] -#[proc_macro] -pub fn pack_err(input: TokenStream) -> TokenStream { - pack_err::pack_err(input) -} - -/// Like `pack_err!` but also marks the type for structured output -/// (JSON / YAML / TOML / RON) via `StructuralData`. -/// -/// # Syntax -/// -/// ```rust,ignore -/// pack_err_structural!(ErrorNotFound); -/// pack_err_structural!(ErrorNotDir = PathBuf); -/// ``` -/// -/// Requires the `structural_renderer` and `extras` features. -#[cfg(all(feature = "structural_renderer", feature = "extras"))] -#[proc_macro] -pub fn pack_err_structural(input: TokenStream) -> TokenStream { - func::pack_err_structural::pack_err_structural(input) -} - /// Early-returns the error from a `Result`, converting the `Ok` branch to the /// next chain process value. /// @@ -555,7 +396,7 @@ pub fn empty_result(input: TokenStream) -> TokenStream { /// /// The macro generates: /// -/// 1. **Entry struct** — A `pack!`-style wrapper around `Vec<String>` (the raw args). +/// 1. **Entry struct** — A newtype wrapper around `Vec<String>` (the raw args). /// Registered in the program enum via `register_type!`. /// 2. **Dispatcher struct** — A hidden zero-sized struct implementing [`Dispatcher<Program>`]: /// - `begin(args)` wraps `args` into the entry type and routes to chain. @@ -664,78 +505,89 @@ pub fn dispatcher(input: TokenStream) -> TokenStream { /// # Sync Example /// /// ```rust,ignore -/// use mingling::macros::{chain, pack, gen_program}; +/// use mingling::macros::{chain, gen_program}; +/// use mingling::{Grouped, Wrap}; /// -/// pack!(MyOutput = String); +/// #[derive(Grouped, Wrap)] +/// pub struct MyOutput(String); /// /// #[chain] /// fn greet(prev: HelloEntry) -> Next { /// let name = prev.first().cloned().unwrap_or_else(|| "World".to_string()); -/// MyOutput::new(name) +/// MyOutput(name) /// } /// ``` /// /// # Sync Example with Resource Injection /// /// ```rust,ignore -/// use mingling::macros::{chain, pack, gen_program}; +/// use mingling::macros::{chain, gen_program}; +/// use mingling::{Grouped, Wrap}; /// /// #[derive(Default, Clone)] /// struct UserName(String); /// -/// pack!(Greeting = String); -/// pack!(DisplayCount = ()); +/// #[derive(Grouped, Wrap)] +/// pub struct Greeting(String); +/// #[derive(Grouped, Wrap)] +/// pub struct DisplayCount(()); /// /// #[chain] /// fn greet(prev: HelloEntry, user_name: &UserName, count: &mut u64) -> Next { /// *count += 1; -/// Greeting::new(format!("Hello, {}!", user_name.0)) +/// Greeting(format!("Hello, {}!", user_name.0)) /// } /// ``` /// /// # Async Example (with `async` feature) /// /// ```rust,ignore -/// use mingling::macros::{chain, pack, gen_program}; +/// use mingling::macros::{chain, gen_program}; +/// use mingling::{Grouped, Wrap}; /// -/// pack!(MyOutput = String); +/// #[derive(Grouped, Wrap)] +/// pub struct MyOutput(String); /// /// #[chain] /// async fn greet(prev: HelloEntry) -> Next { /// let name = prev.first().cloned().unwrap_or_else(|| "World".to_string()); /// some_async_fn(&name).await; -/// MyOutput::new(name) +/// MyOutput(name) /// } /// ``` /// /// # Async Example with Immutable Resource Injection /// /// ```rust,ignore -/// use mingling::macros::{chain, pack, gen_program}; +/// use mingling::macros::{chain, gen_program}; +/// use mingling::{Grouped, Wrap}; /// -/// pack!(MyOutput = String); +/// #[derive(Grouped, Wrap)] +/// pub struct MyOutput(String); /// /// #[chain] /// async fn greet(prev: HelloEntry, prefix: &Prefix) -> Next { /// let name = prev.first().cloned().unwrap_or_else(|| "World".to_string()); /// some_async_fn(&name).await; -/// MyOutput::new(format!("{}{}", prefix.0, name)) +/// MyOutput(format!("{}{}", prefix.0, name)) /// } /// ``` /// /// # Async Example with Mutable Resource Injection /// /// ```rust,ignore -/// use mingling::macros::{chain, pack, gen_program}; +/// use mingling::macros::{chain, gen_program}; +/// use mingling::{Grouped, Wrap}; /// -/// pack!(MyOutput = String); +/// #[derive(Grouped, Wrap)] +/// pub struct MyOutput(String); /// /// #[chain] /// async fn greet(prev: HelloEntry, ec: &mut ResExitCode) -> Next { /// let name = prev.first().cloned().unwrap_or_else(|| "World".to_string()); /// ec.exit_code = 42; /// some_async_fn(&name).await; -/// MyOutput::new(name) +/// MyOutput(name) /// } /// ``` /// @@ -777,10 +629,12 @@ pub fn chain(attr: TokenStream, item: TokenStream) -> TokenStream { /// # Example /// /// ```rust,ignore -/// use mingling::macros::{renderer, pack, gen_program}; +/// use mingling::macros::{renderer, gen_program}; +/// use mingling::{Grouped, Wrap}; /// use std::io::Write; /// -/// pack!(Greeting = String); +/// #[derive(Grouped, Wrap)] +/// pub struct Greeting(String); /// /// #[renderer] /// fn render_greeting(prev: Greeting) -> RenderResult { @@ -1063,7 +917,7 @@ pub fn dispatcher_clap(attr: TokenStream, item: TokenStream) -> TokenStream { /// Creates a packed entry value from a list of string literals. /// /// This is a convenience macro for constructing entry wrapper types (created -/// via `pack!` or `dispatcher!`) with test data, typically used in unit tests +/// via `dispatcher!`) with test data, typically used in unit tests /// or quick prototypes. /// /// # Syntax @@ -1071,9 +925,9 @@ pub fn dispatcher_clap(attr: TokenStream, item: TokenStream) -> TokenStream { /// Two forms: /// /// ```rust,ignore -/// // Named form — wraps into a specific pack type: +/// // Named form — wraps into a specific entry type: /// entry!(MyEntry, ["a", "b", "c"]) -/// // Expands to: MyEntry::new(vec!["a".to_string(), "b".to_string(), "c".to_string()]) +/// // Expands to: MyEntry(vec!["a".to_string(), "b".to_string(), "c".to_string()]) /// /// // Bracket form — returns Vec<String>.into() for type inference: /// entry!["a", "b", "c"] @@ -1085,7 +939,7 @@ pub fn dispatcher_clap(attr: TokenStream, item: TokenStream) -> TokenStream { /// ```rust,ignore /// use mingling::macros::entry; /// -/// // Named form (with a specific pack type): +/// // Named form (with a specific entry type): /// let args = entry!(MyEntry, ["--name", "Alice", "--count", "5"]); /// /// // Bracket form (type inference): @@ -1094,8 +948,7 @@ pub fn dispatcher_clap(attr: TokenStream, item: TokenStream) -> TokenStream { /// /// # See also /// -/// - `pack!` — For creating the wrapper types used with `entry!`. -/// - `dispatcher!` — Which implicitly creates entry types via `pack!`. +/// - `dispatcher!` — Which implicitly creates entry types. #[cfg(feature = "extras")] #[proc_macro] pub fn entry(input: TokenStream) -> TokenStream { @@ -1204,11 +1057,12 @@ pub fn register_dispatcher(input: TokenStream) -> TokenStream { /// # Example /// /// ```rust,ignore -/// use mingling::macros::{help, pack, gen_program}; +/// use mingling::macros::{help, gen_program}; /// use mingling::{prelude::*, setup::BasicProgramSetup, RenderResult}; /// use std::io::Write; /// -/// pack!(MyEntry = Vec<String>); +/// #[derive(Grouped, Wrap)] +/// pub struct MyEntry(Vec<String>); /// /// #[help] /// fn help_my_entry(prev: MyEntry) -> RenderResult { @@ -1620,8 +1474,8 @@ pub fn derive_wrap(input: TokenStream) -> TokenStream { /// } /// ``` /// -/// This is equivalent to using `pack!` but works with custom structs that -/// have named fields. For simple wrappers, prefer `pack!`. +/// This is equivalent to using `#[derive(Grouped)]` but works with custom structs that +/// have named fields. #[proc_macro_derive(Grouped, attributes(group))] pub fn derive_grouped(input: TokenStream) -> TokenStream { grouped::derive_grouped(input) @@ -1813,7 +1667,7 @@ pub fn program_comp_gen(input: TokenStream) -> TokenStream { /// Registers a type into the global packed types registry for inclusion in /// the program enum generated by `gen_program!`. /// -/// This macro is called internally by `pack!` and `#[derive(Grouped)]`(`macro.derive_grouped.html`) +/// This macro is called internally by `#[derive(Grouped)]` (`macro.derive_grouped.html`) /// and is generally not needed in user code. However, it can be used for manual /// registration if you are implementing custom type registration outside of /// the standard macros. @@ -1885,7 +1739,7 @@ pub fn program_fallback_gen(input: TokenStream) -> TokenStream { /// and its `ProgramCollect` implementation. /// /// This is the core code generation macro that: -/// 1. Collects all registered types (from `pack!`, `#[derive(Grouped)]`, etc.) and +/// 1. Collects all registered types (from `#[derive(Grouped)]`, etc.) and /// creates an enum with each type as a variant. /// 2. Generates the `Display` implementation for the enum. /// 3. Generates the `ProgramCollect` implementation that dispatches to all diff --git a/mingling_macros/src/systems.rs b/mingling_macros/src/systems.rs index ef3624e..3279b51 100644 --- a/mingling_macros/src/systems.rs +++ b/mingling_macros/src/systems.rs @@ -1,8 +1,7 @@ -// Doc Not Optimize #[cfg(not(feature = "dispatch_tree"))] pub(crate) mod dispatch_list_gen; + #[cfg(feature = "dispatch_tree")] pub(crate) mod dispatch_tree_gen; + pub(crate) mod res_injection; -#[cfg(feature = "structural_renderer")] -pub(crate) mod structural_data; diff --git a/mingling_macros/src/systems/structural_data.rs b/mingling_macros/src/systems/structural_data.rs deleted file mode 100644 index ac9b1ca..0000000 --- a/mingling_macros/src/systems/structural_data.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Doc Not Optimize -//! Legacy structural data module. -//! -//! Functions have been moved to: -//! - `derive::structural_data` — `derive_structural_data` -//! - `func::pack_structural` — `pack_structural` -//! - `func::group_structural` — `group_structural` |
