Skip to content

Commit

Permalink
feat: add optional support for hasbrown Map & Set
Browse files Browse the repository at this point in the history
  • Loading branch information
OliverNChalk committed Aug 15, 2023
1 parent bc517f1 commit 96bd441
Show file tree
Hide file tree
Showing 11 changed files with 432 additions and 15 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions serde_with/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ time_0_3 = ["dep:time_0_3"]
base64 = {version = "0.21.0", optional = true, default-features = false}
chrono_0_4 = {package = "chrono", version = "0.4.20", optional = true, default-features = false, features = ["serde"]}
doc-comment = {version = "0.3.3", optional = true}
hashbrown = {version = "0.14.0", optional = true, features = ["serde"]}
hex = {version = "0.4.3", optional = true, default-features = false}
indexmap_1 = {package = "indexmap", version = "1.8", optional = true, default-features = false, features = ["serde-1"]}
indexmap_2 = {package = "indexmap", version = "2.0", optional = true, default-features = false, features = ["serde"]}
Expand Down Expand Up @@ -112,6 +113,11 @@ name = "hex"
path = "tests/hex.rs"
required-features = ["hex", "macros"]

[[test]]
name = "hashbrown"
path = "tests/hashbrown.rs"
required-features = ["hashbrown", "macros"]

[[test]]
name = "indexmap_1"
path = "tests/indexmap_1.rs"
Expand Down
2 changes: 2 additions & 0 deletions serde_with/src/de/duplicates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::{
prelude::*,
MapFirstKeyWins, MapPreventDuplicates, SetLastValueWins, SetPreventDuplicates,
};
#[cfg(feature = "hashbrown")]
use hashbrown::{HashMap as HashbrownMap, HashSet as HashbrownSet};
#[cfg(feature = "indexmap_1")]
use indexmap_1::{IndexMap, IndexSet};
#[cfg(feature = "indexmap_2")]
Expand Down
17 changes: 17 additions & 0 deletions serde_with/src/de/impls.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::{formats::*, prelude::*};
#[cfg(feature = "hashbrown")]
use hashbrown::{HashMap as HashbrownMap, HashSet as HashbrownSet};
#[cfg(feature = "indexmap_1")]
use indexmap_1::{IndexMap, IndexSet};
#[cfg(feature = "indexmap_2")]
Expand All @@ -16,6 +18,8 @@ macro_rules! foreach_map {
$m!(BTreeMap<K: Ord, V>);
#[cfg(feature = "std")]
$m!(HashMap<K: Eq + Hash, V, H: Sized>);
#[cfg(all(feature = "std", feature = "hashbrown"))]
$m!(HashbrownMap<K: Eq + Hash, V, H: Sized>);
#[cfg(all(feature = "std", feature = "indexmap_1"))]
$m!(IndexMap<K: Eq + Hash, V, H: Sized>);
#[cfg(all(feature = "std", feature = "indexmap_2"))]
Expand All @@ -33,6 +37,11 @@ macro_rules! foreach_map_create {
HashMap<K: Eq + Hash, V, S: BuildHasher + Default>,
(|size| HashMap::with_capacity_and_hasher(size, Default::default()))
);
#[cfg(feature = "hashbrown")]
$m!(
HashbrownMap<K: Eq + Hash, V, S: BuildHasher + Default>,
(|size| HashbrownMap::with_capacity_and_hasher(size, Default::default()))
);
#[cfg(feature = "indexmap_1")]
$m!(
IndexMap<K: Eq + Hash, V, S: BuildHasher + Default>,
Expand All @@ -53,6 +62,8 @@ macro_rules! foreach_set {
$m!(BTreeSet<(K, V): Ord>);
#[cfg(feature = "std")]
$m!(HashSet<(K, V): Eq + Hash>);
#[cfg(all(feature = "std", feature = "hashbrown"))]
$m!(HashbrownSet<(K, V): Eq + Hash>);
#[cfg(all(feature = "std", feature = "indexmap_1"))]
$m!(IndexSet<(K, V): Eq + Hash>);
#[cfg(all(feature = "std", feature = "indexmap_2"))]
Expand All @@ -71,6 +82,12 @@ macro_rules! foreach_set_create {
(|size| HashSet::with_capacity_and_hasher(size, S::default())),
insert
);
#[cfg(feature = "hashbrown")]
$m!(
HashbrownSet<T: Eq + Hash, S: BuildHasher + Default>,
(|size| HashbrownSet::with_capacity_and_hasher(size, S::default())),
insert
);
#[cfg(feature = "indexmap_1")]
$m!(
IndexSet<T: Eq + Hash, S: BuildHasher + Default>,
Expand Down
40 changes: 40 additions & 0 deletions serde_with/src/duplicate_key_impls/error_on_duplicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,26 @@ where
}
}

#[cfg(feature = "hashbrown")]
impl<T, S> PreventDuplicateInsertsSet<T> for hashbrown::HashSet<T, S>
where
T: Eq + Hash,
S: BuildHasher + Default,
{
#[inline]
fn new(size_hint: Option<usize>) -> Self {
match size_hint {
Some(size) => Self::with_capacity_and_hasher(size, S::default()),
None => Self::with_hasher(S::default()),
}
}

#[inline]
fn insert(&mut self, value: T) -> bool {
self.insert(value)
}
}

#[cfg(feature = "indexmap_1")]
impl<T, S> PreventDuplicateInsertsSet<T> for indexmap_1::IndexSet<T, S>
where
Expand Down Expand Up @@ -109,6 +129,26 @@ where
}
}

