aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-04-19 00:31:05 +0800
committer魏曹先生 <1992414357@qq.com>2026-04-19 00:31:05 +0800
commit532f4ceba2bddb1c84d2e0bdd69808a3ebd5ca4a (patch)
tree043514a2aca670d8b2398726b17aab1066938ba1 /mingling_macros
parentecc1329bbd31cd98fa9b4c2f25a3114f133987ae (diff)
Make async an optional feature
Diffstat (limited to 'mingling_macros')
-rw-r--r--mingling_macros/Cargo.toml1
-rw-r--r--mingling_macros/src/chain.rs102
-rw-r--r--mingling_macros/src/lib.rs42
3 files changed, 104 insertions, 41 deletions
diff --git a/mingling_macros/Cargo.toml b/mingling_macros/Cargo.toml
index 1154c3d..1875cb0 100644
--- a/mingling_macros/Cargo.toml
+++ b/mingling_macros/Cargo.toml
@@ -11,6 +11,7 @@ proc-macro = true
[features]
default = []
+async = []
full = ["comp", "general_renderer"]
comp = []
general_renderer = []
diff --git a/mingling_macros/src/chain.rs b/mingling_macros/src/chain.rs
index 14e62ec..ed36e10 100644
--- a/mingling_macros/src/chain.rs
+++ b/mingling_macros/src/chain.rs
@@ -1,7 +1,10 @@
//! Chain Attribute Macro Implementation
//!
//! This module provides the `#[chain(Group)]` attribute macro for automatically
-//! generating structs that implement the `Chain` trait from async functions.
+//! generating structs that implement the `Chain` trait from functions.
+//!
+//! When the `async` feature is enabled, chain functions must be async functions.
+//! When the `async` feature is disabled, chain functions can be regular functions.
use proc_macro::TokenStream;
use quote::{ToTokens, quote};
@@ -74,11 +77,30 @@ pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
// Parse the function item
let input_fn = parse_macro_input!(item as ItemFn);
- // Validate the function
- if input_fn.sig.asyncness.is_none() {
- return syn::Error::new(input_fn.sig.span(), "Chain function must be async")
+ // Validate the chain functions is a async function
+ #[cfg(feature = "async")]
+ {
+ if input_fn.sig.asyncness.is_none() {
+ return syn::Error::new(
+ input_fn.sig.span(),
+ "Chain function must be async when async feature is enabled",
+ )
+ .to_compile_error()
+ .into();
+ }
+ }
+
+ // Validate the chain functions is a regular function
+ #[cfg(not(feature = "async"))]
+ {
+ if input_fn.sig.asyncness.is_some() {
+ return syn::Error::new(
+ input_fn.sig.span(),
+ "Chain function cannot be async when async feature is disabled",
+ )
.to_compile_error()
.into();
+ }
}
// Extract the previous type and parameter name from function arguments
@@ -122,6 +144,48 @@ pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
let pascal_case_name = just_fmt::pascal_case!(fn_name.to_string());
let struct_name = Ident::new(&pascal_case_name, fn_name.span());
+ #[cfg(feature = "async")]
+ let proc_fn = quote! {
+ async fn proc(#prev_param: Self::Previous) ->
+ ::mingling::ChainProcess<ThisProgram>
+ {
+ let _ = NextProcess;
+ // Call the original function
+ #fn_name(#prev_param).await
+ }
+ };
+
+ #[cfg(feature = "async")]
+ let origin_proc_fn = quote! {
+ #(#fn_attrs)*
+ #vis async fn #fn_name(#prev_param: #previous_type)
+ -> ::mingling::ChainProcess<#group_name>
+ {
+ #fn_body
+ }
+ };
+
+ #[cfg(not(feature = "async"))]
+ let proc_fn = quote! {
+ fn proc(#prev_param: Self::Previous) ->
+ ::mingling::ChainProcess<ThisProgram>
+ {
+ let _ = NextProcess;
+ // Call the original function
+ #fn_name(#prev_param)
+ }
+ };
+
+ #[cfg(not(feature = "async"))]
+ let origin_proc_fn = quote! {
+ #(#fn_attrs)*
+ #vis fn #fn_name(#prev_param: #previous_type)
+ -> ::mingling::ChainProcess<#group_name>
+ {
+ #fn_body
+ }
+ };
+
// Generate the struct and implementation
let expanded = if use_crate_prefix {
quote! {
@@ -134,22 +198,11 @@ pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
impl ::mingling::Chain<ThisProgram> for #struct_name {
type Previous = #previous_type;
- async fn proc(#prev_param: Self::Previous) ->
- ::mingling::ChainProcess<ThisProgram>
- {
- let _ = NextProcess;
- // Call the original function
- #fn_name(#prev_param).await
- }
+ #proc_fn
}
// Keep the original function for internal use
- #(#fn_attrs)*
- #vis async fn #fn_name(#prev_param: #previous_type)
- -> ::mingling::ChainProcess<ThisProgram>
- {
- #fn_body
- }
+ #origin_proc_fn
}
} else {
quote! {
@@ -161,22 +214,11 @@ pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
impl ::mingling::Chain<#group_name> for #struct_name {
type Previous = #previous_type;
- async fn proc(#prev_param: Self::Previous) ->
- ::mingling::ChainProcess<#group_name>
- {
- let _ = NextProcess;
- // Call the original function
- #fn_name(#prev_param).await
- }
+ #proc_fn
}
// Keep the original function for internal use
- #(#fn_attrs)*
- #vis async fn #fn_name(#prev_param: #previous_type)
- -> ::mingling::ChainProcess<#group_name>
- {
- #fn_body
- }
+ #origin_proc_fn
}
};
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index 5391dfd..4ae9e43 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -132,6 +132,36 @@ pub fn gen_program(input: TokenStream) -> TokenStream {
pub fn program_gen_completion(input: TokenStream) -> TokenStream {
let name = read_name(&input);
+ #[cfg(feature = "async")]
+ let fn_exec_comp = quote! {
+ #[::mingling::macros::chain(#name)]
+ pub async fn __exec_completion(prev: CompletionContext) -> NextProcess {
+ let read_ctx = ::mingling::ShellContext::try_from(prev.inner);
+ match read_ctx {
+ Ok(ctx) => {
+ let suggest = ::mingling::CompletionHelper::exec_completion::<#name>(&ctx);
+ CompletionSuggest::new((ctx, suggest)).to_render()
+ }
+ Err(_) => std::process::exit(1),
+ }
+ }
+ };
+
+ #[cfg(not(feature = "async"))]
+ let fn_exec_comp = quote! {
+ #[::mingling::macros::chain(#name)]
+ pub fn __exec_completion(prev: CompletionContext) -> NextProcess {
+ let read_ctx = ::mingling::ShellContext::try_from(prev.inner);
+ match read_ctx {
+ Ok(ctx) => {
+ let suggest = ::mingling::CompletionHelper::exec_completion::<#name>(&ctx);
+ CompletionSuggest::new((ctx, suggest)).to_render()
+ }
+ Err(_) => std::process::exit(1),
+ }
+ }
+ };
+
let comp_dispatcher = quote! {
#[allow(unused)]
use __completion_gen::*;
@@ -144,17 +174,7 @@ pub fn program_gen_completion(input: TokenStream) -> TokenStream {
CompletionSuggest = (::mingling::ShellContext, ::mingling::Suggest)
);
- #[::mingling::macros::chain(#name)]
- pub async fn __exec_completion(prev: CompletionContext) -> NextProcess {
- let read_ctx = ::mingling::ShellContext::try_from(prev.inner);
- match read_ctx {
- Ok(ctx) => {
- let suggest = ::mingling::CompletionHelper::exec_completion::<#name>(&ctx);
- CompletionSuggest::new((ctx, suggest)).to_render()
- }
- Err(_) => std::process::exit(1),
- }
- }
+ #fn_exec_comp
::mingling::macros::register_type!(CompletionContext);