aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/de.rs9
-rw-r--r--src/ser.rs49
-rw-r--r--test-suite/build.rs1
-rw-r--r--test-suite/tests/float.rs79
-rw-r--r--test-suite/tests/invalid-encoder-misc.rs14
-rw-r--r--test-suite/tests/invalid-misc.rs3
-rw-r--r--test-suite/tests/valid/integer.json4
-rw-r--r--test-suite/tests/valid/integer.toml2
8 files changed, 117 insertions, 44 deletions
diff --git a/src/de.rs b/src/de.rs
index 1d43cc9..5e63cb4 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -6,6 +6,7 @@
use std::borrow::Cow;
use std::error;
+use std::f64;
use std::fmt;
use std::str;
use std::vec;
@@ -882,6 +883,14 @@ impl<'a> Deserializer<'a> {
}
_ => Err(self.error(at, ErrorKind::NumberInvalid)),
}
+ } else if s == "inf" {
+ Ok(Value { e: E::Float(f64::INFINITY), start: start, end: end })
+ } else if s == "-inf" {
+ Ok(Value { e: E::Float(f64::NEG_INFINITY), start: start, end: end })
+ } else if s == "nan" {
+ Ok(Value { e: E::Float(f64::NAN), start: start, end: end })
+ } else if s == "-nan" {
+ Ok(Value { e: E::Float(-f64::NAN), start: start, end: end })
} else {
self.integer(s).map(|f| Value { e: E::Integer(f), start: start, end: end })
}
diff --git a/src/ser.rs b/src/ser.rs
index 8f4e72b..9d989db 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -737,6 +737,27 @@ impl<'a> Serializer<'a> {
}
}
+macro_rules! serialize_float {
+ ($this:expr, $v:expr) => {{
+ $this.emit_key("float")?;
+ if ($v.is_nan() || $v == 0.0) && $v.is_sign_negative() {
+ drop(write!($this.dst, "-"));
+ }
+ if $v.is_nan() {
+ drop(write!($this.dst, "nan"));
+ } else {
+ drop(write!($this.dst, "{}", $v));
+ }
+ if $v % 1.0 == 0.0 {
+ drop(write!($this.dst, ".0"));
+ }
+ if let State::Table { .. } = $this.state {
+ $this.dst.push_str("\n");
+ }
+ return Ok(());
+ }};
+}
+
impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
type Ok = ();
type Error = Error;
@@ -785,35 +806,11 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
}
fn serialize_f32(self, v: f32) -> Result<(), Self::Error> {
- if !v.is_finite() {
- return Err(Error::NumberInvalid);
- }
-
- self.emit_key("float")?;
- drop(write!(self.dst, "{}", v));
- if v % 1.0 == 0.0 {
- drop(write!(self.dst, ".0"));
- }
- if let State::Table { .. } = self.state {
- self.dst.push_str("\n");
- }
- Ok(())
+ serialize_float!(self, v)
}
fn serialize_f64(self, v: f64) -> Result<(), Self::Error> {
- if !v.is_finite() {
- return Err(Error::NumberInvalid);
- }
-
- self.emit_key("float")?;
- drop(write!(self.dst, "{}", v));
- if v % 1.0 == 0.0 {
- drop(write!(self.dst, ".0"));
- }
- if let State::Table { .. } = self.state {
- self.dst.push_str("\n");
- }
- Ok(())
+ serialize_float!(self, v)
}
fn serialize_char(self, v: char) -> Result<(), Self::Error> {
diff --git a/test-suite/build.rs b/test-suite/build.rs
index ca63946..5a9a55a 100644
--- a/test-suite/build.rs
+++ b/test-suite/build.rs
@@ -4,5 +4,6 @@ use rustc_version::{version, Version};
fn main() {
if version().unwrap() >= Version::parse("1.20.0").unwrap() {
println!(r#"cargo:rustc-cfg=feature="test-quoted-keys-in-macro""#);
+ println!(r#"cargo:rustc-cfg=feature="test-nan-sign""#);
}
}
diff --git a/test-suite/tests/float.rs b/test-suite/tests/float.rs
new file mode 100644
index 0000000..6590fe4
--- /dev/null
+++ b/test-suite/tests/float.rs
@@ -0,0 +1,79 @@
+extern crate toml;
+#[macro_use]
+extern crate serde_derive;
+
+use toml::Value;
+
+macro_rules! float_inf_tests {
+ ($ty:ty) => {{
+ #[derive(Serialize, Deserialize)]
+ struct S {
+ sf1: $ty,
+ sf2: $ty,
+ sf3: $ty,
+ sf4: $ty,
+ sf5: $ty,
+ sf6: $ty,
+ sf7: $ty,
+ sf8: $ty,
+ }
+ let inf: S = toml::from_str(
+ r"
+ # infinity
+ sf1 = inf # positive infinity
+ sf2 = +inf # positive infinity
+ sf3 = -inf # negative infinity
+
+ # not a number
+ sf4 = nan # actual sNaN/qNaN encoding is implementation specific
+ sf5 = +nan # same as `nan`
+ sf6 = -nan # valid, actual encoding is implementation specific
+
+ # zero
+ sf7 = +0.0
+ sf8 = -0.0
+ ").expect("Parse infinities.");
+
+ assert!(inf.sf1.is_infinite());
+ assert!(inf.sf1.is_sign_positive());
+ assert!(inf.sf2.is_infinite());
+ assert!(inf.sf2.is_sign_positive());
+ assert!(inf.sf3.is_infinite());
+ assert!(inf.sf3.is_sign_negative());
+
+ assert!(inf.sf4.is_nan());
+ assert!(inf.sf4.is_sign_positive());
+ assert!(inf.sf5.is_nan());
+ assert!(inf.sf5.is_sign_positive());
+ assert!(inf.sf6.is_nan());
+ assert!(inf.sf6.is_sign_negative());
+
+ assert_eq!(inf.sf7, 0.0);
+ assert!(inf.sf7.is_sign_positive());
+ assert_eq!(inf.sf8, 0.0);
+ assert!(inf.sf8.is_sign_negative());
+
+ let s = toml::to_string(&inf).unwrap();
+ assert_eq!(
+ s, "\
+sf1 = inf
+sf2 = inf
+sf3 = -inf
+sf4 = nan
+sf5 = nan
+sf6 = -nan
+sf7 = 0.0
+sf8 = -0.0
+"
+ );
+
+ toml::from_str::<Value>(&s).expect("roundtrip");
+ }};
+}
+
+#[test]
+#[cfg(feature = "test-nan-sign")]
+fn float_inf() {
+ float_inf_tests!(f32);
+ float_inf_tests!(f64);
+}
diff --git a/test-suite/tests/invalid-encoder-misc.rs b/test-suite/tests/invalid-encoder-misc.rs
deleted file mode 100644
index 272f58f..0000000
--- a/test-suite/tests/invalid-encoder-misc.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-extern crate toml;
-
-use std::f64;
-
-#[test]
-fn test_invalid_float_encode() {
- fn bad(value: toml::Value) {
- assert!(toml::to_string(&value).is_err());
- }
-
- bad(toml::Value::Float(f64::INFINITY));
- bad(toml::Value::Float(f64::NEG_INFINITY));
- bad(toml::Value::Float(f64::NAN));
-}
diff --git a/test-suite/tests/invalid-misc.rs b/test-suite/tests/invalid-misc.rs
index 7d34651..218be4f 100644
--- a/test-suite/tests/invalid-misc.rs
+++ b/test-suite/tests/invalid-misc.rs
@@ -10,9 +10,6 @@ fn bad() {
bad("a = 1__1");
bad("a = 1_");
bad("''");
- bad("a = nan");
- bad("a = -inf");
- bad("a = inf");
bad("a = 9e99999");
bad("a = \"\u{7f}\"");
bad("a = '\u{7f}'");
diff --git a/test-suite/tests/valid/integer.json b/test-suite/tests/valid/integer.json
index 61985a1..86f779f 100644
--- a/test-suite/tests/valid/integer.json
+++ b/test-suite/tests/valid/integer.json
@@ -1,4 +1,6 @@
{
"answer": {"type": "integer", "value": "42"},
- "neganswer": {"type": "integer", "value": "-42"}
+ "neganswer": {"type": "integer", "value": "-42"},
+ "neg_zero": {"type": "integer", "value": "0"},
+ "pos_zero": {"type": "integer", "value": "0"}
}
diff --git a/test-suite/tests/valid/integer.toml b/test-suite/tests/valid/integer.toml
index c4f6297..2bdca34 100644
--- a/test-suite/tests/valid/integer.toml
+++ b/test-suite/tests/valid/integer.toml
@@ -1,2 +1,4 @@
answer = 42
neganswer = -42
+neg_zero = -0
+pos_zero = +0