Skip to content

Commit

Permalink
Serialization support (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
GarkGarcia authored Apr 4, 2020
1 parent d1f67c2 commit 7a27f38
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 4 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ sanitize = ['crossbeam-epoch/sanitize']
crossbeam-epoch = "0.8.2"
parking_lot = "0.10"
num_cpus = "1.12.0"
serde = {version = "1.0.105", optional = true}

[dependencies.ahash]
version = "0.3.2"
Expand All @@ -35,6 +36,7 @@ default-features = false
rand = "0.7"
rayon = "1.3"
criterion = "0.3"
serde_json = "1.0.50"

[[bench]]
name = "flurry_dashmap"
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ mod raw;
mod set;
mod set_ref;

#[cfg(feature = "serde")]
mod serde_impls;

/// Iterator types.
pub mod iter;

Expand Down
216 changes: 216 additions & 0 deletions src/serde_impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
use crate::{HashMap, HashMapRef, HashSet, HashSetRef};
use serde::{
de::{MapAccess, SeqAccess, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::fmt::{self, Formatter};
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;

struct HashMapVisitor<K, V, S> {
key_marker: PhantomData<K>,
value_marker: PhantomData<V>,
hash_builder_marker: PhantomData<S>,
}

impl<K, V, S> Serialize for HashMapRef<'_, K, V, S>
where
K: Serialize,
V: Serialize,
{
fn serialize<Sr>(&self, serializer: Sr) -> Result<Sr::Ok, Sr::Error>
where
Sr: Serializer,
{
serializer.collect_map(self.iter())
}
}

impl<K, V, S> Serialize for HashMap<K, V, S>
where
K: Serialize,
V: Serialize,
{
fn serialize<Sr>(&self, serializer: Sr) -> Result<Sr::Ok, Sr::Error>
where
Sr: Serializer,
{
self.pin().serialize(serializer)
}
}

impl<'de, K, V, S> Deserialize<'de> for HashMap<K, V, S>
where
K: 'static + Deserialize<'de> + Send + Sync + Hash + Clone + Eq,
V: 'static + Deserialize<'de> + Send + Sync + Eq,
S: Default + BuildHasher,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(HashMapVisitor::new())
}
}

impl<K, V, S> HashMapVisitor<K, V, S> {
pub(crate) fn new() -> Self {
Self {
key_marker: PhantomData,
value_marker: PhantomData,
hash_builder_marker: PhantomData,
}
}
}

impl<'de, K, V, S> Visitor<'de> for HashMapVisitor<K, V, S>
where
K: 'static + Deserialize<'de> + Send + Sync + Hash + Clone + Eq,
V: 'static + Deserialize<'de> + Send + Sync + Eq,
S: Default + BuildHasher,
{
type Value = HashMap<K, V, S>;

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

fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let map = match access.size_hint() {
Some(n) => HashMap::with_capacity_and_hasher(n, S::default()),
None => HashMap::with_hasher(S::default()),
};
let guard = map.guard();

while let Some((key, value)) = access.next_entry()? {
if let Some(_old_value) = map.insert(key, value, &guard) {
unreachable!("Serialized map held two values with the same key");
}
}

Ok(map)
}
}

impl<T, S> Serialize for HashSetRef<'_, T, S>
where
T: Serialize,
{
fn serialize<Sr>(&self, serilizer: Sr) -> Result<Sr::Ok, Sr::Error>
where
Sr: Serializer,
{
serilizer.collect_seq(self.iter())
}
}

impl<T, S> Serialize for HashSet<T, S>
where
T: Serialize,
{
fn serialize<Sr>(&self, serializer: Sr) -> Result<Sr::Ok, Sr::Error>
where
Sr: Serializer,
{
self.pin().serialize(serializer)
}
}

impl<'de, T, S> Deserialize<'de> for HashSet<T, S>
where
T: 'static + Deserialize<'de> + Send + Sync + Hash + Clone + Eq,
S: Default + BuildHasher,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(HashSetVisitor::new())
}
}

struct HashSetVisitor<T, S> {
type_marker: PhantomData<T>,
hash_builder_marker: PhantomData<S>,
}

impl<T, S> HashSetVisitor<T, S> {
pub(crate) fn new() -> Self {
Self {
type_marker: PhantomData,
hash_builder_marker: PhantomData,
}
}
}

impl<'de, T, S> Visitor<'de> for HashSetVisitor<T, S>
where
T: 'static + Deserialize<'de> + Send + Sync + Hash + Clone + Eq,
S: Default + BuildHasher,
{
type Value = HashSet<T, S>;

fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "a set")
}

fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let set = HashSet::default();
let guard = set.guard();

while let Some(value) = access.next_element()? {
let _ = set.insert(value, &guard);
}

Ok(set)
}
}

#[cfg(test)]
mod test {
use crate::{HashMap, HashSet};

#[test]
fn test_map() {
let map: HashMap<u8, u8> = HashMap::with_capacity(5);
let guard = map.guard();

let _ = map.insert(0, 4, &guard);
let _ = map.insert(1, 3, &guard);
let _ = map.insert(2, 2, &guard);
let _ = map.insert(3, 1, &guard);
let _ = map.insert(4, 0, &guard);

let serialized = serde_json::to_string(&map).expect("Couldn't serialize map");

let deserialized: HashMap<u8, u8> =
serde_json::from_str(&serialized).expect("Couldn't deserialize map");

assert_eq!(map, deserialized);
}

#[test]
fn test_set() {
let set: HashSet<u8> = HashSet::with_capacity(5);
let guard = set.guard();

let _ = set.insert(0, &guard);
let _ = set.insert(1, &guard);
let _ = set.insert(2, &guard);
let _ = set.insert(3, &guard);
let _ = set.insert(4, &guard);

let serialized = serde_json::to_string(&set).expect("Couldn't serialize map");

let deserialized: HashSet<u8> =
serde_json::from_str(&serialized).expect("Couldn't deserialize map");

assert_eq!(set, deserialized);
}
}
7 changes: 3 additions & 4 deletions src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
//!
//! See `HashSet` for details.
use crate::epoch::Guard;
use crate::iter::Keys;
use crate::HashMap;
use std::borrow::Borrow;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};
use std::iter::FromIterator;

use crate::epoch::Guard;
use crate::iter::Keys;
use crate::HashMap;

/// A concurrent hash set implemented as a `HashMap` where the value is `()`.
///
/// # Examples
Expand Down

0 comments on commit 7a27f38

Please sign in to comment.