diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-06-23 00:40:05 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-06-23 00:40:05 +0800 |
| commit | 1df1fc664c4a4b12807a49ef2f1a0effda6ce064 (patch) | |
| tree | a5bcdab31e18094b226d6cef36d99c879c64e25f /mingling_macros/src/lib.rs | |
| parent | d94103fd7e76dd86cd64c23f00c818165fb7dc22 (diff) | |
Add compile-time duplicate variant detection
Add duplicate variant checks for chain, renderer, help, and completion
registrations to produce a clear compile error instead of silently
generating unreachable code
Diffstat (limited to 'mingling_macros/src/lib.rs')
| -rw-r--r-- | mingling_macros/src/lib.rs | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs index c6b94c3..5bc73a4 100644 --- a/mingling_macros/src/lib.rs +++ b/mingling_macros/src/lib.rs @@ -195,6 +195,37 @@ pub(crate) static CHAINS_EXIST: Registry = OnceLock::new(); pub(crate) static RENDERERS_EXIST: Registry = OnceLock::new(); pub(crate) static HELP_REQUESTS: Registry = OnceLock::new(); +/// Checks if a variant name already exists in a registered set. +/// Returns a `compile_error` token stream if a duplicate is found. +pub(crate) fn check_duplicate_variant( + set: &std::collections::BTreeSet<String>, + variant_name: &str, + kind: &str, + error_span: proc_macro2::Span, +) -> Result<(), proc_macro2::TokenStream> { + for existing in set.iter() { + if entry_has_variant(existing, variant_name) { + return Err(syn::Error::new( + error_span, + format!( + "duplicate {kind} registration for `{variant_name}`: a {kind} with this type already exists" + ), + ) + .to_compile_error()); + } + } + Ok(()) +} + +/// Checks if a stored entry string contains the given variant name. +/// Handles both "StructName => Variant," and "Self::Variant => ..." formats. +fn entry_has_variant(entry: &str, variant_name: &str) -> bool { + entry.contains(&format!("=> {variant_name},")) + || entry.contains(&format!("=> {variant_name} ")) + || entry.contains(&format!("=> {variant_name}")) + || entry.contains(&format!(":: {variant_name} =>")) +} + /// Registers an outside-type as a member of a program group without modifying its definition. /// /// This macro allows you to use outside-types from external crates (like `std::io::Error`) |
