De/serialize for HashMap<K, V, S>

This commit is contained in:
David Tolnay 2016-06-11 00:43:02 -07:00
parent 84a573c926
commit 46a1860601
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
6 changed files with 62 additions and 31 deletions

View File

@ -32,7 +32,7 @@ use collections::enum_set::{CLike, EnumSet};
#[cfg(all(feature = "nightly", feature = "collections"))] #[cfg(all(feature = "nightly", feature = "collections"))]
use collections::borrow::ToOwned; use collections::borrow::ToOwned;
use core::hash::Hash; use core::hash::{Hash, BuildHasher};
use core::marker::PhantomData; use core::marker::PhantomData;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::net; use std::net;
@ -726,31 +726,26 @@ tuple_impls! {
macro_rules! map_impl { macro_rules! map_impl {
( (
$ty:ty, $ty:ty,
< $($constraints:ident),* >, $visitor_ty:ident < $($typaram:ident : $bound1:ident $(+ $bound2:ident)*),* >,
$visitor_name:ident,
$visitor:ident, $visitor:ident,
$ctor:expr, $ctor:expr,
$with_capacity:expr, $with_capacity:expr
$insert:expr
) => { ) => {
/// A visitor that produces a map. /// A visitor that produces a map.
pub struct $visitor_name<K, V> { pub struct $visitor_ty<$($typaram),*> {
marker: PhantomData<$ty>, marker: PhantomData<$ty>,
} }
impl<K, V> $visitor_name<K, V> { impl<$($typaram : $bound1 $(+ $bound2)*),*> $visitor_ty<$($typaram),*> {
/// Construct a `MapVisitor*<T>`. /// Construct a `MapVisitor*<T>`.
pub fn new() -> Self { pub fn new() -> Self {
$visitor_name { $visitor_ty {
marker: PhantomData, marker: PhantomData,
} }
} }
} }
impl<K, V> Visitor for $visitor_name<K, V> impl<$($typaram : $bound1 $(+ $bound2)*),*> Visitor for $visitor_ty<$($typaram),*> {
where K: $($constraints +)*,
V: Deserialize,
{
type Value = $ty; type Value = $ty;
#[inline] #[inline]
@ -767,7 +762,7 @@ macro_rules! map_impl {
let mut values = $with_capacity; let mut values = $with_capacity;
while let Some((key, value)) = try!($visitor.visit()) { while let Some((key, value)) = try!($visitor.visit()) {
$insert(&mut values, key, value); values.insert(key, value);
} }
try!($visitor.end()); try!($visitor.end());
@ -776,14 +771,11 @@ macro_rules! map_impl {
} }
} }
impl<K, V> Deserialize for $ty impl<$($typaram : $bound1 $(+ $bound2)*),*> Deserialize for $ty {
where K: $($constraints +)*,
V: Deserialize,
{
fn deserialize<D>(deserializer: &mut D) -> Result<$ty, D::Error> fn deserialize<D>(deserializer: &mut D) -> Result<$ty, D::Error>
where D: Deserializer, where D: Deserializer,
{ {
deserializer.deserialize_map($visitor_name::new()) deserializer.deserialize_map($visitor_ty::new())
} }
} }
} }
@ -792,22 +784,21 @@ macro_rules! map_impl {
#[cfg(any(feature = "std", feature = "collections"))] #[cfg(any(feature = "std", feature = "collections"))]
map_impl!( map_impl!(
BTreeMap<K, V>, BTreeMap<K, V>,
<Deserialize, Eq, Ord>, BTreeMapVisitor<K: Deserialize + Eq + Ord,
BTreeMapVisitor, V: Deserialize>,
visitor, visitor,
BTreeMap::new(), BTreeMap::new(),
BTreeMap::new(), BTreeMap::new());
BTreeMap::insert);
#[cfg(feature = "std")] #[cfg(feature = "std")]
map_impl!( map_impl!(
HashMap<K, V>, HashMap<K, V, S>,
<Deserialize, Eq, Hash>, HashMapVisitor<K: Deserialize + Eq + Hash,
HashMapVisitor, V: Deserialize,
S: BuildHasher + Default>,
visitor, visitor,
HashMap::new(), HashMap::with_hasher(S::default()),
HashMap::with_capacity(visitor.size_hint().0), HashMap::with_capacity_and_hasher(visitor.size_hint().0, S::default()));
HashMap::insert);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -31,7 +31,7 @@ use collections::enum_set::{CLike, EnumSet};
#[cfg(all(feature = "nightly", feature = "collections"))] #[cfg(all(feature = "nightly", feature = "collections"))]
use collections::borrow::ToOwned; use collections::borrow::ToOwned;
use core::hash::Hash; use core::hash::{Hash, BuildHasher};
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use core::iter; use core::iter;
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -651,9 +651,10 @@ impl<K, V> Serialize for BTreeMap<K, V>
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<K, V> Serialize for HashMap<K, V> impl<K, V, H> Serialize for HashMap<K, V, H>
where K: Serialize + Eq + Hash, where K: Serialize + Eq + Hash,
V: Serialize, V: Serialize,
H: BuildHasher,
{ {
#[inline] #[inline]
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>

View File

@ -19,6 +19,7 @@ syntex_syntax = { version = "^0.35.0" }
serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] } serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] }
[dev-dependencies] [dev-dependencies]
fnv = "1.0"
rustc-serialize = "^0.3.16" rustc-serialize = "^0.3.16"
serde = { version = "*", path = "../serde" } serde = { version = "*", path = "../serde" }
syntex = "^0.35.0" syntex = "^0.35.0"

View File

@ -75,5 +75,13 @@ macro_rules! hashmap {
$(map.insert($key, $value);)+ $(map.insert($key, $value);)+
map map
} }
};
($hasher:ident @ $($key:expr => $value:expr),+) => {
{
use std::hash::BuildHasherDefault;
let mut map = HashMap::with_hasher(BuildHasherDefault::<$hasher>::default());
$(map.insert($key, $value);)+
map
}
} }
} }

