aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros/src/func/pack_structural.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-07-26 20:56:24 +0800
committer魏曹先生 <1992414357@qq.com>2026-07-26 20:56:24 +0800
commit5714eba48ee9031d61858425583c219b881f2d13 (patch)
tree714a2f82d7652ab14433a9ea4c129c30f6d04597 /mingling_macros/src/func/pack_structural.rs
parent2cb8893711b73ccde946ca83e01dc315a9294c23 (diff)
feat(macros): split monolith into one-macro-per-file modules
Diffstat (limited to 'mingling_macros/src/func/pack_structural.rs')
-rw-r--r--mingling_macros/src/func/pack_structural.rs168
1 files changed, 168 insertions, 0 deletions
diff --git a/mingling_macros/src/func/pack_structural.rs b/mingling_macros/src/func/pack_structural.rs
new file mode 100644
index 0000000..9399959
--- /dev/null
+++ b/mingling_macros/src/func/pack_structural.rs
@@ -0,0 +1,168 @@
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::Ident;
+
+use crate::get_global_set;
+
+/// `pack_structural!` — like `pack!` but also marks the type as supporting
+/// structured output via `StructuralData`.
+pub(crate) fn pack_structural(input: TokenStream) -> TokenStream {
+ // Parse same input format as `pack!`
+ let input_parsed = syn::parse_macro_input!(input as PackStructuralInput);
+ let type_name = input_parsed.type_name;
+ let inner_type = input_parsed.inner_type;
+ let attrs = input_parsed.attrs;
+ let program_path = crate::default_program_path();
+
+ // Register in STRUCTURED_TYPES
+ let type_name_str = type_name.to_string();
+ get_global_set(&crate::STRUCTURED_TYPES)
+ .lock()
+ .unwrap()
+ .insert(type_name_str);
+
+ // Struct definition (with Serialize derive, same as pack! under structural_renderer)
+ #[cfg(not(feature = "structural_renderer"))]
+ let struct_def = quote! {
+ #(#attrs)*
+ pub struct #type_name {
+ pub inner: #inner_type,
+ }
+ };
+
+ #[cfg(feature = "structural_renderer")]
+ let struct_def = quote! {
+ #(#attrs)*
+ #[derive(serde::Serialize)]
+ pub struct #type_name {
+ pub inner: #inner_type,
+ }
+ };
+
+ // Helper impls (same as pack!)
+ let new_impl = quote! {
+ impl #type_name {
+ pub fn new(inner: #inner_type) -> Self {
+ Self { inner }
+ }
+ }
+ };
+
+ let from_into_impl = quote! {
+ impl From<#inner_type> for #type_name {
+ fn from(inner: #inner_type) -> Self {
+ Self::new(inner)
+ }
+ }
+ impl From<#type_name> for #inner_type {
+ fn from(wrapper: #type_name) -> #inner_type {
+ wrapper.inner
+ }
+ }
+ };
+
+ let as_ref_impl = quote! {
+ impl ::std::convert::AsRef<#inner_type> for #type_name {
+ fn as_ref(&self) -> &#inner_type {
+ &self.inner
+ }
+ }
+ impl ::std::convert::AsMut<#inner_type> for #type_name {
+ fn as_mut(&mut self) -> &mut #inner_type {
+ &mut self.inner
+ }
+ }
+ };
+
+ let deref_impl = quote! {
+ impl ::std::ops::Deref for #type_name {
+ type Target = #inner_type;
+ fn deref(&self) -> &Self::Target {
+ &self.inner
+ }
+ }
+ impl ::std::ops::DerefMut for #type_name {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.inner
+ }
+ }
+ };
+
+ let default_impl = quote! {
+ impl ::std::default::Default for #type_name
+ where
+ #inner_type: ::std::default::Default,
+ {
+ fn default() -> Self {
+ Self::new(::std::default::Default::default())
+ }
+ }
+ };
+
+ let register_impl = quote! {
+ ::mingling::macros::register_type!(#type_name);
+ };
+
+ // StructuralData impl + sealed + registration
+ let structural_impl = quote! {
+ impl ::mingling::__private::StructuralDataSealed<crate::ThisProgram> for #type_name {}
+ impl ::mingling::__private::StructuralData<crate::ThisProgram> for #type_name {}
+ };
+
+ let expanded = quote! {
+ #struct_def
+
+ #new_impl
+ #from_into_impl
+ #as_ref_impl
+ #deref_impl
+ #default_impl
+ #register_impl
+ #structural_impl
+
+ impl Into<::mingling::AnyOutput<#program_path>> for #type_name {
+ fn into(self) -> ::mingling::AnyOutput<#program_path> {
+ ::mingling::AnyOutput::new(self)
+ }
+ }
+
+ impl Into<::mingling::ChainProcess<#program_path>> for #type_name {
+ fn into(self) -> ::mingling::ChainProcess<#program_path> {
+ ::mingling::AnyOutput::new(self).route_chain()
+ }
+ }
+
+ /// SAFETY: This is an internal implementation of the `pack_structural!` macro,
+ /// guaranteeing that the enum value registered by the `register_type!` macro
+ /// is exactly the same as the actual return value,
+ /// which can be confirmed via the `Ident` in the `quote!` block.
+ unsafe impl ::mingling::Grouped<#program_path> for #type_name {
+ fn member_id() -> #program_path {
+ #program_path::#type_name
+ }
+ }
+ };
+
+ expanded.into()
+}
+
+/// Input for `pack_structural!` — same format as `pack!`.
+struct PackStructuralInput {
+ attrs: Vec<syn::Attribute>,
+ type_name: Ident,
+ inner_type: syn::Type,
+}
+
+impl syn::parse::Parse for PackStructuralInput {
+ fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+ let attrs = input.call(syn::Attribute::parse_outer)?;
+ let type_name: Ident = input.parse()?;
+ input.parse::<syn::Token![=]>()?;
+ let inner_type: syn::Type = input.parse()?;
+ Ok(PackStructuralInput {
+ attrs,
+ type_name,
+ inner_type,
+ })
+ }
+}