From 4588e17f7ddacd8391a5c881a209735e08d48797 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Tue, 4 Aug 2026 13:26:48 +0800 Subject: feat: add entry metadata system with compile-time typed values Add `Metadata` trait and `#[metadata(Entry)]` attribute macro to attach arbitrary, compile-time-typed metadata to entries. Implement `ProgramCollect::get_metadata()` for runtime retrieval, backed by a global registry populated by `register_metadata!`. Extend `pathf` with `MetadataPattern` to resolve metadata types across modules at build time. Add two examples demonstrating metadata usage with and without pathf integration. --- mingling_macros/src/func/register_metadata.rs | 67 +++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 mingling_macros/src/func/register_metadata.rs (limited to 'mingling_macros/src/func/register_metadata.rs') diff --git a/mingling_macros/src/func/register_metadata.rs b/mingling_macros/src/func/register_metadata.rs new file mode 100644 index 0000000..a1f9965 --- /dev/null +++ b/mingling_macros/src/func/register_metadata.rs @@ -0,0 +1,67 @@ +use proc_macro::TokenStream; +use quote::ToTokens; +use syn::TypePath; +use syn::spanned::Spanned; + +use crate::METADATA; +use crate::get_global_set; + +/// Parses and registers a metadata mapping of the form +/// `register_metadata!(EntryGreet, Description)`. +/// +/// Stores a match-arm-style string entry `Self::EntryGreet => { ... }` that is +/// later consumed by `program_final_gen!` to generate the `get_metadata` +/// method of `ProgramCollect`. +pub(crate) fn register_metadata_impl(input: TokenStream) -> TokenStream { + // Parse the input as a comma-separated list of type arguments. + let input_parsed = syn::parse_macro_input!( + input with syn::punctuated::Punctuated::parse_terminated + ); + + if input_parsed.len() != 2 { + return syn::Error::new( + input_parsed.span(), + "Expected exactly two comma-separated arguments: `EntryVariant, MetadataType`", + ) + .to_compile_error() + .into(); + } + + let entry_expr = &input_parsed[0]; + let metadata_expr = &input_parsed[1]; + + let entry_type = match syn::parse2::(entry_expr.to_token_stream()) { + Ok(ty) => ty, + Err(e) => return e.to_compile_error().into(), + }; + let metadata_type = match syn::parse2::(metadata_expr.to_token_stream()) { + Ok(ty) => ty, + Err(e) => return e.to_compile_error().into(), + }; + + let entry_str = build_metadata_entry(&entry_type, &metadata_type).to_string(); + + get_global_set(&METADATA).lock().unwrap().insert(entry_str); + + quote::quote! {}.into() +} + +/// Builds the match-arm entry for `get_metadata`, matching on the enum variant +/// and then on the requested `TypeId`. +fn build_metadata_entry( + entry_type: &TypePath, + metadata_type: &TypePath, +) -> proc_macro2::TokenStream { + let enum_variant = entry_type.path.segments.last().unwrap().ident.clone(); + quote::quote! { + Self::#enum_variant => { + let __metadata_type_id = ::std::any::TypeId::of::<#metadata_type>(); + match type_id { + _ if type_id == __metadata_type_id => Some(::std::boxed::Box::new( + <#entry_type as ::mingling::Metadata<#metadata_type>>::init_metadata(), + ) as ::std::boxed::Box), + _ => None, + } + } + } +} -- cgit