View File

@ -2,6 +2,9 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::net; use std::net;
use std::path::PathBuf; use std::path::PathBuf;
extern crate fnv;
use self::fnv::FnvHasher;
use token::{ use token::{
Error, Error,
Token, Token,
@ -532,6 +535,17 @@ declare_tests! {
Token::StructStart("Anything", Some(0)), Token::StructStart("Anything", Some(0)),
Token::MapEnd, Token::MapEnd,
], ],
hashmap![FnvHasher @ 1 => 2, 3 => 4] => vec![
Token::MapStart(Some(2)),
Token::MapSep,
Token::I32(1),
Token::I32(2),
Token::MapSep,
Token::I32(3),
Token::I32(4),
Token::MapEnd,
],
} }
test_struct { test_struct {
Struct { a: 1, b: 2, c: 0 } => vec![ Struct { a: 1, b: 2, c: 0 } => vec![

View File

@ -1,10 +1,13 @@
use std::collections::BTreeMap; use std::collections::{BTreeMap, HashMap};
use std::net; use std::net;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str; use std::str;
use token::{self, Token}; use token::{self, Token};
extern crate fnv;
use self::fnv::FnvHasher;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#[derive(Serialize)] #[derive(Serialize)]
@ -204,6 +207,19 @@ declare_ser_tests! {
Token::MapEnd, Token::MapEnd,
], ],
} }
test_hashmap {
hashmap![FnvHasher @ 1 => 2, 3 => 4] => &[
Token::MapStart(Some(2)),
Token::MapSep,
Token::I32(1),
Token::I32(2),
Token::MapSep,
Token::I32(3),
Token::I32(4),
Token::MapEnd,
],
}
test_unit_struct { test_unit_struct {
UnitStruct => &[Token::UnitStruct("UnitStruct")], UnitStruct => &[Token::UnitStruct("UnitStruct")],
} }