aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-07-18 01:59:19 +0800
committer魏曹先生 <1992414357@qq.com>2026-07-18 01:59:19 +0800
commit6f2053e27a4dda5d6208b27bd652a9e861173e59 (patch)
tree9d5862f942dd2bbb751bfcc11f49614f11c21705
parentf5a4cebde2f12eb980de73ea41eb8d9e133ae49a (diff)
feat(macros): relax `#[help]` return type to accept `Into<RenderResult>`
-rw-r--r--CHANGELOG.md20
-rw-r--r--mingling_macros/src/help.rs45
-rw-r--r--mingling_macros/src/lib.rs2
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