diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-07-18 01:59:19 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-07-18 01:59:19 +0800 |
| commit | 6f2053e27a4dda5d6208b27bd652a9e861173e59 (patch) | |
| tree | 9d5862f942dd2bbb751bfcc11f49614f11c21705 | |
| parent | f5a4cebde2f12eb980de73ea41eb8d9e133ae49a (diff) | |
feat(macros): relax `#[help]` return type to accept `Into<RenderResult>`
| -rw-r--r-- | CHANGELOG.md | 20 | ||||
| -rw-r--r-- | mingling_macros/src/help.rs | 45 | ||||
| -rw-r--r-- | mingling_macros/src/lib.rs | 2 |
3 files changed, 34 insertions, 33 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index fb0cc85..e85058c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -141,6 +141,26 @@ None } ``` +6. **[`macros:help`]** Removed the restriction that `#[help]` functions must return `::mingling::RenderResult`. The `#[help]` macro now accepts any return type (including no return type), and automatically converts the return value to `RenderResult` via `Into::into`. + + - Functions returning `RenderResult` work as before. + - Functions returning other types (e.g., `String`, `i32`, `()`) are converted via `Into<RenderResult>`. + - Functions with no return type (`-> ()` or omitted) return `()` which is converted to an empty `RenderResult` via `From<()>`. + + This makes `#[help]` consistent with the `#[renderer]` macro's ergonomic return type handling introduced in item 5 above. + + ```rust + #[help] + fn help_greeting(prev: EntryGreeting) -> String { + format!("Displaying help for greeting: {}", *prev) + } + + #[help] + fn help_void(prev: EntryVoid) { + // side effects only, returns empty RenderResult + } + ``` + #### **BREAKING CHANGES** (API CHANGES): 1. **[`macros:renderer`]** **[`macros:help`]** Removed `r_println!` and `r_print!` macros. The `#[renderer]` and `#[help]` macros no longer implicitly inject an internal `RenderResult` variable or provide `r_println!` / `r_print!` macros. diff --git a/mingling_macros/src/help.rs b/mingling_macros/src/help.rs index 1903d07..6e0d12e 100644 --- a/mingling_macros/src/help.rs +++ b/mingling_macros/src/help.rs @@ -1,34 +1,16 @@ use proc_macro::TokenStream; use quote::{ToTokens, quote}; use syn::spanned::Spanned; -use syn::{Ident, ItemFn, ReturnType, Type, TypePath, parse_macro_input}; +use syn::{Ident, ItemFn, ReturnType, Signature, TypePath, parse_macro_input}; use crate::get_global_set; use crate::res_injection::{extract_args_info, generate_immut_resource_bindings}; -/// Validates that the function returns `::mingling::RenderResult`. -fn validate_render_result_return(sig: &syn::Signature) -> syn::Result<()> { +/// Extracts the user's return type, returning `None` for no return type. +fn extract_user_return_type(sig: &Signature) -> Option<proc_macro2::TokenStream> { match &sig.output { - ReturnType::Type(_, ty) => match &**ty { - Type::Path(type_path) => { - let last_seg = type_path.path.segments.last().map(|s| s.ident.to_string()); - match last_seg.as_deref() { - Some("RenderResult") => Ok(()), - _ => Err(syn::Error::new( - ty.span(), - "Help function must return `RenderResult`", - )), - } - } - _ => Err(syn::Error::new( - ty.span(), - "Help function must return `RenderResult`", - )), - }, - ReturnType::Default => Err(syn::Error::new( - sig.span(), - "Help function must have a return type `-> RenderResult`", - )), + ReturnType::Type(_, ty) => Some(quote! { #ty }), + ReturnType::Default => None, } } @@ -49,10 +31,8 @@ pub fn help_attr(item: TokenStream) -> TokenStream { Err(e) => return e.to_compile_error().into(), }; - // Validate return type is RenderResult - if let Err(e) = validate_render_result_return(&input_fn.sig) { - return e.to_compile_error().into(); - } + // Determine the user's return type for preserving the original function + let user_return_type = extract_user_return_type(&input_fn.sig); // Get the function body let fn_body = &input_fn.block; @@ -69,8 +49,8 @@ pub fn help_attr(item: TokenStream) -> TokenStream { let fn_name = &input_fn.sig.ident; // Get original inputs to keep the original function - let original_inputs = input_fn.sig.inputs.clone(); + let original_return_type = user_return_type.clone().unwrap_or(quote! { () }); // Generate internal name using snake_case let internal_name = format!( @@ -149,17 +129,18 @@ pub fn help_attr(item: TokenStream) -> TokenStream { type Entry = #entry_type; fn render_help(#prev_param: Self::Entry) -> ::mingling::RenderResult { - #help_render_body + let __help_result = { #help_render_body }; + ::std::convert::Into::into(__help_result) } } ::mingling::macros::register_help!(#entry_type, #struct_name); // Keep the original function unchanged - + #[allow(dead_code)] #(#fn_attrs)* - #vis fn #fn_name(#original_inputs) -> ::mingling::RenderResult { - #fn_body + #vis fn #fn_name(#original_inputs) -> #original_return_type { + #(#fn_body_stmts)* } }; diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs index e9fc327..9419f39 100644 --- a/mingling_macros/src/lib.rs +++ b/mingling_macros/src/lib.rs @@ -1235,7 +1235,7 @@ pub fn register_dispatcher(input: TokenStream) -> TokenStream { /// /// - The function must have exactly one parameter (the entry type to provide help for). /// - The parameter type must be a single-segment type path (e.g., `MyEntry`, not `other::MyEntry`). -/// - The function must return `RenderResult`. +/// - The function may return `RenderResult`, `()`, or any type that implements `Into<RenderResult>`. /// - The function cannot be async. /// /// # See also |