#[cfg(feature = "hashbrown")]
impl<K, V, S> PreventDuplicateInsertsMap<K, V> for hashbrown::HashMap<K, V, S>
where
K: Eq + Hash,
S: BuildHasher + Default,
{
#[inline]
fn new(size_hint: Option<usize>) -> Self {
match size_hint {
Some(size) => Self::with_capacity_and_hasher(size, S::default()),
None => Self::with_hasher(S::default()),
}
}

#[inline]
fn insert(&mut self, key: K, value: V) -> bool {
self.insert(key, value).is_none()
}
}

#[cfg(feature = "indexmap_1")]
impl<K, V, S> PreventDuplicateInsertsMap<K, V> for indexmap_1::IndexMap<K, V, S>
where
Expand Down
28 changes: 28 additions & 0 deletions serde_with/src/duplicate_key_impls/first_value_wins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,34 @@ where
}
}

#[cfg(feature = "hashbrown")]
impl<K, V, S> DuplicateInsertsFirstWinsMap<K, V> for hashbrown::HashMap<K, V, S>
where
K: Eq + Hash,
S: BuildHasher + Default,
{
#[inline]
fn new(size_hint: Option<usize>) -> Self {
match size_hint {
Some(size) => Self::with_capacity_and_hasher(size, S::default()),
None => Self::with_hasher(S::default()),
}
}

#[inline]
fn insert(&mut self, key: K, value: V) {
use hashbrown::hash_map::Entry;

match self.entry(key) {
// we want to keep the first value, so do nothing
Entry::Occupied(_) => {}
Entry::Vacant(vacant) => {
vacant.insert(value);
}
}
}
}

#[cfg(feature = "indexmap_1")]
impl<K, V, S> DuplicateInsertsFirstWinsMap<K, V> for indexmap_1::IndexMap<K, V, S>
where
Expand Down
21 changes: 21 additions & 0 deletions serde_with/src/duplicate_key_impls/last_value_wins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@ where
}
}

#[cfg(feature = "hashbrown")]
impl<T, S> DuplicateInsertsLastWinsSet<T> for hashbrown::HashSet<T, S>
where
T: Eq + Hash,
S: BuildHasher + Default,
{
#[inline]
fn new(size_hint: Option<usize>) -> Self {
match size_hint {
Some(size) => Self::with_capacity_and_hasher(size, S::default()),
None => Self::with_hasher(S::default()),
}
}

#[inline]
fn replace(&mut self, value: T) {
// Hashset already fulfils the contract
self.replace(value);
}
}

