diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs index ed727aa2..ad3d39eb 100644 --- a/serde/src/de/impls.rs +++ b/serde/src/de/impls.rs @@ -32,7 +32,7 @@ use collections::enum_set::{CLike, EnumSet}; #[cfg(all(feature = "nightly", feature = "collections"))] use collections::borrow::ToOwned; -use core::hash::Hash; +use core::hash::{Hash, BuildHasher}; use core::marker::PhantomData; #[cfg(feature = "std")] use std::net; @@ -726,31 +726,26 @@ tuple_impls! { macro_rules! map_impl { ( $ty:ty, - < $($constraints:ident),* >, - $visitor_name:ident, + $visitor_ty:ident < $($typaram:ident : $bound1:ident $(+ $bound2:ident)*),* >, $visitor:ident, $ctor:expr, - $with_capacity:expr, - $insert:expr + $with_capacity:expr ) => { /// A visitor that produces a map. - pub struct $visitor_name { + pub struct $visitor_ty<$($typaram),*> { marker: PhantomData<$ty>, } - impl $visitor_name { + impl<$($typaram : $bound1 $(+ $bound2)*),*> $visitor_ty<$($typaram),*> { /// Construct a `MapVisitor*`. pub fn new() -> Self { - $visitor_name { + $visitor_ty { marker: PhantomData, } } } - impl Visitor for $visitor_name - where K: $($constraints +)*, - V: Deserialize, - { + impl<$($typaram : $bound1 $(+ $bound2)*),*> Visitor for $visitor_ty<$($typaram),*> { type Value = $ty; #[inline] @@ -767,7 +762,7 @@ macro_rules! map_impl { let mut values = $with_capacity; while let Some((key, value)) = try!($visitor.visit()) { - $insert(&mut values, key, value); + values.insert(key, value); } try!($visitor.end()); @@ -776,14 +771,11 @@ macro_rules! map_impl { } } - impl Deserialize for $ty - where K: $($constraints +)*, - V: Deserialize, - { + impl<$($typaram : $bound1 $(+ $bound2)*),*> Deserialize for $ty { fn deserialize(deserializer: &mut D) -> Result<$ty, D::Error> 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"))] map_impl!( BTreeMap, - , - BTreeMapVisitor, + BTreeMapVisitor, visitor, BTreeMap::new(), - BTreeMap::new(), - BTreeMap::insert); + BTreeMap::new()); #[cfg(feature = "std")] map_impl!( - HashMap, - , - HashMapVisitor, + HashMap, + HashMapVisitor, visitor, - HashMap::new(), - HashMap::with_capacity(visitor.size_hint().0), - HashMap::insert); + HashMap::with_hasher(S::default()), + HashMap::with_capacity_and_hasher(visitor.size_hint().0, S::default())); /////////////////////////////////////////////////////////////////////////////// diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index b51226a9..a05ae862 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -31,7 +31,7 @@ use collections::enum_set::{CLike, EnumSet}; #[cfg(all(feature = "nightly", feature = "collections"))] use collections::borrow::ToOwned; -use core::hash::Hash; +use core::hash::{Hash, BuildHasher}; #[cfg(feature = "nightly")] use core::iter; #[cfg(feature = "std")] @@ -651,9 +651,10 @@ impl Serialize for BTreeMap } #[cfg(feature = "std")] -impl Serialize for HashMap +impl Serialize for HashMap where K: Serialize + Eq + Hash, V: Serialize, + H: BuildHasher, { #[inline] fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> diff --git a/serde_tests/Cargo.toml b/serde_tests/Cargo.toml index adb7a940..47792176 100644 --- a/serde_tests/Cargo.toml +++ b/serde_tests/Cargo.toml @@ -19,6 +19,7 @@ syntex_syntax = { version = "^0.35.0" } serde_codegen = { version = "*", path = "../serde_codegen", features = ["with-syntex"] } [dev-dependencies] +fnv = "1.0" rustc-serialize = "^0.3.16" serde = { version = "*", path = "../serde" } syntex = "^0.35.0" diff --git a/serde_tests/tests/macros.rs b/serde_tests/tests/macros.rs index 069d4f26..c0b38b3d 100644 --- a/serde_tests/tests/macros.rs +++ b/serde_tests/tests/macros.rs @@ -75,5 +75,13 @@ macro_rules! hashmap { $(map.insert($key, $value);)+ 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 + } } } diff --git a/serde_tests/tests/test_de.rs b/serde_tests/tests/test_de.rs index 932b4b10..8081b9ea 100644 --- a/serde_tests/tests/test_de.rs +++ b/serde_tests/tests/test_de.rs @@ -2,6 +2,9 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::net; use std::path::PathBuf; +extern crate fnv; +use self::fnv::FnvHasher; + use token::{ Error, Token, @@ -532,6 +535,17 @@ declare_tests! { Token::StructStart("Anything", Some(0)), 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 { Struct { a: 1, b: 2, c: 0 } => vec![ diff --git a/serde_tests/tests/test_ser.rs b/serde_tests/tests/test_ser.rs index 2a8117a1..4b6e4c70 100644 --- a/serde_tests/tests/test_ser.rs +++ b/serde_tests/tests/test_ser.rs @@ -1,10 +1,13 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use std::net; use std::path::{Path, PathBuf}; use std::str; use token::{self, Token}; +extern crate fnv; +use self::fnv::FnvHasher; + ////////////////////////////////////////////////////////////////////////// #[derive(Serialize)] @@ -204,6 +207,19 @@ declare_ser_tests! { 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 { UnitStruct => &[Token::UnitStruct("UnitStruct")], }