Repository: jonasbb/serde_with
Pull request #16 (2018-08-05 19:35:51)

Implement strategies to handle duplicate values for sets/maps
* Implement a first-value-wins strategy, in contrasts to serde's last-value-wins.
* Implement a error-on-duplicate strategy, if you want to know if duplicate values exists and otherwise would silently be ignored.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8bcde9b..65cda52 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 ### Added
 
 * `unwrap_or_skip` allows to transparently serialize the inner part of a `Some(T)`
+* Add deserialization helpser for sets and maps, inspired by [comment](https://github.com/serde-rs/serde/issues/553#issuecomment-299711855)
+    * Create an error if duplicate values for a set are detected
+    * Create an error if duplicate keys for a map are detected
+    * Implement a first-value wins strategy for sets/maps. This is different to serde's default
+        which implements a last value wins strategy.
 
 ## [0.2.1]
 
diff --git a/src/duplicate_key_impls/error_on_duplicate.rs b/src/duplicate_key_impls/error_on_duplicate.rs
new file mode 100644
index 0000000..10510fa
--- /dev/null
+++ b/src/duplicate_key_impls/error_on_duplicate.rs
@@ -0,0 +1,84 @@
+use std::{
+    collections::{BTreeMap, BTreeSet, HashMap, HashSet},
+    hash::Hash,
+};
+
+pub trait PreventDuplicateInsertsSet<T> {
+    fn new(size_hint: Option<usize>) -> Self;
+
+    /// Return true if the insert was successful and the value did not exist in the set
+    fn insert(&mut self, value: T) -> bool;
+}
+
+pub trait PreventDuplicateInsertsMap<K, V> {
+    fn new(size_hint: Option<usize>) -> Self;
+
+    /// Return true if the insert was successful and the key did not exist in the map
+    fn insert(&mut self, key: K, value: V) -> bool;
+}
+
+impl<T> PreventDuplicateInsertsSet<T> for HashSet<T>
+where
+    T: Eq + Hash,
+{
+    #[inline]
+    fn new(size_hint: Option<usize>) -> Self {
+        match size_hint {
+            Some(size) => Self::with_capacity(size),
+            None => Self::new(),
+        }
+    }
+
+    #[inline]
+    fn insert(&mut self, value: T) -> bool {
+        self.insert(value)
+    }
+}
+
+impl<T> PreventDuplicateInsertsSet<T> for BTreeSet<T>
+where
+    T: Ord,
+{
+    #[inline]
+    fn new(_size_hint: Option<usize>) -> Self {
+        Self::new()
+    }
+
+    #[inline]
+    fn insert(&mut self, value: T) -> bool {
+        self.insert(value)
+    }
+}
+
+impl<K, V> PreventDuplicateInsertsMap<K, V> for HashMap<K, V>
+where
+    K: Eq + Hash,
+{
+    #[inline]
+    fn new(size_hint: Option<usize>) -> Self {
+        match size_hint {
+            Some(size) => Self::with_capacity(size),
+            None => Self::new(),
+        }
+    }
+
+    #[inline]
+    fn insert(&mut self, key: K, value: V) -> bool {
+        self.insert(key, value).is_none()
+    }
+}
+
+impl<K, V> PreventDuplicateInsertsMap<K, V> for BTreeMap<K, V>
+where
+    K: Ord,
+{
+    #[inline]
+    fn new(_size_hint: Option<usize>) -> Self {
+        Self::new()
+    }
+
+    #[inline]
+    fn insert(&mut self, key: K, value: V) -> bool {
+        self.insert(key, value).is_none()
+    }
+}
diff --git a/src/duplicate_key_impls/first_value_wins.rs b/src/duplicate_key_impls/first_value_wins.rs
new file mode 100644
index 0000000..dde6040
--- /dev/null
+++ b/src/duplicate_key_impls/first_value_wins.rs
@@ -0,0 +1,102 @@
+use std::{
+    collections::{BTreeMap, BTreeSet, HashMap, HashSet},
+    hash::Hash,
+};
+
+pub trait DuplicateInsertsFirstWinsSet<T> {
+    fn new(size_hint: Option<usize>) -> Self;
+
+    /// Insert the value into the set, if there is not already an existing value
+    fn insert(&mut self, value: T);
+}
+
+pub trait DuplicateInsertsFirstWinsMap<K, V> {
+    fn new(size_hint: Option<usize>) -> Self;
+
+    /// Insert the value into the set, if there is not already an existing value
+    fn insert(&mut self, key: K, value: V);
+}
+
+impl<T> DuplicateInsertsFirstWinsSet<T> for HashSet<T>
+where
+    T: Eq + Hash,
+{
+    #[inline]
+    fn new(size_hint: Option<usize>) -> Self {
+        match size_hint {
+            Some(size) => Self::with_capacity(size),
+            None => Self::new(),
+        }
+    }
+
+    #[inline]
+    fn insert(&mut self, value: T) {
+        // Hashset already fullfils the contract and always keeps the first value
+        self.insert(value);
+    }
+}
+
+impl<T> DuplicateInsertsFirstWinsSet<T> for BTreeSet<T>
+where
+    T: Ord,
+{
+    #[inline]
+    fn new(_size_hint: Option<usize>) -> Self {
+        Self::new()
+    }
+
+    #[inline]
+    fn insert(&mut self, value: T) {
+        // BTreeSet already fullfils the contract and always keeps the first value
+        self.insert(value);
+    }
+}
+
+impl<K, V> DuplicateInsertsFirstWinsMap<K, V> for HashMap<K, V>
+where
+    K: Eq + Hash,
+{
+    #[inline]
+    fn new(size_hint: Option<usize>) -> Self {
+        match size_hint {
+            Some(size) => Self::with_capacity(size),
+            None => Self::new(),
+        }
+    }
+
+    #[inline]
+    fn insert(&mut self, key: K, value: V) {
+        use std::collections::hash_map::Entry;
+
+        match self.entry(key) {
+            // we want to keep the first value, so do nothing
+            Entry::Occupied(_) => {}
+            Entry::Vacant(vacant) => {
+                vacant.insert(value);
+            }
+        }
+    }
+}
+
+impl<K, V> DuplicateInsertsFirstWinsMap<K, V> for BTreeMap<K, V>
+where
+    K: Ord,
+{
+    #[inline]
+    fn new(_size_hint: Option<usize>) -> Self {
+        Self::new()
+    }
+
+    #[inline]
+    fn insert(&mut self, key: K, value: V) {
+        use std::collections::btree_map::Entry;
+
+        match self.entry(key) {
+            // we want to keep the first value, so do nothing
+            Entry::Occupied(_) => {}
+            Entry::Vacant(vacant) => {
+                vacant.insert(value);
+            }
+        }
+    }
+}
diff --git a/src/duplicate_key_impls/mod.rs b/src/duplicate_key_impls/mod.rs
new file mode 100644
index 0000000..e433baa
--- /dev/null
+++ b/src/duplicate_key_impls/mod.rs
@@ -0,0 +1,7 @@
+mod error_on_duplicate;
+mod first_value_wins;
+
+pub use self::{
+    error_on_duplicate::{PreventDuplicateInsertsMap, PreventDuplicateInsertsSet},
+    first_value_wins::{DuplicateInsertsFirstWinsMap, DuplicateInsertsFirstWinsSet},
+};
diff --git a/src/lib.rs b/src/lib.rs
index dffa02f..79461e8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -89,6 +89,7 @@ pub mod json;
 pub mod rust;
 #[doc(hidden)]
 pub mod with_prefix;
+mod duplicate_key_impls;
 
 /// Separator for string-based collection de/serialization
 pub trait Separator {
diff --git a/src/rust.rs b/src/rust.rs
index 8dbf1c6..3b44d59 100644
--- a/src/rust.rs
+++ b/src/rust.rs
@@ -325,8 +325,10 @@ pub mod double_option {
 /// # }
 /// ```
 pub mod unwrap_or_skip {
-    use serde::de::{DeserializeOwned, Deserializer};
-    use serde::ser::{Serialize, Serializer};
+    use serde::{
+        de::{DeserializeOwned, Deserializer},
+        ser::{Serialize, Serializer},
+    };
 
     /// Deserialize value wrapped in Some(T)
     pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
@@ -350,3 +352,346 @@ pub mod unwrap_or_skip {
         }
     }
 }
+
+/// Ensure no duplicate values exist in a set.
+///
+/// By default serde has a last-value-wins implementation, if duplicate values for a set exist.
+/// Sometimes it is desirable to know when such an event happens, as the first value is overwritten
+/// and it can indicate an error in the serialized data.
+///
+/// This helper returns an error if two identical values exist in a set.
+///
+/// # Example
+///
+/// ```rust
+/// # extern crate serde;
+/// # #[macro_use]
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// # use std::{collections::HashSet, iter::FromIterator};
+/// # #[derive(Debug, Eq, PartialEq)]
+/// #[derive(Deserialize)]
+/// struct Doc {
+///     #[serde(with = "::serde_with::rust::sets_duplicate_value_is_error")]
+///     set: HashSet<usize>,
+/// }
+/// # fn main() {
+///
+/// // Sets are serialized normally,
+/// let s = r#"{"set": [1, 2, 3, 4]}"#;
+/// let v = Doc {
+///     set: HashSet::from_iter(vec![1, 2, 3, 4]),
+/// };
+/// assert_eq!(v, serde_json::from_str(s).unwrap());
+///
+/// // but create an error if duplicate values, like the `1`, exist.
+/// let s = r#"{"set": [1, 2, 3, 4, 1]}"#;
+/// let res: Result<Doc, _> = serde_json::from_str(s);
+/// assert!(res.is_err());
+/// # }
+/// ```
+pub mod sets_duplicate_value_is_error {
+    use duplicate_key_impls::PreventDuplicateInsertsSet;
+    use serde::de::{Deserialize, Deserializer, Error, SeqAccess, Visitor};
+    use std::{fmt, marker::PhantomData};
+
+    /// Deserialize a set and return an error on duplicate values
+    pub fn deserialize<'de, D, T, V>(deserializer: D) -> Result<T, D::Error>
+    where
+        T: PreventDuplicateInsertsSet<V>,
+        V: Deserialize<'de>,
+        D: Deserializer<'de>,
+    {
+        struct SeqVisitor<T, V> {
+            marker: PhantomData<T>,
+            set_item_type: PhantomData<V>,
+        };
+
+        impl<'de, T, V> Visitor<'de> for SeqVisitor<T, V>
+        where
+            T: PreventDuplicateInsertsSet<V>,
+            V: Deserialize<'de>,
+        {
+            type Value = T;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                formatter.write_str("a sequence")
+            }
+
+            #[inline]
+            fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
+            where
+                A: SeqAccess<'de>,
+            {
+                let mut values = Self::Value::new(access.size_hint());
+
+                while let Some(value) = access.next_element()? {
+                    if !values.insert(value) {
+                        return Err(Error::custom("invalid entry: found duplicate value"));
+                    };
+                }
+
+                Ok(values)
+            }
+        }
+
+        let visitor = SeqVisitor {
+            marker: PhantomData,
+            set_item_type: PhantomData,
+        };
+        deserializer.deserialize_seq(visitor)
+    }
+}
+
+/// Ensure no duplicate keys exist in a map.
+///
+/// By default serde has a last-value-wins implementation, if duplicate keys for a map exist.
+/// Sometimes it is desirable to know when such an event happens, as the first value is overwritten
+/// and it can indicate an error in the serialized data.
+///
+/// This helper returns an error if two identical keys exist in a map.
+///
+/// # Example
+///
+/// ```rust
+/// # extern crate serde;
+/// # #[macro_use]
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// # use std::collections::HashMap;
+/// # #[derive(Debug, Eq, PartialEq)]
+/// #[derive(Deserialize)]
+/// struct Doc {
+///     #[serde(with = "::serde_with::rust::maps_duplicate_key_is_error")]
+///     map: HashMap<usize, usize>,
+/// }
+/// # fn main() {
+///
+/// // Maps are serialized normally,
+/// let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+/// let mut v = Doc {
+///     map: HashMap::new(),
+/// };
+/// v.map.insert(1, 1);
+/// v.map.insert(2, 2);
+/// v.map.insert(3, 3);
+/// assert_eq!(v, serde_json::from_str(s).unwrap());
+///
+/// // but create an error if duplicate keys, like the `1`, exist.
+/// let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+/// let res: Result<Doc, _> = serde_json::from_str(s);
+/// assert!(res.is_err());
+/// # }
+/// ```
+pub mod maps_duplicate_key_is_error {
+
+    use duplicate_key_impls::PreventDuplicateInsertsMap;
+    use serde::de::{Deserialize, Deserializer, Error, MapAccess, Visitor};
+    use std::{fmt, marker::PhantomData};
+
+    /// Deserialize a map and return an error on duplicate keys
+    pub fn deserialize<'de, D, T, K, V>(deserializer: D) -> Result<T, D::Error>
+    where
+        T: PreventDuplicateInsertsMap<K, V>,
+        K: Deserialize<'de>,
+        V: Deserialize<'de>,
+        D: Deserializer<'de>,
+    {
+        struct MapVisitor<T, K, V> {
+            marker: PhantomData<T>,
+            map_key_type: PhantomData<K>,
+            map_value_type: PhantomData<V>,
+        };
+
+        impl<'de, T, K, V> Visitor<'de> for MapVisitor<T, K, V>
+        where
+            T: PreventDuplicateInsertsMap<K, V>,
+            K: Deserialize<'de>,
+            V: Deserialize<'de>,
+        {
+            type Value = T;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                formatter.write_str("a map")
+            }
+
+            #[inline]
+            fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
+            where
+                A: MapAccess<'de>,
+            {
+                let mut values = Self::Value::new(access.size_hint());
+
+                while let Some((key, value)) = access.next_entry()? {
+                    if !values.insert(key, value) {
+                        return Err(Error::custom("invalid entry: found duplicate key"));
+                    };
+                }
+
+                Ok(values)
+            }
+        }
+
+        let visitor = MapVisitor {
+            marker: PhantomData,
+            map_key_type: PhantomData,
+            map_value_type: PhantomData,
+        };
+        deserializer.deserialize_map(visitor)
+    }
+}
+
+/// Ensure that the first value is taken, if duplicate values exist
+///
+/// By default serde has a last-value-wins implementation, if duplicate keys for a set exist.
+/// Sometimes the opposite strategy is desired. This helper implements a first-value-wins strategy.
+pub mod sets_first_value_wins {
+    use duplicate_key_impls::DuplicateInsertsFirstWinsSet;
+    use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
+    use std::{fmt, marker::PhantomData};
+
+    /// Deserialize a set and return an error on duplicate values
+    pub fn deserialize<'de, D, T, V>(deserializer: D) -> Result<T, D::Error>
+    where
+        T: DuplicateInsertsFirstWinsSet<V>,
+        V: Deserialize<'de>,
+        D: Deserializer<'de>,
+    {
+        struct SeqVisitor<T, V> {
+            marker: PhantomData<T>,
+            set_item_type: PhantomData<V>,
+        };
+
+        impl<'de, T, V> Visitor<'de> for SeqVisitor<T, V>
+        where
+            T: DuplicateInsertsFirstWinsSet<V>,
+            V: Deserialize<'de>,
+        {
+            type Value = T;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                formatter.write_str("a sequence")
+            }
+
+            #[inline]
+            fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
+            where
+                A: SeqAccess<'de>,
+            {
+                let mut values = Self::Value::new(access.size_hint());
+
+                while let Some(value) = access.next_element()? {
+                    values.insert(value);
+                }
+
+                Ok(values)
+            }
+        }
+
+        let visitor = SeqVisitor {
+            marker: PhantomData,
+            set_item_type: PhantomData,
+        };
+        deserializer.deserialize_seq(visitor)
+    }
+}
+
+/// Ensure that the first key is taken, if duplicate keys exist
+///
+/// By default serde has a last-key-wins implementation, if duplicate keys for a map exist.
+/// Sometimes the opposite strategy is desired. This helper implements a first-key-wins strategy.
+///
+/// # Example
+///
+/// ```rust
+/// # extern crate serde;
+/// # #[macro_use]
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// # use std::collections::HashMap;
+/// # #[derive(Debug, Eq, PartialEq)]
+/// #[derive(Deserialize)]
+/// struct Doc {
+///     #[serde(with = "::serde_with::rust::maps_first_key_wins")]
+///     map: HashMap<usize, usize>,
+/// }
+/// # fn main() {
+///
+/// // Maps are serialized normally,
+/// let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+/// let mut v = Doc {
+///     map: HashMap::new(),
+/// };
+/// v.map.insert(1, 1);
+/// v.map.insert(2, 2);
+/// v.map.insert(3, 3);
+/// assert_eq!(v, serde_json::from_str(s).unwrap());
+///
+/// // but create an error if duplicate keys, like the `1`, exist.
+/// let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+/// let mut v = Doc {
+///     map: HashMap::new(),
+/// };
+/// v.map.insert(1, 1);
+/// v.map.insert(2, 2);
+/// assert_eq!(v, serde_json::from_str(s).unwrap());
+/// # }
+/// ```
+pub mod maps_first_key_wins {
+
+    use duplicate_key_impls::DuplicateInsertsFirstWinsMap;
+    use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
+    use std::{fmt, marker::PhantomData};
+
+    /// Deserialize a map and return an error on duplicate keys
+    pub fn deserialize<'de, D, T, K, V>(deserializer: D) -> Result<T, D::Error>
+    where
+        T: DuplicateInsertsFirstWinsMap<K, V>,
+        K: Deserialize<'de>,
+        V: Deserialize<'de>,
+        D: Deserializer<'de>,
+    {
+        struct MapVisitor<T, K, V> {
+            marker: PhantomData<T>,
+            map_key_type: PhantomData<K>,
+            map_value_type: PhantomData<V>,
+        };
+
+        impl<'de, T, K, V> Visitor<'de> for MapVisitor<T, K, V>
+        where
+            T: DuplicateInsertsFirstWinsMap<K, V>,
+            K: Deserialize<'de>,
+            V: Deserialize<'de>,
+        {
+            type Value = T;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                formatter.write_str("a map")
+            }
+
+            #[inline]
+            fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
+            where
+                A: MapAccess<'de>,
+            {
+                let mut values = Self::Value::new(access.size_hint());
+
+                while let Some((key, value)) = access.next_entry()? {
+                    values.insert(key, value);
+                }
+
+                Ok(values)
+            }
+        }
+
+        let visitor = MapVisitor {
+            marker: PhantomData,
+            map_key_type: PhantomData,
+            map_value_type: PhantomData,
+        };
+        deserializer.deserialize_map(visitor)
+    }
+}


