Skip to content

Commit

Permalink
Merge #226
Browse files Browse the repository at this point in the history
226: Add serde support r=Kerollmops a=irevoire

Add support for serde to make our serialize function easier to use.

Co-authored-by: Irevoire <[email protected]>
Co-authored-by: Tamo <[email protected]>
  • Loading branch information
bors[bot] and irevoire authored Sep 1, 2022
2 parents 7f5627b + c2cb09a commit 28db3cb
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 1 deletion.
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --features serde

- name: Test benchmarks
uses: actions-rs/cargo@v1
Expand Down
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ license = "MIT OR Apache-2.0"
bytemuck = "1.7.3"
byteorder = "1.4.3"
retain_mut = "=0.1.7"
serde = { version = "1.0.139", optional = true }

[features]
simd = []

[dev-dependencies]
proptest = { version = "1.0.0" }
proptest = "1.0.0"
serde_json = "1.0.85"
bincode = "1.3.3"

[profile.test]
opt-level = 2
2 changes: 2 additions & 0 deletions src/bitmap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ mod cmp;
mod inherent;
mod iter;
mod ops;
#[cfg(feature = "serde")]
mod serde;
mod serialization;

use self::cmp::Pairs;
Expand Down
82 changes: 82 additions & 0 deletions src/bitmap/serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use serde::de::SeqAccess;
use serde::de::Visitor;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;

use crate::RoaringBitmap;

impl<'de> Deserialize<'de> for RoaringBitmap {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct BitmapVisitor;

impl<'de> Visitor<'de> for BitmapVisitor {
type Value = RoaringBitmap;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("roaring bitmap")
}

fn visit_bytes<E>(self, bytes: &[u8]) -> Result<RoaringBitmap, E>
where
E: serde::de::Error,
{
RoaringBitmap::deserialize_from(bytes).map_err(serde::de::Error::custom)
}

// in some case bytes will be serialized as a sequence thus we need to accept both
// even if it means non optimal performance
fn visit_seq<A>(self, mut seq: A) -> Result<RoaringBitmap, A::Error>
where
A: SeqAccess<'de>,
{
let mut bytes: Vec<u8> = Vec::new();
while let Some(el) = seq.next_element()? {
bytes.push(el);
}
RoaringBitmap::deserialize_from(&*bytes).map_err(serde::de::Error::custom)
}
}

deserializer.deserialize_bytes(BitmapVisitor)
}
}

impl Serialize for RoaringBitmap {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut buf = Vec::new();
self.serialize_into(&mut buf).map_err(serde::ser::Error::custom)?;

serializer.serialize_bytes(&buf)
}
}

#[cfg(test)]
mod test {
use crate::RoaringBitmap;
use proptest::prelude::*;

proptest! {
#[test]
fn test_serde_json(
bitmap in RoaringBitmap::arbitrary(),
) {
let json = serde_json::to_vec(&bitmap).unwrap();
prop_assert_eq!(bitmap, serde_json::from_slice(&json).unwrap());
}

#[test]
fn test_bincode(
bitmap in RoaringBitmap::arbitrary(),
) {
let buffer = bincode::serialize(&bitmap).unwrap();
prop_assert_eq!(bitmap, bincode::deserialize(&buffer).unwrap());
}
}
}
17 changes: 17 additions & 0 deletions src/bitmap/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,20 @@ impl RoaringBitmap {
Ok(RoaringBitmap { containers })
}
}

#[cfg(test)]
mod test {
use crate::RoaringBitmap;
use proptest::prelude::*;

proptest! {
#[test]
fn test_serialization(
bitmap in RoaringBitmap::arbitrary(),
) {
let mut buffer = Vec::new();
bitmap.serialize_into(&mut buffer).unwrap();
prop_assert_eq!(bitmap, RoaringBitmap::deserialize_from(buffer.as_slice()).unwrap());
}
}
}
2 changes: 2 additions & 0 deletions src/treemap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ mod cmp;
mod inherent;
mod iter;
mod ops;
#[cfg(feature = "serde")]
mod serde;
mod serialization;

pub use self::iter::{IntoIter, Iter};
Expand Down
82 changes: 82 additions & 0 deletions src/treemap/serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use serde::de::SeqAccess;
use serde::de::Visitor;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;

use crate::RoaringTreemap;

impl<'de> Deserialize<'de> for RoaringTreemap {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct TreemapVisitor;

impl<'de> Visitor<'de> for TreemapVisitor {
type Value = RoaringTreemap;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("roaring bitmap")
}

fn visit_bytes<E>(self, bytes: &[u8]) -> Result<RoaringTreemap, E>
where
E: serde::de::Error,
{
RoaringTreemap::deserialize_from(bytes).map_err(serde::de::Error::custom)
}

// in some case bytes will be serialized as a sequence thus we need to accept both
// even if it means non optimal performance
fn visit_seq<A>(self, mut seq: A) -> Result<RoaringTreemap, A::Error>
where
A: SeqAccess<'de>,
{
let mut bytes: Vec<u8> = Vec::new();
while let Some(el) = seq.next_element()? {
bytes.push(el);
}
RoaringTreemap::deserialize_from(&*bytes).map_err(serde::de::Error::custom)
}
}

deserializer.deserialize_bytes(TreemapVisitor)
}
}

impl Serialize for RoaringTreemap {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut buf = Vec::new();
self.serialize_into(&mut buf).map_err(serde::ser::Error::custom)?;

serializer.serialize_bytes(&buf)
}
}

#[cfg(test)]
mod test {
use crate::RoaringTreemap;
use proptest::prelude::*;

proptest! {
#[test]
fn test_serde_json(
treemap in RoaringTreemap::arbitrary(),
) {
let json = serde_json::to_vec(&treemap).unwrap();
prop_assert_eq!(treemap, serde_json::from_slice(&json).unwrap());
}

#[test]
fn test_bincode(
treemap in RoaringTreemap::arbitrary(),
) {
let buffer = bincode::serialize(&treemap).unwrap();
prop_assert_eq!(treemap, bincode::deserialize(&buffer).unwrap());
}
}
}
17 changes: 17 additions & 0 deletions src/treemap/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,20 @@ impl RoaringTreemap {
Ok(s)
}
}

#[cfg(test)]
mod test {
use crate::RoaringTreemap;
use proptest::prelude::*;

proptest! {
#[test]
fn test_serialization(
treemap in RoaringTreemap::arbitrary(),
) {
let mut buffer = Vec::new();
treemap.serialize_into(&mut buffer).unwrap();
prop_assert_eq!(treemap, RoaringTreemap::deserialize_from(buffer.as_slice()).unwrap());
}
}
}

0 comments on commit 28db3cb

Please sign in to comment.