Skip to content

Commit

Permalink
Auto merge of #449 - tomcc-reactor:master, r=Amanieu
Browse files Browse the repository at this point in the history
Allow serializing `HashMap`s that use a custom allocator

Hi,
I'm using `HashMap` with custom allocators (eg. not `Global`) in my project, and I got hit with a "`HashMap` doesn't implement trait `Serialize`" error.

It looks like it has a very trivial fix, eg. exposing the `A` generic parameter on the impl so that it doesn't default to `Global`.

I have a very limited understanding of HashBrown so let me know if this is a change that makes sense!
- Is `crate::raw::Allocator` the right way to import the `Allocator` trait?
- Do you need `Deserialize` to be fixed as well?
- What about `HashSet`?

Anyway, if the change makes sense I can try to clean it up a bit more :)
  • Loading branch information
bors committed Aug 22, 2023
2 parents b2190e2 + 065b6ee commit 5e578e7
Showing 1 changed file with 41 additions and 22 deletions.
63 changes: 41 additions & 22 deletions src/external_trait_impls/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod size_hint {
}

mod map {
use crate::raw::Allocator;
use core::fmt;
use core::hash::{BuildHasher, Hash};
use core::marker::PhantomData;
Expand All @@ -21,11 +22,12 @@ mod map {

use super::size_hint;

impl<K, V, H> Serialize for HashMap<K, V, H>
impl<K, V, H, A> Serialize for HashMap<K, V, H, A>
where
K: Serialize + Eq + Hash,
V: Serialize,
H: BuildHasher,
A: Allocator + Clone,
{
#[cfg_attr(feature = "inline-more", inline)]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
Expand All @@ -36,40 +38,46 @@ mod map {
}
}

impl<'de, K, V, S> Deserialize<'de> for HashMap<K, V, S>
impl<'de, K, V, S, A> Deserialize<'de> for HashMap<K, V, S, A>
where
K: Deserialize<'de> + Eq + Hash,
V: Deserialize<'de>,
S: BuildHasher + Default,
A: Allocator + Clone + Default,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct MapVisitor<K, V, S> {
marker: PhantomData<HashMap<K, V, S>>,
struct MapVisitor<K, V, S, A>
where
A: Allocator + Clone,
{
marker: PhantomData<HashMap<K, V, S, A>>,
}

impl<'de, K, V, S> Visitor<'de> for MapVisitor<K, V, S>
impl<'de, K, V, S, A> Visitor<'de> for MapVisitor<K, V, S, A>
where
K: Deserialize<'de> + Eq + Hash,
V: Deserialize<'de>,
S: BuildHasher + Default,
A: Allocator + Clone + Default,
{
type Value = HashMap<K, V, S>;
type Value = HashMap<K, V, S, A>;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a map")
}

#[cfg_attr(feature = "inline-more", inline)]
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
where
A: MapAccess<'de>,
M: MapAccess<'de>,
{
let mut values = HashMap::with_capacity_and_hasher(
let mut values = HashMap::with_capacity_and_hasher_in(
size_hint::cautious(map.size_hint()),
S::default(),
A::default(),
);

while let Some((key, value)) = map.next_entry()? {
Expand All @@ -89,6 +97,7 @@ mod map {
}

mod set {
use crate::raw::Allocator;
use core::fmt;
use core::hash::{BuildHasher, Hash};
use core::marker::PhantomData;
Expand All @@ -99,10 +108,11 @@ mod set {

use super::size_hint;

impl<T, H> Serialize for HashSet<T, H>
impl<T, H, A> Serialize for HashSet<T, H, A>
where
T: Serialize + Eq + Hash,
H: BuildHasher,
A: Allocator + Clone,
{
#[cfg_attr(feature = "inline-more", inline)]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
Expand All @@ -113,38 +123,44 @@ mod set {
}
}

impl<'de, T, S> Deserialize<'de> for HashSet<T, S>
impl<'de, T, S, A> Deserialize<'de> for HashSet<T, S, A>
where
T: Deserialize<'de> + Eq + Hash,
S: BuildHasher + Default,
A: Allocator + Clone + Default,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct SeqVisitor<T, S> {
marker: PhantomData<HashSet<T, S>>,
struct SeqVisitor<T, S, A>
where
A: Allocator + Clone,
{
marker: PhantomData<HashSet<T, S, A>>,
}

impl<'de, T, S> Visitor<'de> for SeqVisitor<T, S>
impl<'de, T, S, A> Visitor<'de> for SeqVisitor<T, S, A>
where
T: Deserialize<'de> + Eq + Hash,
S: BuildHasher + Default,
A: Allocator + Clone + Default,
{
type Value = HashSet<T, S>;
type Value = HashSet<T, S, A>;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a sequence")
}

#[cfg_attr(feature = "inline-more", inline)]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
fn visit_seq<M>(self, mut seq: M) -> Result<Self::Value, M::Error>
where
A: SeqAccess<'de>,
M: SeqAccess<'de>,
{
let mut values = HashSet::with_capacity_and_hasher(
let mut values = HashSet::with_capacity_and_hasher_in(
size_hint::cautious(seq.size_hint()),
S::default(),
A::default(),
);

while let Some(value) = seq.next_element()? {
Expand All @@ -166,12 +182,15 @@ mod set {
where
D: Deserializer<'de>,
{
struct SeqInPlaceVisitor<'a, T, S>(&'a mut HashSet<T, S>);
struct SeqInPlaceVisitor<'a, T, S, A>(&'a mut HashSet<T, S, A>)
where
A: Allocator + Clone;

impl<'a, 'de, T, S> Visitor<'de> for SeqInPlaceVisitor<'a, T, S>
impl<'a, 'de, T, S, A> Visitor<'de> for SeqInPlaceVisitor<'a, T, S, A>
where
T: Deserialize<'de> + Eq + Hash,
S: BuildHasher + Default,
A: Allocator + Clone,
{
type Value = ();

Expand All @@ -180,9 +199,9 @@ mod set {
}

#[cfg_attr(feature = "inline-more", inline)]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
fn visit_seq<M>(self, mut seq: M) -> Result<Self::Value, M::Error>
where
A: SeqAccess<'de>,
M: SeqAccess<'de>,
{
self.0.clear();
self.0.reserve(size_hint::cautious(seq.size_hint()));
Expand Down

0 comments on commit 5e578e7

Please sign in to comment.