From 12628258e811f1d00ee10586c1f8241a401acf37 Mon Sep 17 00:00:00 2001 From: Robin Bernon Date: Tue, 30 Mar 2021 16:31:06 +0100 Subject: [PATCH] Making the deserialization for LinkedHashMap generic for build hasher type --- Cargo.toml | 1 + src/serde.rs | 83 ++++++++++++++++++++++++++------------------------ tests/serde.rs | 30 ++++++++++++++++++ 3 files changed, 75 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4d6b32e..865583c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,4 @@ serde = { version = "1.0", optional = true } [dev-dependencies] serde_test = "1.0" +fxhash = "0.2.1" diff --git a/src/serde.rs b/src/serde.rs index b8e307c..ca9dc7e 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -31,54 +31,59 @@ where } } -#[derive(Debug)] -pub struct LinkedHashMapVisitor { - marker: PhantomData>, -} - -impl LinkedHashMapVisitor { - fn new() -> Self { - LinkedHashMapVisitor { - marker: PhantomData, - } - } -} - -impl Default for LinkedHashMapVisitor { - fn default() -> Self { - Self::new() - } -} - -impl<'de, K, V> Visitor<'de> for LinkedHashMapVisitor +impl<'de, K, V, S> Deserialize<'de> for LinkedHashMap where K: Deserialize<'de> + Eq + Hash, V: Deserialize<'de>, + S: BuildHasher + Default, { - type Value = LinkedHashMap; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - write!(formatter, "a map") - } + fn deserialize>(deserializer: D) -> Result { + #[derive(Debug)] + pub struct LinkedHashMapVisitor { + marker: PhantomData>, + } - #[inline] - fn visit_map>(self, mut map: M) -> Result { - let mut values = LinkedHashMap::with_capacity(map.size_hint().unwrap_or(0)); + impl LinkedHashMapVisitor { + fn new() -> Self { + LinkedHashMapVisitor { + marker: PhantomData, + } + } + } - while let Some((k, v)) = map.next_entry()? { - values.insert(k, v); + impl Default for LinkedHashMapVisitor { + fn default() -> Self { + Self::new() + } } - Ok(values) - } -} + impl<'de, K, V, S> Visitor<'de> for LinkedHashMapVisitor + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: BuildHasher + Default, + { + type Value = LinkedHashMap; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + write!(formatter, "a map") + } + + #[inline] + fn visit_map>(self, mut map: M) -> Result { + let mut values = LinkedHashMap::with_capacity_and_hasher( + map.size_hint().unwrap_or(0), + S::default(), + ); + + while let Some((k, v)) = map.next_entry()? { + values.insert(k, v); + } + + Ok(values) + } + } -impl<'de, K, V> Deserialize<'de> for LinkedHashMap -where - K: Deserialize<'de> + Eq + Hash, - V: Deserialize<'de>, -{ - fn deserialize>(deserializer: D) -> Result { deserializer.deserialize_map(LinkedHashMapVisitor::default()) } } diff --git a/tests/serde.rs b/tests/serde.rs index fce3108..63a6752 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -1,5 +1,6 @@ #![cfg(feature = "serde_impl")] +use fxhash::FxBuildHasher; use hashlink::{LinkedHashMap, LinkedHashSet}; use serde_test::{assert_tokens, Token}; @@ -32,6 +33,35 @@ fn map_serde_tokens() { ); } +#[test] +fn map_serde_tokens_empty_generic() { + let map = LinkedHashMap::::new(); + + assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]); +} + +#[test] +fn map_serde_tokens_generic() { + let mut map = LinkedHashMap::with_hasher(FxBuildHasher::default()); + map.insert('a', 10); + map.insert('b', 20); + map.insert('c', 30); + + assert_tokens( + &map, + &[ + Token::Map { len: Some(3) }, + Token::Char('a'), + Token::I32(10), + Token::Char('b'), + Token::I32(20), + Token::Char('c'), + Token::I32(30), + Token::MapEnd, + ], + ); +} + #[test] fn set_serde_tokens_empty() { let set = LinkedHashSet::::new();