Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialization support #79

Merged
merged 19 commits into from
Apr 4, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
39d3761
Implemented `serde::Serialize` for `HashMapRef`
GarkGarcia Mar 27, 2020
5d0bb3c
Merge branch 'master' of https://github.com/jonhoo/flurry
GarkGarcia Mar 27, 2020
668f363
Implemented `serde::Serialize` for `HashSetRef`
GarkGarcia Mar 27, 2020
4d344a7
Implemented `serde::Serialize` for `HashMap` and `HashSet`
GarkGarcia Mar 27, 2020
70e5e73
Implemented `serde::Deserialize` for `HashMap`
GarkGarcia Mar 28, 2020
78d9e1d
Made serialization an optional feature
GarkGarcia Mar 28, 2020
fd193df
Update src/map.rs
GarkGarcia Mar 28, 2020
0863d9e
Update Cargo.toml
GarkGarcia Mar 28, 2020
907b6bb
Removed the `serialize` feature in favor of `serde`
GarkGarcia Mar 28, 2020
6942c79
Replaced `HashMap::with_capacity(0)` by `HashMap::new()` in the imple…
GarkGarcia Mar 28, 2020
6f1dec3
Made the implementation of `Deserialize` for `HashMap` generic over `…
GarkGarcia Mar 29, 2020
3f93169
Implemented `Deserialize` for `HashSet`
GarkGarcia Mar 29, 2020
0cea56c
Fixed compiletime errors
GarkGarcia Mar 29, 2020
9822de1
Optimized the implementation of `Deserialize` for `HashMap` by preall…
GarkGarcia Mar 29, 2020
99ca146
Removed the usage of the `todo!` macro
GarkGarcia Mar 31, 2020
b483438
Fixed compile time erros
GarkGarcia Mar 31, 2020
9d7aef9
Fixed the `Deserialize::expecting` implementations
GarkGarcia Mar 31, 2020
c85a482
Moved the `Serialize` and `Deserialize` implementations to a separate…
GarkGarcia Apr 2, 2020
6464ff9
Added rudimentary test of the implementations of `Serialize` and `Des…
GarkGarcia Apr 2, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 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 Down
87 changes: 87 additions & 0 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ use crate::iter::*;
use crate::node::*;
use crate::raw::*;
use crossbeam_epoch::{self as epoch, Atomic, Guard, Owned, Shared};
#[cfg(feature = "serde")]
use serde::{
de::{MapAccess, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::borrow::Borrow;
use std::error::Error;
use std::fmt::{self, Debug, Display, Formatter};
use std::hash::{BuildHasher, Hash, Hasher};
use std::iter::FromIterator;
#[cfg(feature = "serde")]
use std::marker::PhantomData;
use std::sync::{
atomic::{AtomicIsize, AtomicUsize, Ordering},
Once,
Expand Down Expand Up @@ -2353,6 +2360,86 @@ where
}
}

#[cfg(feature = "serde")]
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)
}
}

#[cfg(feature = "serde")]
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())
}
}

#[cfg(feature = "serde")]
struct HashMapVisitor<K, V, S> {
key_marker: PhantomData<K>,
value_marker: PhantomData<V>,
hash_builder_marker: PhantomData<S>,
}

#[cfg(feature = "serde")]
impl<K, V, S> HashMapVisitor<K, V, S> {
pub(crate) fn new() -> Self {
Self {
key_marker: PhantomData,
value_marker: PhantomData,
hash_builder_marker: PhantomData,
}
}
}

#[cfg(feature = "serde")]
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 could no be deserialized");
}

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)
}
}

#[cfg(not(miri))]
#[inline]
/// Returns the number of physical CPUs in the machine (_O(1)_).
Expand Down
16 changes: 16 additions & 0 deletions src/map_ref.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::iter::*;
use crate::{GuardRef, HashMap, TryInsertError};
use crossbeam_epoch::Guard;
#[cfg(feature = "serde")]
use serde::{Serialize, Serializer};
use std::borrow::Borrow;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};
Expand Down Expand Up @@ -304,3 +306,17 @@ where
self.get(key).expect("no entry found for key")
}
}

#[cfg(feature = "serde")]
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())
}
}
78 changes: 78 additions & 0 deletions src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@
//!
//! See `HashSet` for details.

#[cfg(feature = "serde")]
use serde::{
de::{SeqAccess, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::borrow::Borrow;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};
use std::iter::FromIterator;
#[cfg(feature = "serde")]
use std::marker::PhantomData;

use crate::epoch::Guard;
use crate::iter::Keys;
Expand Down Expand Up @@ -600,3 +607,74 @@ where
}
}
}

#[cfg(feature = "serde")]
impl<T, S> Serialize for HashSet<T, S>
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
where
T: Serialize,
{
fn serialize<Sr>(&self, serializer: Sr) -> Result<Sr::Ok, Sr::Error>
where
Sr: Serializer,
{
self.pin().serialize(serializer)
}
}

#[cfg(feature = "serde")]
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())
}
}

#[cfg(feature = "serde")]
struct HashSetVisitor<T, S> {
type_marker: PhantomData<T>,
hash_builder_marker: PhantomData<S>,
}

#[cfg(feature = "serde")]
impl<T, S> HashSetVisitor<T, S> {
pub(crate) fn new() -> Self {
Self {
type_marker: PhantomData,
hash_builder_marker: PhantomData,
}
}
}

#[cfg(feature = "serde")]
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>;

// TODO: Create an error message
GarkGarcia marked this conversation as resolved.
Show resolved Hide resolved
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "a set could not be parsed");
}

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)
}
}
15 changes: 15 additions & 0 deletions src/set_ref.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::iter::*;
use crate::{GuardRef, HashSet};
use crossbeam_epoch::Guard;
#[cfg(feature = "serde")]
use serde::{Serialize, Serializer};
use std::borrow::Borrow;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};
Expand Down Expand Up @@ -235,3 +237,16 @@ where
S: BuildHasher,
{
}

#[cfg(feature = "serde")]
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())
}
}