From ec88e6a1682740c64cb3735016632542e69f9e53 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Sun, 19 Jul 2026 10:53:33 +0800 Subject: feat(macros): add Routable trait and update route! macro Introduce a `Routable` trait with `to_chain` and `to_render` methods, replacing direct `Grouped` usage in the `route!` macro so error branches correctly route through the rendering pipeline --- mingling_core/src/any/group.rs | 16 +++++++++++++- mingling_core/src/asset.rs | 3 +++ mingling_core/src/asset/routable.rs | 22 +++++++++++++++++++ mingling_core/src/lib.rs | 1 + mingling_macros/src/lib.rs | 43 ++++++++++++++++++++++++++++++------- 5 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 mingling_core/src/asset/routable.rs diff --git a/mingling_core/src/any/group.rs b/mingling_core/src/any/group.rs index 14663db..90ef9fc 100644 --- a/mingling_core/src/any/group.rs +++ b/mingling_core/src/any/group.rs @@ -1,4 +1,4 @@ -use crate::{AnyOutput, ChainProcess}; +use crate::{AnyOutput, ChainProcess, ProgramCollect, Routable}; /// Used to mark a type with a unique enum ID, assisting dynamic dispatch /// @@ -32,3 +32,17 @@ where AnyOutput::new(self).route_renderer() } } + +impl Routable for T +where + C: ProgramCollect, + T: Grouped + Send, +{ + fn to_chain(self) -> ChainProcess { + T::to_chain(self) + } + + fn to_render(self) -> ChainProcess { + T::to_render(self) + } +} diff --git a/mingling_core/src/asset.rs b/mingling_core/src/asset.rs index b1fd617..9b9a5d4 100644 --- a/mingling_core/src/asset.rs +++ b/mingling_core/src/asset.rs @@ -21,3 +21,6 @@ pub mod node; #[doc(hidden)] pub mod renderer; + +#[doc(hidden)] +pub mod routable; diff --git a/mingling_core/src/asset/routable.rs b/mingling_core/src/asset/routable.rs new file mode 100644 index 0000000..24b7bb1 --- /dev/null +++ b/mingling_core/src/asset/routable.rs @@ -0,0 +1,22 @@ +use crate::ChainProcess; + +/// Provides routing capabilities for converting an item into a `ChainProcess` +/// directed to either the chain or render processing pipeline. +/// +/// This trait enables items to be dispatched to different processing routes +/// (chain or render) by wrapping them into an `AnyOutput` and routing them +/// through the appropriate pipeline. +pub trait Routable +where + Self: Sized + 'static, +{ + /// Converts the routable item into a `ChainProcess` directed to the chain route. + /// + /// This wraps the item into an `AnyOutput` and routes it to the chain processing pipeline. + fn to_chain(self) -> ChainProcess; + + /// Converts the routable item into a `ChainProcess` directed to the render route. + /// + /// This wraps the item into an `AnyOutput` and routes it to the render processing pipeline. + fn to_render(self) -> ChainProcess; +} diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs index 3c2cf9b..4996b19 100644 --- a/mingling_core/src/lib.rs +++ b/mingling_core/src/lib.rs @@ -36,6 +36,7 @@ pub use crate::asset::help::*; pub use crate::asset::lazy_resource::*; pub use crate::asset::node::*; pub use crate::asset::renderer::*; +pub use crate::asset::routable::*; /// All error types of `Mingling` pub mod error { diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs index 77e1137..ea33577 100644 --- a/mingling_macros/src/lib.rs +++ b/mingling_macros/src/lib.rs @@ -521,20 +521,25 @@ pub fn pack_err_structural(input: TokenStream) -> TokenStream { pack_err::pack_err_structural(input) } -/// Early-returns an error from a `Result`, converting the `Ok` branch to a -/// `ChainProcess`. +/// Early-returns the error from a `Result`, converting the `Ok` branch to the +/// next chain process value. /// /// This macro is equivalent to: /// ```rust,ignore /// match expr { /// Ok(r) => r, -/// Err(e) => return ::mingling::Grouped::to_chain(e), +/// Err(e) => return ::mingling::Routable::to_chain(e), /// } /// ``` /// -/// It is useful inside chain functions where you have a `Result` -/// where both types implement `Grouped` and want to propagate the error case -/// as an early return via `Grouped::to_chain()`. +/// It is useful inside chain functions where you have a `Result` +/// where both types implement `Routable` and you want to propagate the error case +/// as an early return via `Routable::to_chain()`. +/// +/// The key difference from a simple `?` operator is that `route!` converts **both** +/// the success and error types into the chain process — the `Ok` value is unwrapped +/// directly, while the `Err` value is converted via `Routable::to_chain()` and +/// returned early. /// /// # Example /// @@ -542,7 +547,7 @@ pub fn pack_err_structural(input: TokenStream) -> TokenStream { /// use mingling::macros::{chain, route}; /// /// #[chain] -/// fn process(prev: SomeEntry) -> ChainProcess { +/// fn process(prev: SomeEntry) -> Next { /// let value = route!(current_dir().map_err(|e| ErrorEntry::new(e.to_string_lossy().to_string()))); /// // value is the PathBuf from current_dir() /// value.to_chain() @@ -555,7 +560,7 @@ pub fn route(input: TokenStream) -> TokenStream { let expanded = quote! { match #expr { Ok(r) => r, - Err(e) => return ::mingling::Grouped::to_chain(e), + Err(e) => return ::mingling::Routable::to_chain(e), } }; TokenStream::from(expanded) @@ -1446,8 +1451,30 @@ pub fn gen_program(_input: TokenStream) -> TokenStream { let comp_gen = quote! {}; TokenStream::from(quote! { + /// Alias for the current program type `crate::ThisProgram` pub type Next = ::mingling::ChainProcess; + impl ::mingling::Routable for ::mingling::ChainProcess + { + fn to_chain(self) -> ::mingling::ChainProcess { + match self { + ::mingling::ChainProcess::Ok((any, _)) => { + ::mingling::ChainProcess::Ok((any, mingling::NextProcess::Chain)) + } + other => other, + } + } + + fn to_render(self) -> ::mingling::ChainProcess { + match self { + ::mingling::ChainProcess::Ok((any, _)) => { + ::mingling::ChainProcess::Ok((any, mingling::NextProcess::Renderer)) + } + other => other, + } + } + } + #comp_gen ::mingling::macros::program_fallback_gen!(); ::mingling::macros::program_final_gen!(); -- cgit