From 4b9699612f57512b6734b43238c2382186245b31 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 17 Mar 2023 19:19:54 -0700 Subject: [PATCH 1/6] No longer test so many old compiler versions --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bfaffaf6c..b58492dba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,7 @@ jobs: strategy: fail-fast: false matrix: - rust: [beta, 1.56.1, 1.53.0, 1.46.0, 1.40.0, 1.38.0, 1.36.0] + rust: [beta, 1.56.1] os: [ubuntu] include: - rust: stable From 02e583360db1a4aa7d21db911a9b62f34161c386 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 25 Mar 2023 21:35:20 -0700 Subject: [PATCH 2/6] Update fuzz crate gitignore to ignore coverage dir --- fuzz/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/fuzz/.gitignore b/fuzz/.gitignore index 188f19609..f83457aec 100644 --- a/fuzz/.gitignore +++ b/fuzz/.gitignore @@ -1,3 +1,4 @@ artifacts/ corpus/ +coverage/ target/ From b0990a51db0f32558cd95ace2e64ef4e23e2cae4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 27 Mar 2023 09:37:10 -0700 Subject: [PATCH 3/6] Add regression test for issue 1004 --- tests/regression/issue1004.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/regression/issue1004.rs diff --git a/tests/regression/issue1004.rs b/tests/regression/issue1004.rs new file mode 100644 index 000000000..d2c3e74c0 --- /dev/null +++ b/tests/regression/issue1004.rs @@ -0,0 +1,9 @@ +#![cfg(feature = "arbitrary_precision")] + +#[test] +fn test() { + let float = 5.55f32; + let value = serde_json::to_value(&float).unwrap(); + let json = serde_json::to_string(&value).unwrap(); + assert_eq!(json, "5.550000190734863"); // FIXME +} From 06f3443c6e6713526d744100768a78bb085aadd8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 27 Mar 2023 09:14:05 -0700 Subject: [PATCH 4/6] Eliminate f32-to-f64 casting in arbitrary_precision mode --- src/number.rs | 18 ++++++++++++++++++ src/value/from.rs | 2 +- src/value/ser.rs | 9 ++++----- tests/regression/issue1004.rs | 5 ++++- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/number.rs b/src/number.rs index 21a76411c..ca2fd55fd 100644 --- a/src/number.rs +++ b/src/number.rs @@ -279,6 +279,24 @@ impl Number { } } + pub(crate) fn from_f32(f: f32) -> Option { + if f.is_finite() { + let n = { + #[cfg(not(feature = "arbitrary_precision"))] + { + N::Float(f as f64) + } + #[cfg(feature = "arbitrary_precision")] + { + ryu::Buffer::new().format_finite(f).to_owned() + } + }; + Some(Number { n }) + } else { + None + } + } + #[cfg(feature = "arbitrary_precision")] /// Not public API. Only tests use this. #[doc(hidden)] diff --git a/src/value/from.rs b/src/value/from.rs index c5a6a3960..462ad3f51 100644 --- a/src/value/from.rs +++ b/src/value/from.rs @@ -40,7 +40,7 @@ impl From for Value { /// let x: Value = f.into(); /// ``` fn from(f: f32) -> Self { - From::from(f as f64) + Number::from_f32(f).map_or(Value::Null, Value::Number) } } diff --git a/src/value/ser.rs b/src/value/ser.rs index a29814e92..875d22e24 100644 --- a/src/value/ser.rs +++ b/src/value/ser.rs @@ -1,6 +1,5 @@ use crate::error::{Error, ErrorCode, Result}; use crate::map::Map; -use crate::number::Number; use crate::value::{to_value, Value}; use alloc::borrow::ToOwned; use alloc::string::{String, ToString}; @@ -149,13 +148,13 @@ impl serde::Serializer for Serializer { } #[inline] - fn serialize_f32(self, value: f32) -> Result { - self.serialize_f64(value as f64) + fn serialize_f32(self, float: f32) -> Result { + Ok(Value::from(float)) } #[inline] - fn serialize_f64(self, value: f64) -> Result { - Ok(Number::from_f64(value).map_or(Value::Null, Value::Number)) + fn serialize_f64(self, float: f64) -> Result { + Ok(Value::from(float)) } #[inline] diff --git a/tests/regression/issue1004.rs b/tests/regression/issue1004.rs index d2c3e74c0..3f5bd96aa 100644 --- a/tests/regression/issue1004.rs +++ b/tests/regression/issue1004.rs @@ -5,5 +5,8 @@ fn test() { let float = 5.55f32; let value = serde_json::to_value(&float).unwrap(); let json = serde_json::to_string(&value).unwrap(); - assert_eq!(json, "5.550000190734863"); // FIXME + + // If the f32 were cast to f64 by Value before serialization, then this + // would incorrectly serialize as 5.550000190734863. + assert_eq!(json, "5.55"); } From c9bff92c1fc750bc6e71af15ecb9498cb75b1cf5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 27 Mar 2023 09:47:21 -0700 Subject: [PATCH 5/6] Fix PartialEq between Value and f32 Caught by test_partialeq_number: thread 'test_partialeq_number' panicked at 'assertion failed: `(left == right)` left: `-3.4028235e38`, right: `Number(-3.4028235e38)`', tests/test.rs:2033:5 --- src/number.rs | 11 +++++++++++ src/value/partial_eq.rs | 10 +++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/number.rs b/src/number.rs index ca2fd55fd..5ecbde873 100644 --- a/src/number.rs +++ b/src/number.rs @@ -279,6 +279,17 @@ impl Number { } } + pub(crate) fn as_f32(&self) -> Option { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(n) => Some(n as f32), + N::NegInt(n) => Some(n as f32), + N::Float(n) => Some(n as f32), + } + #[cfg(feature = "arbitrary_precision")] + self.n.parse::().ok().filter(|float| float.is_finite()) + } + pub(crate) fn from_f32(f: f32) -> Option { if f.is_finite() { let n = { diff --git a/src/value/partial_eq.rs b/src/value/partial_eq.rs index b4ef84c4f..6b2e350b6 100644 --- a/src/value/partial_eq.rs +++ b/src/value/partial_eq.rs @@ -9,6 +9,13 @@ fn eq_u64(value: &Value, other: u64) -> bool { value.as_u64().map_or(false, |i| i == other) } +fn eq_f32(value: &Value, other: f32) -> bool { + match value { + Value::Number(n) => n.as_f32().map_or(false, |i| i == other), + _ => false, + } +} + fn eq_f64(value: &Value, other: f64) -> bool { value.as_f64().map_or(false, |i| i == other) } @@ -90,6 +97,7 @@ macro_rules! partialeq_numeric { partialeq_numeric! { eq_i64[i8 i16 i32 i64 isize] eq_u64[u8 u16 u32 u64 usize] - eq_f64[f32 f64] + eq_f32[f32] + eq_f64[f64] eq_bool[bool] } From 4ea38c40019d3c00c04a0b6f080c4c62df92ae27 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 27 Mar 2023 10:00:56 -0700 Subject: [PATCH 6/6] Release 1.0.95 --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ee5428450..030282f3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_json" -version = "1.0.94" # remember to update html_root_url +version = "1.0.95" # remember to update html_root_url authors = ["Erick Tryzelaar ", "David Tolnay "] categories = ["encoding", "parser-implementations", "no-std"] description = "A JSON serialization file format" diff --git a/src/lib.rs b/src/lib.rs index bd4976398..95242d40b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -300,7 +300,7 @@ //! [macro]: crate::json //! [`serde-json-core`]: https://github.com/rust-embedded-community/serde-json-core -#![doc(html_root_url = "https://docs.rs/serde_json/1.0.94")] +#![doc(html_root_url = "https://docs.rs/serde_json/1.0.95")] // Ignored clippy lints #![allow( clippy::collapsible_else_if,