diff --git a/Cargo.toml b/Cargo.toml index 630f44846..c8279e6ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,3 +86,8 @@ raw_value = [] # overflow the stack after deserialization has completed, including, but not # limited to, Display and Debug and Drop impls. unbounded_depth = [] + +# When deserializing Map, return an error if a key is found that +# is already in the Map. +no_duplicate_keys = [] + diff --git a/src/map.rs b/src/map.rs index 520cd6cf5..52573790d 100644 --- a/src/map.rs +++ b/src/map.rs @@ -17,8 +17,12 @@ use core::mem; use core::ops; use serde::de; +#[cfg(feature = "no_duplicate_keys")] +use std::format; + #[cfg(not(feature = "preserve_order"))] use alloc::collections::{btree_map, BTreeMap}; + #[cfg(feature = "preserve_order")] use indexmap::IndexMap; @@ -472,6 +476,10 @@ impl<'de> de::Deserialize<'de> for Map { let mut values = Map::new(); while let Some((key, value)) = tri!(visitor.next_entry()) { + #[cfg(feature = "no_duplicate_keys")] + if values.contains_key(&key) { + Err(serde::de::Error::custom(format!("duplicate key '{key}'")))? + } values.insert(key, value); } diff --git a/src/value/de.rs b/src/value/de.rs index 1e8b5acbb..c5b6c2b30 100644 --- a/src/value/de.rs +++ b/src/value/de.rs @@ -10,6 +10,10 @@ use alloc::vec::{self, Vec}; use core::fmt; use core::slice; use core::str::FromStr; + +#[cfg(feature = "no_duplicate_keys")] +use std::format; + use serde::de::{ self, Deserialize, DeserializeSeed, EnumAccess, Expected, IntoDeserializer, MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor, @@ -122,6 +126,10 @@ impl<'de> Deserialize<'de> for Value { values.insert(first_key, tri!(visitor.next_value())); while let Some((key, value)) = tri!(visitor.next_entry()) { + #[cfg(feature = "no_duplicate_keys")] + if values.contains_key(&key) { + Err(serde::de::Error::custom(format!("duplicate key '{key}'")))? + } values.insert(key, value); }