Skip to content

Commit

Permalink
Merge pull request #7 from robinbernon/generic_hashmap_deserialization
Browse files Browse the repository at this point in the history
Making the deserialization for LinkedHashMap generic for build hasher type
  • Loading branch information
kyren authored May 3, 2021
2 parents b283e8b + 6446756 commit 9b42ad0
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 39 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ serde = { version = "1.0", optional = true }

[dev-dependencies]
serde_test = "1.0"
fxhash = "0.2.1"
83 changes: 44 additions & 39 deletions src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,54 +31,59 @@ where
}
}

#[derive(Debug)]
pub struct LinkedHashMapVisitor<K, V> {
marker: PhantomData<LinkedHashMap<K, V>>,
}

impl<K, V> LinkedHashMapVisitor<K, V> {
fn new() -> Self {
LinkedHashMapVisitor {
marker: PhantomData,
}
}
}

impl<K, V> Default for LinkedHashMapVisitor<K, V> {
fn default() -> Self {
Self::new()
}
}

impl<'de, K, V> Visitor<'de> for LinkedHashMapVisitor<K, V>
impl<'de, K, V, S> Deserialize<'de> for LinkedHashMap<K, V, S>
where
K: Deserialize<'de> + Eq + Hash,
V: Deserialize<'de>,
S: BuildHasher + Default,
{
type Value = LinkedHashMap<K, V>;

fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "a map")
}
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Debug)]
pub struct LinkedHashMapVisitor<K, V, S> {
marker: PhantomData<LinkedHashMap<K, V, S>>,
}

#[inline]
fn visit_map<M: MapAccess<'de>>(self, mut map: M) -> Result<Self::Value, M::Error> {
let mut values = LinkedHashMap::with_capacity(map.size_hint().unwrap_or(0));
impl<K, V, S> LinkedHashMapVisitor<K, V, S> {
fn new() -> Self {
LinkedHashMapVisitor {
marker: PhantomData,
}
}
}

while let Some((k, v)) = map.next_entry()? {
values.insert(k, v);
impl<K, V, S> Default for LinkedHashMapVisitor<K, V, S> {
fn default() -> Self {
Self::new()
}
}

Ok(values)
}
}
impl<'de, K, V, S> Visitor<'de> for LinkedHashMapVisitor<K, V, S>
where
K: Deserialize<'de> + Eq + Hash,
V: Deserialize<'de>,
S: BuildHasher + Default,
{
type Value = LinkedHashMap<K, V, S>;

fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "a map")
}

#[inline]
fn visit_map<M: MapAccess<'de>>(self, mut map: M) -> Result<Self::Value, M::Error> {
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<K, V>
where
K: Deserialize<'de> + Eq + Hash,
V: Deserialize<'de>,
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_map(LinkedHashMapVisitor::default())
}
}
Expand Down
30 changes: 30 additions & 0 deletions tests/serde.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![cfg(feature = "serde_impl")]

use fxhash::FxBuildHasher;
use hashlink::{LinkedHashMap, LinkedHashSet};
use serde_test::{assert_tokens, Token};

Expand Down Expand Up @@ -32,6 +33,35 @@ fn map_serde_tokens() {
);
}

#[test]
fn map_serde_tokens_empty_generic() {
let map = LinkedHashMap::<char, u32, FxBuildHasher>::with_hasher(FxBuildHasher::default());

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::<u32>::new();
Expand Down

0 comments on commit 9b42ad0

Please sign in to comment.