Skip to content
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
30 changes: 30 additions & 0 deletions src/serde_ron.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,17 @@ impl DeRonState {
if let DeRonTok::F64(value) = self.tok {
return Ok(value);
}
// The non-finite float literals `inf` and `NaN` (RON also accepts
// `-inf`/`+inf`, which are tokenized as `F64` above) are scanned as
// bare identifiers, so accept them here when a float is expected.
if let DeRonTok::Ident = self.tok {
if self.identbuf == "inf" {
return Ok(f64::INFINITY);
}
if self.identbuf == "NaN" {
return Ok(f64::NAN);
}
}
Err(self.err_token("floating point"))
}

Expand Down Expand Up @@ -519,6 +530,25 @@ impl DeRonState {
} else {
false
};
// A sign followed by `inf` is the non-finite float literal
// `-inf`/`+inf` (as emitted by `SerRon` for infinities).
if self.cur == 'i' {
self.identbuf.truncate(0);
while self.cur >= 'a' && self.cur <= 'z' {
self.identbuf.push(self.cur);
self.next(i);
}
if self.identbuf == "inf" {
self.tok = DeRonTok::F64(if is_neg {
f64::NEG_INFINITY
} else {
f64::INFINITY
});
return Ok(());
} else {
return Err(self.err_parse("number"));
}
}
while self.cur >= '0' && self.cur <= '9' {
self.numbuf.push(self.cur);
self.next(i);
Expand Down
71 changes: 71 additions & 0 deletions tests/ron.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@
pub struct Test(i32, pub i32, pub(crate) String, f32);

#[derive(DeRon, SerRon, PartialEq)]
pub struct Vec2(pub(crate) f32, pub(crate) f32);

Check warning on line 577 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Test Individual Features NoStd (ron)

struct `Vec2` is never constructed

Check warning on line 577 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, wasm32-unknown-unknown)

struct `Vec2` is never constructed

Check warning on line 577 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Test Individual Features (ron)

struct `Vec2` is never constructed

Check warning on line 577 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, x86_64-unknown-linux-gnu)

struct `Vec2` is never constructed

Check warning on line 577 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, x86_64-unknown-linux-gnu)

struct `Vec2` is never constructed

Check warning on line 577 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Test No Std (ubuntu-latest, x86_64-unknown-linux-gnu)

struct `Vec2` is never constructed

Check warning on line 577 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Test No Std (ubuntu-latest, x86_64-unknown-linux-gnu)

struct `Vec2` is never constructed

Check warning on line 577 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Build (macos-latest, x86_64-apple-darwin)

struct `Vec2` is never constructed

Check warning on line 577 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, x86_64-pc-windows-gnu)

struct `Vec2` is never constructed

Check warning on line 577 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Build (windows-latest, x86_64-pc-windows-msvc)

struct `Vec2` is never constructed

let test = Test(0, 1, "asd".to_string(), 2.);
let bytes = SerRon::serialize_ron(&test);
Expand Down Expand Up @@ -666,7 +666,7 @@
#[test]
fn no_whitespace_when_serialized() {
// A vec of every type which implements `SerRon`. Actual values were picked arbitrarily.
let mut rons: Vec<Box<dyn SerRon>> = vec![

Check warning on line 669 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Test Individual Features NoStd (ron)

variable does not need to be mutable

Check warning on line 669 in tests/ron.rs

View workflow job for this annotation

GitHub Actions / Test No Std (ubuntu-latest, x86_64-unknown-linux-gnu)

variable does not need to be mutable
Box::new(()),
Box::new((0, 1.0)),
Box::new((0, 1.0, [2])),
Expand Down Expand Up @@ -813,3 +813,74 @@
let deserialized_none: SystemTime = DeRon::deserialize_ron(none).unwrap();
assert_eq!(deserialized_none, SystemTime::UNIX_EPOCH);
}

#[test]
fn ron_de_ser_non_finite_floats() {
// `SerRon` emits `NaN`, `inf` and `-inf` for non-finite floats (matching
// the RON specification and the reference `ron` crate), so the RON
// deserializer must round-trip them back. Previously these tokens failed
// to parse, making `deserialize_ron(serialize_ron(x))` error for any value
// containing an infinity or NaN.

// f64
assert!(f64::deserialize_ron(&f64::INFINITY.serialize_ron())
.unwrap()
.is_infinite());
assert_eq!(
f64::deserialize_ron(&f64::INFINITY.serialize_ron()).unwrap(),
f64::INFINITY
);
assert_eq!(
f64::deserialize_ron(&f64::NEG_INFINITY.serialize_ron()).unwrap(),
f64::NEG_INFINITY
);
assert!(f64::deserialize_ron(&f64::NAN.serialize_ron())
.unwrap()
.is_nan());

// f32
assert_eq!(
f32::deserialize_ron(&f32::INFINITY.serialize_ron()).unwrap(),
f32::INFINITY
);
assert_eq!(
f32::deserialize_ron(&f32::NEG_INFINITY.serialize_ron()).unwrap(),
f32::NEG_INFINITY
);
assert!(f32::deserialize_ron(&f32::NAN.serialize_ron())
.unwrap()
.is_nan());

// Parse the literal forms directly (as accepted by the RON spec).
assert_eq!(f64::deserialize_ron("inf").unwrap(), f64::INFINITY);
assert_eq!(f64::deserialize_ron("+inf").unwrap(), f64::INFINITY);
assert_eq!(f64::deserialize_ron("-inf").unwrap(), f64::NEG_INFINITY);
assert!(f64::deserialize_ron("NaN").unwrap().is_nan());

// Non-finite floats nested inside a struct must round-trip too.
#[derive(DeRon, SerRon, Debug)]
struct Holder {
a: f32,
b: f64,
c: Vec<f64>,
d: Option<f32>,
}
let h = Holder {
a: f32::NEG_INFINITY,
b: f64::INFINITY,
c: vec![f64::NAN, 1.5, f64::NEG_INFINITY],
d: Some(f32::NAN),
};
let back: Holder = DeRon::deserialize_ron(&h.serialize_ron()).unwrap();
assert_eq!(back.a, f32::NEG_INFINITY);
assert_eq!(back.b, f64::INFINITY);
assert!(back.c[0].is_nan());
assert_eq!(back.c[1], 1.5);
assert_eq!(back.c[2], f64::NEG_INFINITY);
assert!(back.d.unwrap().is_nan());

// Finite floats must keep working (no regression).
assert_eq!(f64::deserialize_ron("-1.5").unwrap(), -1.5);
assert_eq!(f64::deserialize_ron("2.0").unwrap(), 2.0);
assert_eq!(i64::deserialize_ron("-42").unwrap(), -42);
}
Loading