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

add serde serialization support #210

Merged
merged 1 commit into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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);
}