Skip to content

Commit

Permalink
Implement support for DeserializeSeed through Options (ron-rs#360)
Browse files Browse the repository at this point in the history
  • Loading branch information
juntyr authored and torkleyy committed Jun 6, 2022
1 parent 3c21904 commit 8fe116d
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix issue [#289](https://github.com/ron-rs/ron/issues/289) enumerate_arrays comments ([#344](https://github.com/ron-rs/ron/pull/344))
- Report struct name in expected struct error ([#342](https://github.com/ron-rs/ron/pull/342))
- Add `Options` builder to configure the RON serde roundtrip ([#343](https://github.com/ron-rs/ron/pull/343))
- Fix issue [#359](https://github.com/ron-rs/ron/issues/359) with `DeserializeSeed` support ([#360](https://github.com/ron-rs/ron/pull/360))

## [0.7.0] - 2021-10-22

Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ serde = { version = "1.0.60", features = ["serde_derive"] }
[dev-dependencies]
serde_bytes = "0.11"
serde_json = "1"

# for testing bitflags compatibility
bitflags-serial = { git = "https://github.com/kvark/bitflags-serial" }
option_set = "0.1"
4 changes: 2 additions & 2 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ impl<'de> Deserializer<'de> {
}
}

/// A convenience function for reading data from a reader
/// and feeding into a deserializer.
/// A convenience function for building a deserializer
/// and deserializing a value of type `T` from a reader.
pub fn from_reader<R, T>(rdr: R) -> Result<T>
where
R: io::Read,
Expand Down
40 changes: 37 additions & 3 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ impl Options {
}

impl Options {
/// A convenience function for reading data from a reader
/// and feeding into a deserializer.
/// A convenience function for building a deserializer
/// and deserializing a value of type `T` from a reader.
pub fn from_reader<R, T>(&self, mut rdr: R) -> Result<T>
where
R: io::Read,
Expand All @@ -93,10 +93,44 @@ impl Options {
pub fn from_bytes<'a, T>(&self, s: &'a [u8]) -> Result<T>
where
T: de::Deserialize<'a>,
{
self.from_bytes_seed(s, std::marker::PhantomData)
}

/// A convenience function for building a deserializer
/// and deserializing a value of type `T` from a reader
/// and a seed.
pub fn from_reader_seed<R, S, T>(&self, mut rdr: R, seed: S) -> Result<T>
where
R: io::Read,
S: for<'a> de::DeserializeSeed<'a, Value = T>,
{
let mut bytes = Vec::new();
rdr.read_to_end(&mut bytes)?;

self.from_bytes_seed(&bytes, seed)
}

/// A convenience function for building a deserializer
/// and deserializing a value of type `T` from a string
/// and a seed.
pub fn from_str_seed<'a, S, T>(&self, s: &'a str, seed: S) -> Result<T>
where
S: de::DeserializeSeed<'a, Value = T>,
{
self.from_bytes_seed(s.as_bytes(), seed)
}

/// A convenience function for building a deserializer
/// and deserializing a value of type `T` from bytes
/// and a seed.
pub fn from_bytes_seed<'a, S, T>(&self, s: &'a [u8], seed: S) -> Result<T>
where
S: de::DeserializeSeed<'a, Value = T>,
{
let mut deserializer = Deserializer::from_bytes_with_options(s, self.clone())?;

let value = T::deserialize(&mut deserializer)?;
let value = seed.deserialize(&mut deserializer)?;

deserializer.end()?;

Expand Down
79 changes: 79 additions & 0 deletions tests/152_bitflags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use bitflags::*;
use option_set::option_set;

#[macro_use]
extern crate bitflags_serial;

bitflags! {
#[derive(serde::Serialize, serde::Deserialize)]
struct TestGood: u8 {
const ONE = 1;
const TWO = 1 << 1;
const THREE = 1 << 2;
}
}

option_set! {
struct TestBad: UpperCamel + u8 {
const ONE = 1;
const TWO = 1 << 1;
const THREE = 1 << 2;
}
}

bitflags_serial! {
struct TestBadTWO: u8 {
const ONE = 1;
const TWO = 1 << 1;
const THREE = 1 << 2;
}
}

#[test]
fn test_bitflags() {
// Test case provided by jaynus in
// https://github.com/ron-rs/ron/issues/152#issue-421298302
let flag_good = TestGood::ONE | TestGood::TWO;

let json_ser_good = serde_json::ser::to_string(&flag_good).unwrap();
let ron_ser_good = ron::ser::to_string(&flag_good).unwrap();

assert_eq!(json_ser_good, "{\"bits\":3}");
assert_eq!(ron_ser_good, "(bits:3)");

let json_de_good: TestGood = serde_json::de::from_str(json_ser_good.as_str()).unwrap();
let ron_de_good: TestGood = ron::de::from_str(ron_ser_good.as_str()).unwrap();

assert_eq!(json_de_good, flag_good);
assert_eq!(ron_de_good, flag_good);

// option_set
let flag_bad = TestBad::ONE | TestBad::TWO;

let json_ser_bad = serde_json::ser::to_string(&flag_bad).unwrap();
let ron_ser_bad = ron::ser::to_string(&flag_bad).unwrap();

assert_eq!(json_ser_bad, "[\"One\",\"Two\"]");
assert_eq!(ron_ser_bad, "[\"One\",\"Two\"]");

let json_de_bad: TestBad = serde_json::de::from_str(json_ser_bad.as_str()).unwrap();
let ron_de_bad: TestBad = ron::de::from_str(ron_ser_bad.as_str()).unwrap();

assert_eq!(json_de_bad, flag_bad);
assert_eq!(ron_de_bad, flag_bad);

// bitflags_serial
let flag_bad_two = TestBadTWO::ONE | TestBadTWO::TWO;

let json_ser_bad_two = serde_json::ser::to_string(&flag_bad_two).unwrap();
let ron_ser_bad_two = ron::ser::to_string(&flag_bad_two).unwrap();

assert_eq!(json_ser_bad_two, "[\"ONE\",\"TWO\"]");
assert_eq!(ron_ser_bad_two, "[ONE,TWO]");

let json_de_bad_two: TestBadTWO = serde_json::de::from_str(json_ser_bad_two.as_str()).unwrap();
let ron_de_bad_two: TestBadTWO = ron::de::from_str(ron_ser_bad_two.as_str()).unwrap();

assert_eq!(json_de_bad_two, flag_bad_two);
assert_eq!(ron_de_bad_two, flag_bad_two);
}
46 changes: 46 additions & 0 deletions tests/359_deserialize_seed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#[test]
fn test_deserialize_seed() {
// Test adapted from David Tolnay's serde-yaml:
// https://github.com/dtolnay/serde-yaml/blob/8a806e316302fd2e6541dccee6d166dd51b689d6/tests/test_de.rs#L357-L392

struct Seed(i64);

impl<'de> serde::de::DeserializeSeed<'de> for Seed {
type Value = i64;

fn deserialize<D>(self, deserializer: D) -> Result<i64, D::Error>
where
D: serde::de::Deserializer<'de>,
{
struct Visitor(i64);

impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = i64;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "an integer")
}

fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<i64, E> {
Ok(v * self.0)
}

fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<i64, E> {
Ok(v as i64 * self.0)
}
}

deserializer.deserialize_any(Visitor(self.0))
}
}

let cases = [("3", 5, 15), ("6", 7, 42), ("-5", 9, -45)];

for &(ron, seed, expected) in &cases {
let deserialized = ron::Options::default()
.from_str_seed(ron, Seed(seed))
.unwrap();

assert_eq!(expected, deserialized);
}
}

0 comments on commit 8fe116d

Please sign in to comment.