diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-05-02 01:38:36 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-05-02 01:40:11 +0800 |
| commit | 81be96847833bd443ddb157cedb7939d8ffcc150 (patch) | |
| tree | b8f476d4430ed435f3ac93a1553219a349c0baca /mingling_macros | |
| parent | 1da9fc6103c06015942cf6c06f5fe015479c2706 (diff) | |
Enforce `NextProcess` return type in chain functions and update examples
Diffstat (limited to 'mingling_macros')
| -rw-r--r-- | mingling_macros/src/chain.rs | 38 | ||||
| -rw-r--r-- | mingling_macros/src/lib.rs | 14 |
2 files changed, 44 insertions, 8 deletions
diff --git a/mingling_macros/src/chain.rs b/mingling_macros/src/chain.rs index a91949d..e7b2db2 100644 --- a/mingling_macros/src/chain.rs +++ b/mingling_macros/src/chain.rs @@ -1,7 +1,9 @@ use proc_macro::TokenStream; use quote::{ToTokens, quote}; use syn::spanned::Spanned; -use syn::{FnArg, Ident, ItemFn, Pat, PatType, Signature, Type, TypePath, parse_macro_input}; +use syn::{ + FnArg, Ident, ItemFn, Pat, PatType, ReturnType, Signature, Type, TypePath, parse_macro_input, +}; /// Extracts the previous type and parameter name from function arguments fn extract_previous_info(sig: &Signature) -> syn::Result<(Pat, TypePath)> { @@ -67,6 +69,40 @@ pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream { } } + // Check that return type is NextProcess + let return_type = &input_fn.sig.output; + match return_type { + ReturnType::Type(_, ty) => { + // Check if the return type is NextProcess + match &**ty { + Type::Path(type_path) => { + let last_segment = type_path.path.segments.last().unwrap(); + if last_segment.ident.to_string() != "NextProcess" { + return syn::Error::new( + ty.span(), + "Chain function must return `NextProcess`", + ) + .to_compile_error() + .into(); + } + } + _ => { + return syn::Error::new(ty.span(), "Chain function must return `NextProcess`") + .to_compile_error() + .into(); + } + } + } + ReturnType::Default => { + return syn::Error::new( + input_fn.sig.span(), + "Chain function must specify a return type (must be `NextProcess`)", + ) + .to_compile_error() + .into(); + } + } + // Extract the previous type and parameter name from function arguments let (prev_param, previous_type) = match extract_previous_info(&input_fn.sig) { Ok(info) => info, diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs index 70a5c3e..818cda6 100644 --- a/mingling_macros/src/lib.rs +++ b/mingling_macros/src/lib.rs @@ -316,14 +316,14 @@ pub fn r_println(input: TokenStream) -> TokenStream { /// ```rust,ignore /// // Default program (ThisProgram): /// #[chain] -/// fn my_step(prev: InputType) -> ChainProcess<ThisProgram> { +/// fn my_step(prev: InputType) -> NextProcess { /// // transform `prev`... /// OutputType::new(result).to_render() /// } /// /// // Explicit program name: /// #[chain(MyProgram)] -/// fn my_step(prev: InputType) -> ChainProcess<MyProgram> { +/// fn my_step(prev: InputType) -> NextProcess { /// // ... /// } /// ``` @@ -336,7 +336,7 @@ pub fn r_println(input: TokenStream) -> TokenStream { /// pack!(MyOutput = String); /// /// #[chain] -/// fn greet(prev: HelloEntry) -> ChainProcess<ThisProgram> { +/// fn greet(prev: HelloEntry) -> NextProcess { /// let name = prev.first().cloned().unwrap_or_else(|| "World".to_string()); /// MyOutput::new(name).to_render() /// } @@ -350,7 +350,7 @@ pub fn r_println(input: TokenStream) -> TokenStream { /// pack!(MyOutput = String); /// /// #[chain] -/// async fn greet(prev: HelloEntry) -> ChainProcess<ThisProgram> { +/// async fn greet(prev: HelloEntry) -> NextProcess { /// let name = prev.first().cloned().unwrap_or_else(|| "World".to_string()); /// some_async_fn(&name).await; /// MyOutput::new(name).to_render() @@ -360,7 +360,7 @@ pub fn r_println(input: TokenStream) -> TokenStream { /// # Requirements /// /// - The function must have exactly **one** parameter (the previous type in the chain). -/// - The function must return `ChainProcess<ProgramName>` (or `impl Into<ChainProcess<ProgramName>>`). +/// - The function must return `NextProcess` (the type alias generated by `gen_program!`, which equals `ChainProcess<ProgramName>`). /// - With the `async` feature, async functions are supported; without it, async functions are rejected. #[proc_macro_attribute] pub fn chain(attr: TokenStream, item: TokenStream) -> TokenStream { @@ -857,7 +857,7 @@ pub fn program_comp_gen(input: TokenStream) -> TokenStream { #[cfg(feature = "async")] let fn_exec_comp = quote! { #[::mingling::macros::chain(#name)] - pub async fn __exec_completion(prev: CompletionContext) -> ::mingling::ChainProcess<#name> { + pub async fn __exec_completion(prev: CompletionContext) -> NextProcess { let read_ctx = ::mingling::ShellContext::try_from(prev.inner); match read_ctx { Ok(ctx) => { @@ -872,7 +872,7 @@ pub fn program_comp_gen(input: TokenStream) -> TokenStream { #[cfg(not(feature = "async"))] let fn_exec_comp = quote! { #[::mingling::macros::chain(#name)] - pub fn __exec_completion(prev: CompletionContext) -> ::mingling::ChainProcess<#name> { + pub fn __exec_completion(prev: CompletionContext) -> NextProcess { let read_ctx = ::mingling::ShellContext::try_from(prev.inner); match read_ctx { Ok(ctx) => { |
