aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros/src/lib.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-06-23 00:40:05 +0800
committer魏曹先生 <1992414357@qq.com>2026-06-23 00:40:05 +0800
commit1df1fc664c4a4b12807a49ef2f1a0effda6ce064 (patch)
treea5bcdab31e18094b226d6cef36d99c879c64e25f /mingling_macros/src/lib.rs
parentd94103fd7e76dd86cd64c23f00c818165fb7dc22 (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.rs31
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`)