#[cfg(feature = "indexmap_1")]
impl<T, S> DuplicateInsertsLastWinsSet<T> for indexmap_1::IndexSet<T, S>
where
Expand Down
32 changes: 21 additions & 11 deletions serde_with/src/guide/feature_flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ Each entry will explain the feature in more detail.
`serde_with` is fully `no_std` compatible.
Using it in a `no_std` environment requires using `default-features = false`, since `std` is enabled by default.

1. [`alloc`](#alloc)
2. [`std` (default)](#std-default)
3. [`base64`](#base64)
4. [`chrono_0_4`](#chrono_0_4)
5. [`guide`](#guide)
6. [`hex`](#hex)
7. [`indexmap_1`](#indexmap_1)
8. [`indexmap_2`](#indexmap_2)
9. [`json`](#json)
10. [`macros` (default)](#macros-default)
11. [`time_0_3`](#time_0_3)
- [Available Feature Flags](#available-feature-flags)
- [`alloc`](#alloc)
- [`std` (default)](#std-default)
- [`base64`](#base64)
- [`chrono_0_4`](#chrono_0_4)
- [`guide`](#guide)
- [`hashbrown`](#hashbrown)
- [`hex`](#hex)
- [`indexmap_1`](#indexmap_1)
- [`indexmap_2`](#indexmap_2)
- [`json`](#json)
- [`macros` (default)](#macros-default)
- [`time_0_3`](#time_0_3)

## `alloc`

Expand Down Expand Up @@ -49,6 +51,14 @@ This pulls in `chrono` v0.4 as a dependency.
The `guide` feature enables inclusion of this user guide.
The feature only changes the rustdoc output and enables no other effects.

## `hashbrown`

The `hashbrown` feature enables `hashbown::{HashMap, HashSet}` as supported containers.

This pulls in `hashbrown` as a dependency.
It enables the `alloc` feature.
Some functionality is only available when `std` is enabled too.

## `hex`

The `hex` feature enables serializing data in hex format.
Expand Down
2 changes: 2 additions & 0 deletions serde_with/src/ser/duplicates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use super::impls::{foreach_map, foreach_set};
use crate::{
prelude::*, MapFirstKeyWins, MapPreventDuplicates, SetLastValueWins, SetPreventDuplicates,
};
#[cfg(feature = "hashbrown")]
use hashbrown::{HashMap as HashbrownMap, HashSet as HashbrownSet};
#[cfg(feature = "indexmap_1")]
use indexmap_1::{IndexMap, IndexSet};
#[cfg(feature = "indexmap_2")]
Expand Down
14 changes: 10 additions & 4 deletions serde_with/src/ser/impls.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::{formats, formats::Strictness, prelude::*};
#[cfg(feature = "hashbrown")]
use hashbrown::{HashMap as HashbrownMap, HashSet as HashbrownSet};
#[cfg(feature = "indexmap_1")]
use indexmap_1::{IndexMap, IndexSet};
#[cfg(feature = "indexmap_2")]
Expand All @@ -17,9 +19,11 @@ macro_rules! foreach_map {
$m!(BTreeMap<K, V>);
#[cfg(feature = "std")]
$m!(HashMap<K, V, H: Sized>);
#[cfg(all(feature = "indexmap_1"))]
#[cfg(feature = "hashbrown")]
$m!(HashbrownMap<K, V, H: Sized>);
#[cfg(feature = "indexmap_1")]
$m!(IndexMap<K, V, H: Sized>);
#[cfg(all(feature = "indexmap_2"))]
#[cfg(feature = "indexmap_2")]
$m!(IndexMap2<K, V, H: Sized>);
};
}
Expand All @@ -31,9 +35,11 @@ macro_rules! foreach_set {
$m!(BTreeSet<$T>);
#[cfg(feature = "std")]
$m!(HashSet<$T, H: Sized>);
#[cfg(all(feature = "indexmap_1"))]
#[cfg(feature = "hashbrown")]
$m!(HashbrownSet<$T, H: Sized>);
#[cfg(feature = "indexmap_1")]
$m!(IndexSet<$T, H: Sized>);
#[cfg(all(feature = "indexmap_2"))]
#[cfg(feature = "indexmap_2")]
$m!(IndexSet2<$T, H: Sized>);
};
($m:ident) => {
Expand Down
Loading

0 comments on commit 96bd441

Please sign in to comment.