summaryrefslogtreecommitdiff
path: root/mingling_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_macros/src')
-rw-r--r--mingling_macros/src/README.txt12
-rw-r--r--mingling_macros/src/chain.rs97
-rw-r--r--mingling_macros/src/dispatcher_chain.rs219
-rw-r--r--mingling_macros/src/lib.rs58
-rw-r--r--mingling_macros/src/pack.rs158
-rw-r--r--mingling_macros/src/renderer.rs11
6 files changed, 440 insertions, 115 deletions
diff --git a/mingling_macros/src/README.txt b/mingling_macros/src/README.txt
new file mode 100644
index 0000000..a882bd0
--- /dev/null
+++ b/mingling_macros/src/README.txt
@@ -0,0 +1,12 @@
+*Listen up*, this is a messy macro written by AI.
+It works, but it looks like expired spaghetti and smells like freshly laid shit.
+
+But the general idea is mostly right. If I'm in a good mood, this code will definitely need a refactor.
+
+----------------------------------------------------
+Chinese original version:
+
+*听着*,这是一坨由 AI 写的乱七八糟的宏
+它能用,但是看起来就像过期的意大利面,闻起来就像刚拉出来的新鲜的屎
+
+不过思路大抵是对的,如果心情好这坨代码肯定要重构
diff --git a/mingling_macros/src/chain.rs b/mingling_macros/src/chain.rs
index 1fddd3b..f8b1e1c 100644
--- a/mingling_macros/src/chain.rs
+++ b/mingling_macros/src/chain.rs
@@ -1,10 +1,10 @@
//! Chain Attribute Macro Implementation
//!
-//! This module provides the `#[chain]` attribute macro for automatically
+//! This module provides the `#[chain(Group)]` attribute macro for automatically
//! generating structs that implement the `Chain` trait from async functions.
use proc_macro::TokenStream;
-use quote::quote;
+use quote::{ToTokens, quote};
use syn::spanned::Spanned;
use syn::{
FnArg, Ident, ItemFn, Pat, PatType, ReturnType, Signature, Type, TypePath, parse_macro_input,
@@ -59,7 +59,18 @@ fn extract_return_type(sig: &Signature) -> syn::Result<TypePath> {
}
}
-pub fn chain_attr(item: TokenStream) -> TokenStream {
+pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
+ // Parse the attribute arguments (e.g., MyProgram from #[chain(MyProgram)])
+ // If no argument is provided, use DefaultProgram
+ let (group_name, use_crate_prefix) = if attr.is_empty() {
+ (
+ Ident::new("DefaultProgram", proc_macro2::Span::call_site()),
+ true,
+ )
+ } else {
+ (parse_macro_input!(attr as Ident), false)
+ };
+
// Parse the function item
let input_fn = parse_macro_input!(item as ItemFn);
@@ -82,11 +93,22 @@ pub fn chain_attr(item: TokenStream) -> TokenStream {
Err(e) => return e.to_compile_error().into(),
};
+ // Ensure the return type is named "GroupProcess"
+ if return_type.path.segments.last().unwrap().ident != "GroupProcess" {
+ return syn::Error::new(
+ return_type.span(),
+ "Return type must be 'mingling::marker::GroupProcess'",
+ )
+ .to_compile_error()
+ .into();
+ }
+
// Get the function body
let fn_body = &input_fn.block;
// Get function attributes (excluding the chain attribute)
let mut fn_attrs = input_fn.attrs.clone();
+
// Remove any #[chain(...)] attributes to avoid infinite recursion
fn_attrs.retain(|attr| !attr.path().is_ident("chain"));
@@ -101,23 +123,55 @@ pub fn chain_attr(item: TokenStream) -> TokenStream {
let struct_name = Ident::new(&pascal_case_name, fn_name.span());
// Generate the struct and implementation
- let expanded = quote! {
- #(#fn_attrs)*
- #vis struct #struct_name;
-
- impl ::mingling::Chain for #struct_name {
- type Previous = #previous_type;
+ let expanded = if use_crate_prefix {
+ quote! {
+ #(#fn_attrs)*
+ #vis struct #struct_name;
+
+ impl ::mingling::Chain<DefaultProgram> for #struct_name {
+ type Previous = #previous_type;
+
+ async fn proc(#prev_param: Self::Previous) ->
+ ::mingling::ChainProcess<DefaultProgram>
+ {
+ let _ = GroupProcess;
+ // Call the original function
+ #fn_name(#prev_param).await
+ }
+ }
- async fn proc(#prev_param: Self::Previous) -> #return_type {
- // Call the original function
- #fn_name(#prev_param).await
+ // Keep the original function for internal use
+ #(#fn_attrs)*
+ #vis async fn #fn_name(#prev_param: #previous_type)
+ -> ::mingling::ChainProcess<DefaultProgram>
+ {
+ #fn_body
}
}
+ } else {
+ quote! {
+ #(#fn_attrs)*
+ #vis struct #struct_name;
+
+ impl ::mingling::Chain<#group_name> for #struct_name {
+ type Previous = #previous_type;
+
+ async fn proc(#prev_param: Self::Previous) ->
+ ::mingling::ChainProcess<#group_name>
+ {
+ let _ = GroupProcess;
+ // Call the original function
+ #fn_name(#prev_param).await
+ }
+ }
- // Keep the original function for internal use
- #(#fn_attrs)*
- #vis async fn #fn_name(#prev_param: #previous_type) -> #return_type {
- #fn_body
+ // Keep the original function for internal use
+ #(#fn_attrs)*
+ #vis async fn #fn_name(#prev_param: #previous_type)
+ -> ::mingling::ChainProcess<#group_name>
+ {
+ #fn_body
+ }
}
};
@@ -127,21 +181,28 @@ pub fn chain_attr(item: TokenStream) -> TokenStream {
};
let chain_exist_entry = quote! {
- id if id == std::any::TypeId::of::<#previous_type>() => true,
+ Self::#previous_type => true,
};
let mut chains = crate::CHAINS.lock().unwrap();
let mut chain_exist = crate::CHAINS_EXIST.lock().unwrap();
+ let mut packed_types = crate::PACKED_TYPES.lock().unwrap();
let chain_entry = chain_entry.to_string();
let chain_exist_entry = chain_exist_entry.to_string();
+ let previous_type_str = previous_type.to_token_stream().to_string();
if !chains.contains(&chain_entry) {
chains.push(chain_entry);
}
- if !chains.contains(&chain_exist_entry) {
+
+ if !chain_exist.contains(&chain_exist_entry) {
chain_exist.push(chain_exist_entry);
}
+ if !packed_types.contains(&previous_type_str) {
+ packed_types.push(previous_type_str);
+ }
+
expanded.into()
}
diff --git a/mingling_macros/src/dispatcher_chain.rs b/mingling_macros/src/dispatcher_chain.rs
index 57c11a3..dc02c33 100644
--- a/mingling_macros/src/dispatcher_chain.rs
+++ b/mingling_macros/src/dispatcher_chain.rs
@@ -8,53 +8,123 @@ use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{Ident, Result as SynResult, Token};
-/// Parses input in the format: `"command_name", CommandStruct => ChainStruct`
-struct DispatcherChainInput {
- command_name: syn::LitStr,
- command_struct: Ident,
- pack: Ident,
+enum DispatcherChainInput {
+ Explicit {
+ group_name: Ident,
+ command_name: syn::LitStr,
+ command_struct: Ident,
+ pack: Ident,
+ },
+ Default {
+ command_name: syn::LitStr,
+ command_struct: Ident,
+ pack: Ident,
+ },
}
impl Parse for DispatcherChainInput {
fn parse(input: ParseStream) -> SynResult<Self> {
- let command_name = input.parse()?;
- input.parse::<Token![,]>()?;
- let command_struct = input.parse()?;
- input.parse::<Token![=>]>()?;
- let pack = input.parse()?;
-
- Ok(DispatcherChainInput {
- command_name,
- command_struct,
- pack,
- })
+ let lookahead = input.lookahead1();
+
+ if lookahead.peek(Ident) && input.peek2(Token![,]) && input.peek3(syn::LitStr) {
+ let group_name = input.parse()?;
+ input.parse::<Token![,]>()?;
+ let command_name = input.parse()?;
+ input.parse::<Token![,]>()?;
+ let command_struct = input.parse()?;
+ input.parse::<Token![=>]>()?;
+ let pack = input.parse()?;
+
+ Ok(DispatcherChainInput::Explicit {
+ group_name,
+ command_name,
+ command_struct,
+ pack,
+ })
+ } else if lookahead.peek(syn::LitStr) {
+ // Default format: "command_name", CommandStruct => ChainStruct
+ let command_name = input.parse()?;
+ input.parse::<Token![,]>()?;
+ let command_struct = input.parse()?;
+ input.parse::<Token![=>]>()?;
+ let pack = input.parse()?;
+
+ Ok(DispatcherChainInput::Default {
+ command_name,
+ command_struct,
+ pack,
+ })
+ } else {
+ Err(lookahead.error())
+ }
}
}
pub fn dispatcher_chain(input: TokenStream) -> TokenStream {
- let DispatcherChainInput {
- command_name,
- command_struct,
- pack,
- } = syn::parse_macro_input!(input as DispatcherChainInput);
+ // Parse the input
+ let dispatcher_input = syn::parse_macro_input!(input as DispatcherChainInput);
- let command_name_str = command_name.value();
-
- let expanded = quote! {
- #[derive(Debug, Default)]
- pub struct #command_struct;
+ // Determine if we're using default or explicit group
+ let (group_name, command_name, command_struct, pack, use_default) = match dispatcher_input {
+ DispatcherChainInput::Explicit {
+ group_name,
+ command_name,
+ command_struct,
+ pack,
+ } => (group_name, command_name, command_struct, pack, false),
+ DispatcherChainInput::Default {
+ command_name,
+ command_struct,
+ pack,
+ } => (
+ Ident::new("DefaultProgram", proc_macro2::Span::call_site()),
+ command_name,
+ command_struct,
+ pack,
+ true,
+ ),
+ };
- ::mingling::macros::pack!(#pack = Vec<String>);
+ let command_name_str = command_name.value();
- impl ::mingling::Dispatcher for #command_struct {
- fn node(&self) -> ::mingling::Node {
- ::mingling::macros::node!(#command_name_str)
+ let expanded = if use_default {
+ // For default case, use DefaultProgram
+ quote! {
+ #[derive(Debug, Default)]
+ pub struct #command_struct;
+
+ ::mingling::macros::pack!(DefaultProgram, #pack = Vec<String>);
+
+ impl ::mingling::Dispatcher<DefaultProgram> for #command_struct {
+ fn node(&self) -> ::mingling::Node {
+ ::mingling::macros::node!(#command_name_str)
+ }
+ fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess<DefaultProgram> {
+ #pack::new(args).to_chain()
+ }
+ fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher<DefaultProgram>> {
+ Box::new(#command_struct)
+ }
}
- fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess {
- #pack::new(args).to_chain()
- }
- fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher> {
- Box::new(#command_struct)
+ }
+ } else {
+ // For explicit case, use the provided group_name
+ quote! {
+ #[derive(Debug, Default)]
+ pub struct #command_struct;
+
+ ::mingling::macros::pack!(#group_name, #pack = Vec<String>);
+
+ impl ::mingling::Dispatcher<#group_name> for #command_struct {
+ fn node(&self) -> ::mingling::Node {
+ ::mingling::macros::node!(#command_name_str)
+ }
+ fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess<#group_name> {
+ #pack::new(args).to_chain()
+ }
+ fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher<#group_name>> {
+ Box::new(#command_struct)
+ }
}
}
};
@@ -63,29 +133,70 @@ pub fn dispatcher_chain(input: TokenStream) -> TokenStream {
}
pub fn dispatcher_render(input: TokenStream) -> TokenStream {
- let DispatcherChainInput {
- command_name,
- command_struct,
- pack,
- } = syn::parse_macro_input!(input as DispatcherChainInput);
+ // Parse the input
+ let dispatcher_input = syn::parse_macro_input!(input as DispatcherChainInput);
- let command_name_str = command_name.value();
-
- let expanded = quote! {
- #[derive(Debug, Default)]
- pub struct #command_struct;
+ // Determine if we're using default or explicit group
+ let (group_name, command_name, command_struct, pack, use_default) = match dispatcher_input {
+ DispatcherChainInput::Explicit {
+ group_name,
+ command_name,
+ command_struct,
+ pack,
+ } => (group_name, command_name, command_struct, pack, false),
+ DispatcherChainInput::Default {
+ command_name,
+ command_struct,
+ pack,
+ } => (
+ Ident::new("DefaultProgram", proc_macro2::Span::call_site()),
+ command_name,
+ command_struct,
+ pack,
+ true,
+ ),
+ };
- ::mingling::macros::pack!(#pack = Vec<String>);
+ let command_name_str = command_name.value();
- impl ::mingling::Dispatcher for #command_struct {
- fn node(&self) -> ::mingling::Node {
- ::mingling::macros::node!(#command_name_str)
+ let expanded = if use_default {
+ // For default case, use DefaultProgram
+ quote! {
+ #[derive(Debug, Default)]
+ pub struct #command_struct;
+
+ ::mingling::macros::pack!(DefaultProgram, #pack = Vec<String>);
+
+ impl ::mingling::Dispatcher for #command_struct {
+ fn node(&self) -> ::mingling::Node {
+ ::mingling::macros::node!(#command_name_str)
+ }
+ fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess {
+ #pack::new(args).to_render()
+ }
+ fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher> {
+ Box::new(#command_struct)
+ }
}
- fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess {
- #pack::new(args).to_render()
- }
- fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher> {
- Box::new(#command_struct)
+ }
+ } else {
+ // For explicit case, use the provided group_name
+ quote! {
+ #[derive(Debug, Default)]
+ pub struct #command_struct;
+
+ ::mingling::macros::pack!(#group_name, #pack = Vec<String>);
+
+ impl ::mingling::Dispatcher for #command_struct {
+ fn node(&self) -> ::mingling::Node {
+ ::mingling::macros::node!(#command_name_str)
+ }
+ fn begin(&self, args: Vec<String>) -> ::mingling::ChainProcess {
+ #pack::new(args).to_render()
+ }
+ fn clone_dispatcher(&self) -> Box<dyn ::mingling::Dispatcher> {
+ Box::new(#command_struct)
+ }
}
}
};
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index 05bcf0b..832b45a 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -19,6 +19,7 @@ use once_cell::sync::Lazy;
use std::sync::Mutex;
// Global variable declarations for storing chain and renderer mappings
+pub(crate) static PACKED_TYPES: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(Vec::new()));
pub(crate) static CHAINS: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(Vec::new()));
pub(crate) static RENDERERS: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(Vec::new()));
pub(crate) static CHAINS_EXIST: Lazy<Mutex<Vec<String>>> = Lazy::new(|| Mutex::new(Vec::new()));
@@ -55,8 +56,8 @@ pub fn r_println(input: TokenStream) -> TokenStream {
}
#[proc_macro_attribute]
-pub fn chain(_attr: TokenStream, item: TokenStream) -> TokenStream {
- chain::chain_attr(item)
+pub fn chain(attr: TokenStream, item: TokenStream) -> TokenStream {
+ chain::chain_attr(attr, item)
}
#[proc_macro_attribute]
@@ -65,14 +66,24 @@ pub fn renderer(_attr: TokenStream, item: TokenStream) -> TokenStream {
}
#[proc_macro]
-pub fn program(input: TokenStream) -> TokenStream {
- let name = parse_macro_input!(input as Ident);
+pub fn gen_program(input: TokenStream) -> TokenStream {
+ let name = if input.is_empty() {
+ Ident::new("DefaultProgram", proc_macro2::Span::call_site())
+ } else {
+ parse_macro_input!(input as Ident)
+ };
+ let packed_types = PACKED_TYPES.lock().unwrap().clone();
let renderers = RENDERERS.lock().unwrap().clone();
let chains = CHAINS.lock().unwrap().clone();
let renderer_exist = RENDERERS_EXIST.lock().unwrap().clone();
let chain_exist = CHAINS_EXIST.lock().unwrap().clone();
+ let packed_types: Vec<proc_macro2::TokenStream> = packed_types
+ .iter()
+ .map(|s| syn::parse_str::<proc_macro2::TokenStream>(s).unwrap())
+ .collect();
+
let renderer_tokens: Vec<proc_macro2::TokenStream> = renderers
.iter()
.map(|s| syn::parse_str::<proc_macro2::TokenStream>(s).unwrap())
@@ -94,23 +105,50 @@ pub fn program(input: TokenStream) -> TokenStream {
.collect();
let expanded = quote! {
- pub struct #name;
+ ::mingling::macros::pack!(#name, RendererNotFound = String);
+ ::mingling::macros::pack!(#name, DispatcherNotFound = Vec<String>);
+
+ #[derive(Debug, Default, PartialEq, Eq, Clone)]
+ #[repr(u32)]
+ pub enum #name {
+ #[default]
+ __FallBack,
+ DispatcherNotFound,
+ RendererNotFound,
+ #(#packed_types),*
+ }
+
+ impl ::std::fmt::Display for #name {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ match self {
+ #name::__FallBack => write!(f, "__FallBack"),
+ #name::DispatcherNotFound => {
+ write!(f, "DispatcherNotFound")
+ }
+ #name::RendererNotFound => {
+ write!(f, "RendererNotFound")
+ }
+ #(#name::#packed_types => write!(f, stringify!(#packed_types)),)*
+ }
+ }
+ }
impl ::mingling::ProgramCollect for #name {
+ type Enum = #name;
::mingling::__dispatch_program_renderers!(
#(#renderer_tokens)*
);
::mingling::__dispatch_program_chains!(
#(#chain_tokens)*
);
- fn has_renderer(any: &::mingling::AnyOutput) -> bool {
- match any.type_id {
+ fn has_renderer(any: &::mingling::AnyOutput<Self::Enum>) -> bool {
+ match any.member_id {
#(#renderer_exist_tokens)*
_ => false
}
}
- fn has_chain(any: &::mingling::AnyOutput) -> bool {
- match any.type_id {
+ fn has_chain(any: &::mingling::AnyOutput<Self::Enum>) -> bool {
+ match any.member_id {
#(#chain_exist_tokens)*
_ => false
}
@@ -118,7 +156,7 @@ pub fn program(input: TokenStream) -> TokenStream {
}
impl #name {
- pub fn new() -> ::mingling::Program<#name> {
+ pub fn new() -> ::mingling::Program<#name, #name> {
::mingling::Program::new()
}
}
diff --git a/mingling_macros/src/pack.rs b/mingling_macros/src/pack.rs
index bff67d4..c6a6c67 100644
--- a/mingling_macros/src/pack.rs
+++ b/mingling_macros/src/pack.rs
@@ -8,37 +8,80 @@ use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{Ident, Result as SynResult, Token, Type};
-/// Parses input in the format: `TypeName = InnerType`
-struct PackInput {
- type_name: Ident,
- inner_type: Type,
+enum PackInput {
+ Explicit {
+ group_name: Ident,
+ type_name: Ident,
+ inner_type: Type,
+ },
+ Default {
+ type_name: Ident,
+ inner_type: Type,
+ },
}
impl Parse for PackInput {
fn parse(input: ParseStream) -> SynResult<Self> {
- let type_name = input.parse()?;
- input.parse::<Token![=]>()?;
- let inner_type = input.parse()?;
+ // Try to parse as explicit format first: GroupName, TypeName = InnerType
+ let lookahead = input.lookahead1();
- Ok(PackInput {
- type_name,
- inner_type,
- })
+ if lookahead.peek(Ident) && input.peek2(Token![,]) {
+ // Explicit format: GroupName, TypeName = InnerType
+ let group_name = input.parse()?;
+ input.parse::<Token![,]>()?;
+ let type_name = input.parse()?;
+ input.parse::<Token![=]>()?;
+ let inner_type = input.parse()?;
+
+ Ok(PackInput::Explicit {
+ group_name,
+ type_name,
+ inner_type,
+ })
+ } else if lookahead.peek(Ident) && input.peek2(Token![=]) {
+ // Default format: TypeName = InnerType
+ let type_name = input.parse()?;
+ input.parse::<Token![=]>()?;
+ let inner_type = input.parse()?;
+
+ Ok(PackInput::Default {
+ type_name,
+ inner_type,
+ })
+ } else {
+ Err(lookahead.error())
+ }
}
}
pub fn pack(input: TokenStream) -> TokenStream {
- let PackInput {
- type_name,
- inner_type,
- } = syn::parse_macro_input!(input as PackInput);
+ // Parse the input
+ let pack_input = syn::parse_macro_input!(input as PackInput);
+
+ // Determine if we're using default or explicit group
+ let (group_name, type_name, inner_type, use_default) = match pack_input {
+ PackInput::Explicit {
+ group_name,
+ type_name,
+ inner_type,
+ } => (group_name, type_name, inner_type, false),
+ PackInput::Default {
+ type_name,
+ inner_type,
+ } => (
+ Ident::new("DefaultProgram", proc_macro2::Span::call_site()),
+ type_name,
+ inner_type,
+ true,
+ ),
+ };
// Generate the struct definition
#[cfg(not(feature = "serde"))]
let struct_def = quote! {
#[derive(Debug)]
pub struct #type_name {
- inner: #inner_type,
+ pub(crate) inner: #inner_type,
}
};
@@ -46,7 +89,7 @@ pub fn pack(input: TokenStream) -> TokenStream {
let struct_def = quote! {
#[derive(Debug, serde::Serialize)]
pub struct #type_name {
- inner: #inner_type,
+ pub(crate) inner: #inner_type,
}
};
@@ -120,42 +163,95 @@ pub fn pack(input: TokenStream) -> TokenStream {
};
let any_out_impl = quote! {
- impl Into<mingling::AnyOutput> for #type_name {
- fn into(self) -> mingling::AnyOutput {
+ impl Into<mingling::AnyOutput<#group_name>> for #type_name {
+ fn into(self) -> mingling::AnyOutput<#group_name> {
mingling::AnyOutput::new(self)
}
}
- impl Into<mingling::ChainProcess> for #type_name {
- fn into(self) -> mingling::ChainProcess {
+ impl Into<mingling::ChainProcess<#group_name>> for #type_name {
+ fn into(self) -> mingling::ChainProcess<#group_name> {
mingling::AnyOutput::new(self).route_chain()
}
}
impl #type_name {
/// Converts the wrapper type into a `ChainProcess` for chaining operations.
- pub fn to_chain(self) -> mingling::ChainProcess {
+ pub fn to_chain(self) -> mingling::ChainProcess<#group_name> {
mingling::AnyOutput::new(self).route_chain()
}
/// Converts the wrapper type into a `ChainProcess` for rendering operations.
- pub fn to_render(self) -> mingling::ChainProcess {
+ pub fn to_render(self) -> mingling::ChainProcess<#group_name> {
mingling::AnyOutput::new(self).route_renderer()
}
}
};
+ let group_impl = quote! {
+ impl ::mingling::Groupped<#group_name> for #type_name {
+ fn member_id() -> #group_name {
+ #group_name::#type_name
+ }
+ }
+ };
+
// Combine all implementations
- let expanded = quote! {
- #struct_def
+ let expanded = if use_default {
+ // For default case, use DefaultProgram
+ quote! {
+ #struct_def
+
+ #new_impl
+ #from_into_impl
+ #as_ref_impl
+ #deref_impl
+ #default_impl
+
+ impl Into<mingling::AnyOutput<DefaultProgram>> for #type_name {
+ fn into(self) -> mingling::AnyOutput<DefaultProgram> {
+ mingling::AnyOutput::new(self)
+ }
+ }
+
+ impl From<#type_name> for mingling::ChainProcess<DefaultProgram> {
+ fn from(value: #type_name) -> Self {
+ mingling::AnyOutput::new(value).route_chain()
+ }
+ }
- #new_impl
- #from_into_impl
- #as_ref_impl
- #deref_impl
- #default_impl
+ impl #type_name {
+ /// Converts the wrapper type into a `ChainProcess` for chaining operations.
+ pub fn to_chain(self) -> mingling::ChainProcess<DefaultProgram> {
+ mingling::AnyOutput::new(self).route_chain()
+ }
- #any_out_impl
+ /// Converts the wrapper type into a `ChainProcess` for rendering operations.
+ pub fn to_render(self) -> mingling::ChainProcess<DefaultProgram> {
+ mingling::AnyOutput::new(self).route_renderer()
+ }
+ }
+
+ impl ::mingling::Groupped<DefaultProgram> for #type_name {
+ fn member_id() -> DefaultProgram {
+ DefaultProgram::#type_name
+ }
+ }
+ }
+ } else {
+ // For explicit case, use the provided group_name
+ quote! {
+ #struct_def
+
+ #new_impl
+ #from_into_impl
+ #as_ref_impl
+ #deref_impl
+ #default_impl
+
+ #any_out_impl
+ #group_impl
+ }
};
expanded.into()
diff --git a/mingling_macros/src/renderer.rs b/mingling_macros/src/renderer.rs
index 21c20c8..0e32b40 100644
--- a/mingling_macros/src/renderer.rs
+++ b/mingling_macros/src/renderer.rs
@@ -4,7 +4,7 @@
//! generating structs that implement the `Renderer` trait from functions.
use proc_macro::TokenStream;
-use quote::quote;
+use quote::{ToTokens, quote};
use syn::spanned::Spanned;
use syn::{FnArg, ItemFn, Pat, PatType, ReturnType, Signature, Type, TypePath, parse_macro_input};
@@ -106,22 +106,29 @@ pub fn renderer_attr(item: TokenStream) -> TokenStream {
};
let renderer_exist_entry = quote! {
- id if id == std::any::TypeId::of::<#previous_type>() => true,
+ Self::#previous_type => true,
};
let mut renderers = crate::RENDERERS.lock().unwrap();
let mut renderer_exist = crate::RENDERERS_EXIST.lock().unwrap();
+ let mut packed_types = crate::PACKED_TYPES.lock().unwrap();
let renderer_entry_str = renderer_entry.to_string();
let renderer_exist_entry_str = renderer_exist_entry.to_string();
+ let previous_type_str = previous_type.to_token_stream().to_string();
if !renderers.contains(&renderer_entry_str) {
renderers.push(renderer_entry_str);
}
+
if !renderer_exist.contains(&renderer_exist_entry_str) {
renderer_exist.push(renderer_exist_entry_str);
}
+ if !packed_types.contains(&previous_type_str) {
+ packed_types.push(previous_type_str);
+ }
+
// Generate the struct and implementation
// We need to create a wrapper function that adds the r parameter
let expanded = quote! {