diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-04-19 00:31:05 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-04-19 00:31:05 +0800 |
| commit | 532f4ceba2bddb1c84d2e0bdd69808a3ebd5ca4a (patch) | |
| tree | 043514a2aca670d8b2398726b17aab1066938ba1 /mingling_macros/src | |
| parent | ecc1329bbd31cd98fa9b4c2f25a3114f133987ae (diff) | |
Make async an optional feature
Diffstat (limited to 'mingling_macros/src')
| -rw-r--r-- | mingling_macros/src/chain.rs | 102 | ||||
| -rw-r--r-- | mingling_macros/src/lib.rs | 42 |
2 files changed, 103 insertions, 41 deletions
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); |