Test patch:
diff --git a/tests/rust.rs b/tests/rust.rs
index f84b196..eed22ae 100644
--- a/tests/rust.rs
+++ b/tests/rust.rs
@@ -54,3 +54,191 @@ fn string_collection_non_existing() {
 
     assert_eq!(r#"{"s":""}"#, serde_json::to_string(&res[0]).unwrap());
 }
+
+#[test]
+fn prohibit_duplicate_value_hashset() {
+    use std::{collections::HashSet, iter::FromIterator};
+    #[derive(Debug, Eq, PartialEq, Deserialize)]
+    struct Doc {
+        #[serde(with = "::serde_with::rust::sets_duplicate_value_is_error")]
+        set: HashSet<usize>,
+    }
+
+    let s = r#"{"set": [1, 2, 3, 4]}"#;
+    let v = Doc {
+        set: HashSet::from_iter(vec![1, 2, 3, 4]),
+    };
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+
+    let s = r#"{"set": [1, 2, 3, 4, 1]}"#;
+    let res: Result<Doc, _> = serde_json::from_str(s);
+    assert!(res.is_err());
+}
+
+#[test]
+fn prohibit_duplicate_value_btreeset() {
+    use std::{collections::BTreeSet, iter::FromIterator};
+    #[derive(Debug, Eq, PartialEq, Deserialize)]
+    struct Doc {
+        #[serde(with = "::serde_with::rust::sets_duplicate_value_is_error")]
+        set: BTreeSet<usize>,
+    }
+
+    let s = r#"{"set": [1, 2, 3, 4]}"#;
+    let v = Doc {
+        set: BTreeSet::from_iter(vec![1, 2, 3, 4]),
+    };
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+
+    let s = r#"{"set": [1, 2, 3, 4, 1]}"#;
+    let res: Result<Doc, _> = serde_json::from_str(s);
+    assert!(res.is_err());
+}
+
+#[test]
+fn prohibit_duplicate_value_hashmap() {
+    use std::collections::HashMap;
+    #[derive(Debug, Eq, PartialEq, Deserialize)]
+    struct Doc {
+        #[serde(with = "::serde_with::rust::maps_duplicate_key_is_error")]
+        map: HashMap<usize, usize>,
+    }
+
+    // Different value and key always works
+    let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+    let mut v = Doc {
+        map: HashMap::new(),
+    };
+    v.map.insert(1, 1);
+    v.map.insert(2, 2);
+    v.map.insert(3, 3);
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+
+    // Same value for different keys is ok
+    let s = r#"{"map": {"1": 1, "2": 1, "3": 1}}"#;
+    let mut v = Doc {
+        map: HashMap::new(),
+    };
+    v.map.insert(1, 1);
+    v.map.insert(2, 1);
+    v.map.insert(3, 1);
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+
+    // Duplicate keys are an error
+    let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+    let res: Result<Doc, _> = serde_json::from_str(s);
+    assert!(res.is_err());
+}
+
+#[test]
+fn prohibit_duplicate_value_btreemap() {
+    use std::collections::BTreeMap;
+    #[derive(Debug, Eq, PartialEq, Deserialize)]
+    struct Doc {
+        #[serde(with = "::serde_with::rust::maps_duplicate_key_is_error")]
+        map: BTreeMap<usize, usize>,
+    }
+
+    // Different value and key always works
+    let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+    let mut v = Doc {
+        map: BTreeMap::new(),
+    };
+    v.map.insert(1, 1);
+    v.map.insert(2, 2);
+    v.map.insert(3, 3);
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+
+    // Same value for different keys is ok
+    let s = r#"{"map": {"1": 1, "2": 1, "3": 1}}"#;
+    let mut v = Doc {
+        map: BTreeMap::new(),
+    };
+    v.map.insert(1, 1);
+    v.map.insert(2, 1);
+    v.map.insert(3, 1);
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+
+    // Duplicate keys are an error
+    let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+    let res: Result<Doc, _> = serde_json::from_str(s);
+    assert!(res.is_err());
+}
+
+#[test]
+fn duplicate_key_first_wins_hashmap() {
+    use std::collections::HashMap;
+    #[derive(Debug, Eq, PartialEq, Deserialize)]
+    struct Doc {
+        #[serde(with = "::serde_with::rust::maps_first_key_wins")]
+        map: HashMap<usize, usize>,
+    }
+
+    // Different value and key always works
+    let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+    let mut v = Doc {
+        map: HashMap::new(),
+    };
+    v.map.insert(1, 1);
+    v.map.insert(2, 2);
+    v.map.insert(3, 3);
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+
+    // Same value for different keys is ok
+    let s = r#"{"map": {"1": 1, "2": 1, "3": 1}}"#;
+    let mut v = Doc {
+        map: HashMap::new(),
+    };
+    v.map.insert(1, 1);
+    v.map.insert(2, 1);
+    v.map.insert(3, 1);
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+
+    // Duplicate keys, the first one is used
+    let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+    let mut v = Doc {
+        map: HashMap::new(),
+    };
+    v.map.insert(1, 1);
+    v.map.insert(2, 2);
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+}
+
+#[test]
+fn duplicate_key_first_wins_btreemap() {
+    use std::collections::BTreeMap;
+    #[derive(Debug, Eq, PartialEq, Deserialize)]
+    struct Doc {
+        #[serde(with = "::serde_with::rust::maps_first_key_wins")]
+        map: BTreeMap<usize, usize>,
+    }
+
+    // Different value and key always works
+    let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+    let mut v = Doc {
+        map: BTreeMap::new(),
+    };
+    v.map.insert(1, 1);
+    v.map.insert(2, 2);
+    v.map.insert(3, 3);
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+
+    // Same value for different keys is ok
+    let s = r#"{"map": {"1": 1, "2": 1, "3": 1}}"#;
+    let mut v = Doc {
+        map: BTreeMap::new(),
+    };
+    v.map.insert(1, 1);
+    v.map.insert(2, 1);
+    v.map.insert(3, 1);
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+
+    // Duplicate keys, the first one is used
+    let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+    let mut v = Doc {
+        map: BTreeMap::new(),
+    };
+    v.map.insert(1, 1);
+    v.map.insert(2, 2);
+    assert_eq!(v, serde_json::from_str(s).unwrap());
+}