Skip to content

Commit

Permalink
add serde serialization support (#210)
Browse files Browse the repository at this point in the history
  • Loading branch information
keithamus committed Apr 8, 2024
1 parent 49c5a71 commit d746a56
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,23 @@ harness = false
# implement its `Allocator` trait.
allocator-api2 = { version = "0.2.8", default-features = false, optional = true }

# This dependency is here to allow integration with Serde, if the `serde` feature is enabled
serde = { version = "1.0.171", optional = true }

[dev-dependencies]
quickcheck = "1.0.3"
criterion = "0.3.6"
rand = "0.8.5"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.115"

[features]
default = []
collections = []
boxed = []
allocator_api = []
std = []
serde = ["dep:serde"]

# [profile.bench]
# debug = true
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,37 @@ in its space itself.
}
```

#### Serde

Adding the `serde` feature flag will enable transparent serialization of Vecs and
boxed values.

```toml
[dependencies]
bumpalo = { version = "3.9", features = ["collections", "boxed", "serde"] }
```

```rust,ignore
use bumpalo::{Bump, boxed::Box, collections::Vec};
// Create a new bump arena.
let bump = Bump::new();
// Create a `Box`
let box = Box::new_in("hello", &bump);
// Serialize with serde_json
assert_eq!(serde_json::to_string(&box).unwrap(), "\"hello\"");
// Create a `Vec`
let vec = Vec::new_in( &bump);
vec.push(1);
vec.push(2);
// Serialize with serde_json
assert_eq!(serde_json::to_string(&vec).unwrap(), "[1, 2]");
```

### `#![no_std]` Support

Bumpalo is a `no_std` crate by default. It depends only on the `alloc` and `core` crates.
Expand Down
16 changes: 16 additions & 0 deletions src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,3 +681,19 @@ impl<'a, T, const N: usize> TryFrom<Box<'a, [T]>> for Box<'a, [T; N]> {
}
}
}

#[cfg(feature = "serde")]
mod serialize {
use super::*;

use serde::{Serialize, Serializer};

impl<'a, T> Serialize for Box<'a, T>
where
T: Serialize,
{
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
T::serialize(self, serializer)
}
}
}
24 changes: 24 additions & 0 deletions src/collections/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2760,3 +2760,27 @@ impl<'bump> io::Write for Vec<'bump, u8> {
Ok(())
}
}

#[cfg(feature = "serde")]
mod serialize {
use super::*;

use serde::{ser::SerializeSeq, Serialize, Serializer};

impl<'a, T> Serialize for Vec<'a, T>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(self.len))?;
for e in self.iter() {
seq.serialize_element(e)?;
}
seq.end()
}
}

}
3 changes: 3 additions & 0 deletions tests/all/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ mod try_alloc_try_with;
mod try_alloc_with;
mod vec;

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

fn main() {}
119 changes: 119 additions & 0 deletions tests/all/serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#![cfg(feature = "collections")]
#![cfg(feature = "serde")]

use bumpalo::{boxed::Box, vec, Bump};
use serde::{Deserialize, Serialize};

macro_rules! compare_std_vec {
(in $bump:ident; $($x:expr),+) => {{
let mut vec = vec![in &$bump; $($x),+];
let std_vec = std::vec![$($x),+];
(vec, std_vec)
}}
}

macro_rules! compare_std_box {
(in $bump:ident; $x:expr) => {
(Box::new_in($x, &$bump), std::boxed::Box::new($x))
};
}

macro_rules! assert_eq_json {
($a:ident, $b:ident) => {
assert_eq!(
serde_json::to_string(&$a).unwrap(),
serde_json::to_string(&$b).unwrap(),
)
};
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(tag = "t", content = "c")]
enum Test {
First,
Second,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde()]
struct Mixed {
i: i32,
s: String,
o: Option<String>,
e: Test,
}

#[test]
fn test_vec_serializes_str() {
let bump = Bump::new();
let (vec, std_vec) = compare_std_vec![in bump; "hello", "world"];
assert_eq_json!(vec, std_vec);
let de: std::vec::Vec<String> =
serde_json::from_str(&serde_json::to_string(&vec).unwrap()).unwrap();
assert_eq!(de, std_vec);
}

#[test]
fn test_vec_serializes_f32() {
let bump = Bump::new();
let (vec, std_vec) = compare_std_vec![in bump; 1.5707964, 3.1415927];
assert_eq_json!(vec, std_vec);
let de: std::vec::Vec<f32> =
serde_json::from_str(&serde_json::to_string(&vec).unwrap()).unwrap();
assert_eq!(de, std_vec);
}

#[cfg(feature = "serde")]
#[test]
fn test_vec_serializes_complex() {
let bump = Bump::new();
let (vec, std_vec) = compare_std_vec![
in bump;
Mixed {
i: 8,
s: "a".into(),
o: None,
e: Test::Second,
},
Mixed {
i: 8,
s: "b".into(),
o: Some("some".into()),
e: Test::First,
}
];
assert_eq_json!(vec, std_vec);
let de: std::vec::Vec<Mixed> =
serde_json::from_str(&serde_json::to_string(&vec).unwrap()).unwrap();
assert_eq!(de, std_vec);
}

#[test]
fn test_box_serializes() {
let bump = Bump::new();
let (box_int, std_box_int) = compare_std_box!(in bump; 1);
assert_eq_json!(box_int, std_box_int);
let (box_str, std_box_str) = compare_std_box!(in bump; 1);
assert_eq_json!(box_str, std_box_str);
let (box_vec, std_box_vec) = compare_std_box!(in bump; std::vec!["hello", "world"]);
assert_eq_json!(box_vec, std_box_vec);
}

#[cfg(feature = "serde")]
#[test]
fn test_box_serializes_complex() {
let bump = Bump::new();
let (vec, std_vec) = compare_std_box![
in bump;
Mixed {
i: 8,
s: "a".into(),
o: None,
e: Test::Second,
}
];
assert_eq_json!(vec, std_vec);
let de: std::boxed::Box<Mixed> =
serde_json::from_str(&serde_json::to_string(&vec).unwrap()).unwrap();
assert_eq!(de, std_vec);
}

0 comments on commit d746a56

Please sign in to comment.