From 02495899ec4f361452daf56ffc3b1923911c9e35 Mon Sep 17 00:00:00 2001 From: Dherse Date: Mon, 14 Jul 2025 14:55:15 +0200 Subject: [PATCH] Added deduplication of keys in macro --- crates/typst-macros/src/time.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/crates/typst-macros/src/time.rs b/crates/typst-macros/src/time.rs index 3ae4d217d..d160cbf87 100644 --- a/crates/typst-macros/src/time.rs +++ b/crates/typst-macros/src/time.rs @@ -1,3 +1,5 @@ +use std::collections::HashSet; + use proc_macro2::TokenStream; use quote::{format_ident, quote, ToTokens}; use syn::parse::{Parse, ParseStream}; @@ -17,12 +19,12 @@ pub struct Meta { pub span: Option, pub callsite: Option, pub func: Option, - pub extras: Vec<(String, Mode, syn::Expr)>, + pub extras: Vec<(syn::Ident, Mode, syn::Expr)>, } impl Parse for Meta { fn parse(input: ParseStream) -> Result { - Ok(Self { + let out = Self { name: parse_string::(input)?, span: parse_key_value::(input)?, callsite: parse_key_value::(input)?, @@ -39,11 +41,26 @@ impl Parse for Meta { let value = input.parse()?; eat_comma(input); - pairs.push((key.to_string(), mode, value)); + pairs.push((key, mode, value)); } pairs }, - }) + }; + + let mut keys = HashSet::new(); + keys.insert("name".to_string()); + keys.insert("span".to_string()); + keys.insert("callsite".to_string()); + keys.insert("func".to_string()); + + // Check that the keys are unique. + for (key, _, _) in &out.extras { + if !keys.insert(key.to_string()) { + bail!(key, "Duplicate key in #[time(..)]: `{}`", key); + } + } + + Ok(out) } } @@ -98,6 +115,7 @@ fn create(meta: Meta, mut item: syn::ItemFn) -> Result { Mode::Serialize => (format_ident!("with_arg"), None), }; + let key = key.to_string(); extras.push(quote! { .#method(#key, (#value) #transform) }); if matches!(mode, Mode::Serialize) { let error_msg = format!("failed to serialize {key}");