diff options
36 files changed, 478 insertions, 1216 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index fa385b5..d3c2d3e 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "09d865b34b9701be52764dc9bf571b1a16e9d3dc" + "sha1": "a15bd0968639884ec7b73107360d58fd655e2071" }, "path_in_vcs": "" }
\ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d997982..bfaffaf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,6 @@ name: CI on: push: pull_request: - workflow_dispatch: schedule: [cron: "40 1 * * *"] permissions: @@ -22,7 +21,7 @@ jobs: os: [ubuntu, windows] timeout-minutes: 45 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@nightly - run: cargo test - run: cargo test --features preserve_order --tests -- --skip ui --exact @@ -38,7 +37,7 @@ jobs: strategy: fail-fast: false matrix: - rust: [beta, 1.64.0, 1.56.1] + rust: [beta, 1.56.1, 1.53.0, 1.46.0, 1.40.0, 1.38.0, 1.36.0] os: [ubuntu] include: - rust: stable @@ -48,37 +47,27 @@ jobs: os: windows timeout-minutes: 45 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{matrix.rust}} targets: ${{matrix.target}} - - run: cargo check --manifest-path tests/crate/Cargo.toml - - run: cargo check --manifest-path tests/crate/Cargo.toml --features float_roundtrip - - run: cargo check --manifest-path tests/crate/Cargo.toml --features arbitrary_precision - - run: cargo check --manifest-path tests/crate/Cargo.toml --features raw_value - - run: cargo check --manifest-path tests/crate/Cargo.toml --features unbounded_depth + - run: cargo check + - run: cargo check --features float_roundtrip + - run: cargo check --features arbitrary_precision + - run: cargo check --features raw_value + - run: cargo check --features unbounded_depth - run: cargo check --manifest-path tests/crate/Cargo.toml --no-default-features --features alloc - run: cargo check --manifest-path tests/crate/Cargo.toml --no-default-features --features alloc,arbitrary_precision - run: cargo check --manifest-path tests/crate/Cargo.toml --no-default-features --features alloc,raw_value - - run: cargo check --manifest-path tests/crate/Cargo.toml --features serde_json/preserve_order - if: matrix.rust != '1.56.1' - - run: cargo check --manifest-path tests/crate/Cargo.toml --no-default-features --features alloc,serde_json/preserve_order - if: matrix.rust != '1.56.1' + - run: cargo check --features preserve_order + if: matrix.rust != '1.53.0' && matrix.rust != '1.46.0' && matrix.rust != '1.45.0' && matrix.rust != '1.40.0' && matrix.rust != '1.38.0' && matrix.rust != '1.36.0' + - run: cargo check --manifest-path tests/crate/Cargo.toml --no-default-features --features alloc,preserve_order + if: matrix.rust != '1.53.0' && matrix.rust != '1.46.0' && matrix.rust != '1.45.0' && matrix.rust != '1.40.0' && matrix.rust != '1.38.0' && matrix.rust != '1.36.0' - name: Build without std run: cargo check --manifest-path tests/crate/Cargo.toml --target ${{matrix.target}} --no-default-features --features alloc if: matrix.target - minimal: - name: Minimal versions - runs-on: ubuntu-latest - timeout-minutes: 45 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly - - run: cargo generate-lockfile -Z minimal-versions - - run: cargo check --locked - miri: name: Miri runs-on: ubuntu-latest @@ -86,9 +75,8 @@ jobs: MIRIFLAGS: -Zmiri-strict-provenance timeout-minutes: 45 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@miri - - run: cargo miri setup - run: cargo miri test - run: cargo miri test --features preserve_order,float_roundtrip,arbitrary_precision,raw_value @@ -98,29 +86,28 @@ jobs: if: github.event_name != 'pull_request' timeout-minutes: 45 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@clippy - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic - run: cargo clippy --all-features --tests -- -Dclippy::all -Dclippy::pedantic - doc: + docs: name: Documentation runs-on: ubuntu-latest timeout-minutes: 45 - env: - RUSTDOCFLAGS: -Dwarnings steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@nightly - - uses: dtolnay/install@cargo-docs-rs - - run: cargo docs-rs + - run: cargo doc --features raw_value,unbounded_depth + env: + RUSTDOCFLAGS: --cfg docsrs fuzz: name: Fuzz runs-on: ubuntu-latest timeout-minutes: 45 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/install@cargo-fuzz - run: cargo fuzz check @@ -131,7 +118,7 @@ jobs: if: github.event_name != 'pull_request' timeout-minutes: 45 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: dtolnay/install@cargo-outdated - - run: cargo outdated --exit-code 1 + - run: cargo outdated --workspace --exit-code 1 - run: cargo outdated --manifest-path fuzz/Cargo.toml --exit-code 1 @@ -43,9 +43,9 @@ rust_library { host_supported: true, crate_name: "serde_json", cargo_env_compat: true, - cargo_pkg_version: "1.0.113", + cargo_pkg_version: "1.0.94", srcs: ["src/lib.rs"], - edition: "2021", + edition: "2018", features: [ "default", "std", @@ -10,10 +10,10 @@ # See Cargo.toml.orig for the original contents. [package] -edition = "2021" -rust-version = "1.56" +edition = "2018" +rust-version = "1.36" name = "serde_json" -version = "1.0.113" +version = "1.0.94" authors = [ "Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>", @@ -36,14 +36,12 @@ repository = "https://github.com/serde-rs/json" [package.metadata.docs.rs] features = [ - "preserve_order", "raw_value", "unbounded_depth", ] rustdoc-args = [ "--cfg", "docsrs", - "--generate-link-to-definition", ] targets = ["x86_64-unknown-linux-gnu"] @@ -54,7 +52,8 @@ features = ["raw_value"] doc-scrape-examples = false [dependencies.indexmap] -version = "2.2.1" +version = "1.5.2" +features = ["std"] optional = true [dependencies.itoa] @@ -64,36 +63,36 @@ version = "1.0" version = "1.0" [dependencies.serde] -version = "1.0.194" +version = "1.0.100" default-features = false [dev-dependencies.automod] -version = "1.0.11" +version = "1.0" [dev-dependencies.indoc] -version = "2.0.2" +version = "2.0" [dev-dependencies.ref-cast] -version = "1.0.18" +version = "1.0" [dev-dependencies.rustversion] -version = "1.0.13" +version = "1.0" [dev-dependencies.serde] -version = "1.0.194" +version = "1.0.100" features = ["derive"] [dev-dependencies.serde_bytes] -version = "0.11.10" +version = "0.11" [dev-dependencies.serde_derive] -version = "1.0.166" +version = "1.0" [dev-dependencies.serde_stacker] -version = "0.1.8" +version = "0.1" [dev-dependencies.trybuild] -version = "1.0.81" +version = "1.0.49" features = ["diff"] [features] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index cedde61..ee54284 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,40 +1,43 @@ [package] name = "serde_json" -version = "1.0.113" +version = "1.0.94" # remember to update html_root_url authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] categories = ["encoding", "parser-implementations", "no-std"] description = "A JSON serialization file format" documentation = "https://docs.rs/serde_json" -edition = "2021" +edition = "2018" keywords = ["json", "serde", "serialization"] license = "MIT OR Apache-2.0" repository = "https://github.com/serde-rs/json" -rust-version = "1.56" +rust-version = "1.36" [dependencies] -indexmap = { version = "2.2.1", optional = true } +serde = { version = "1.0.100", default-features = false } +indexmap = { version = "1.5.2", features = ["std"], optional = true } itoa = "1.0" ryu = "1.0" -serde = { version = "1.0.194", default-features = false } [dev-dependencies] -automod = "1.0.11" -indoc = "2.0.2" -ref-cast = "1.0.18" -rustversion = "1.0.13" -serde = { version = "1.0.194", features = ["derive"] } -serde_bytes = "0.11.10" -serde_derive = "1.0.166" -serde_stacker = "0.1.8" -trybuild = { version = "1.0.81", features = ["diff"] } +automod = "1.0" +indoc = "2.0" +ref-cast = "1.0" +rustversion = "1.0" +serde = { version = "1.0.100", features = ["derive"] } +serde_bytes = "0.11" +serde_derive = "1.0" +serde_stacker = "0.1" +trybuild = { version = "1.0.49", features = ["diff"] } + +[workspace] +members = ["tests/crate"] [lib] doc-scrape-examples = false [package.metadata.docs.rs] -features = ["preserve_order", "raw_value", "unbounded_depth"] +features = ["raw_value", "unbounded_depth"] targets = ["x86_64-unknown-linux-gnu"] -rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] +rustdoc-args = ["--cfg", "docsrs"] [package.metadata.playground] features = ["raw_value"] @@ -1,20 +1,23 @@ # This project was upgraded with external_updater. -# Usage: tools/external_updater/updater.sh update external/rust/crates/serde_json -# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md +# Usage: tools/external_updater/updater.sh update rust/crates/serde_json +# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md name: "serde_json" description: "A JSON serialization file format" third_party { + url { + type: HOMEPAGE + value: "https://crates.io/crates/serde_json" + } + url { + type: ARCHIVE + value: "https://static.crates.io/crates/serde_json/serde_json-1.0.94.crate" + } + version: "1.0.94" license_type: NOTICE last_upgrade_date { - year: 2024 - month: 2 - day: 5 - } - homepage: "https://crates.io/crates/serde_json" - identifier { - type: "Archive" - value: "https://static.crates.io/crates/serde_json/serde_json-1.0.113.crate" - version: "1.0.113" + year: 2023 + month: 3 + day: 20 } } @@ -76,7 +76,7 @@ enum Value { A string of JSON data can be parsed into a `serde_json::Value` by the [`serde_json::from_str`][from_str] function. There is also -[`from_slice`][from_slice] for parsing from a byte slice &\[u8\] and +[`from_slice`][from_slice] for parsing from a byte slice &[u8] and [`from_reader`][from_reader] for parsing from any `io::Read` like a File or a TCP stream. @@ -1,4 +1,6 @@ use std::env; +use std::process::Command; +use std::str::{self, FromStr}; fn main() { println!("cargo:rerun-if-changed=build.rs"); @@ -7,11 +9,46 @@ fn main() { // src/lexical/math.rs for where this has an effect. let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); match target_arch.as_str() { - "aarch64" | "mips64" | "powerpc64" | "x86_64" | "loongarch64" => { + "aarch64" | "mips64" | "powerpc64" | "x86_64" => { println!("cargo:rustc-cfg=limb_width_64"); } _ => { println!("cargo:rustc-cfg=limb_width_32"); } } + + let minor = match rustc_minor_version() { + Some(minor) => minor, + None => return, + }; + + // BTreeMap::get_key_value + // https://blog.rust-lang.org/2019/12/19/Rust-1.40.0.html#additions-to-the-standard-library + if minor < 40 { + println!("cargo:rustc-cfg=no_btreemap_get_key_value"); + } + + // BTreeMap::remove_entry + // https://blog.rust-lang.org/2020/07/16/Rust-1.45.0.html#library-changes + if minor < 45 { + println!("cargo:rustc-cfg=no_btreemap_remove_entry"); + } + + // BTreeMap::retain + // https://blog.rust-lang.org/2021/06/17/Rust-1.53.0.html#stabilized-apis + if minor < 53 { + println!("cargo:rustc-cfg=no_btreemap_retain"); + } +} + +fn rustc_minor_version() -> Option<u32> { + let rustc = env::var_os("RUSTC")?; + let output = Command::new(rustc).arg("--version").output().ok()?; + let version = str::from_utf8(&output.stdout).ok()?; + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + let next = pieces.next()?; + u32::from_str(next).ok() } @@ -22,7 +22,6 @@ use crate::number::NumberDeserializer; pub use crate::read::{Read, SliceRead, StrRead}; #[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub use crate::read::IoRead; ////////////////////////////////////////////////////////////////////////////// @@ -210,7 +209,7 @@ impl<'de, R: Read<'de>> Deserializer<R> { self.disable_recursion_limit = true; } - pub(crate) fn peek(&mut self) -> Result<Option<u8>> { + fn peek(&mut self) -> Result<Option<u8>> { self.read.peek() } @@ -249,7 +248,7 @@ impl<'de, R: Read<'de>> Deserializer<R> { fn parse_whitespace(&mut self) -> Result<Option<u8>> { loop { match tri!(self.peek()) { - Some(b' ' | b'\n' | b'\t' | b'\r') => { + Some(b' ') | Some(b'\n') | Some(b'\t') | Some(b'\r') => { self.eat_char(); } other => { @@ -310,9 +309,9 @@ impl<'de, R: Read<'de>> Deserializer<R> { self.fix_position(err) } - pub(crate) fn deserialize_number<'any, V>(&mut self, visitor: V) -> Result<V::Value> + fn deserialize_number<V>(&mut self, visitor: V) -> Result<V::Value> where - V: de::Visitor<'any>, + V: de::Visitor<'de>, { let peek = match tri!(self.parse_whitespace()) { Some(b) => b, @@ -336,79 +335,6 @@ impl<'de, R: Read<'de>> Deserializer<R> { } } - #[cfg(feature = "float_roundtrip")] - pub(crate) fn do_deserialize_f32<'any, V>(&mut self, visitor: V) -> Result<V::Value> - where - V: de::Visitor<'any>, - { - self.single_precision = true; - let val = self.deserialize_number(visitor); - self.single_precision = false; - val - } - - pub(crate) fn do_deserialize_i128<'any, V>(&mut self, visitor: V) -> Result<V::Value> - where - V: de::Visitor<'any>, - { - let mut buf = String::new(); - - match tri!(self.parse_whitespace()) { - Some(b'-') => { - self.eat_char(); - buf.push('-'); - } - Some(_) => {} - None => { - return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); - } - }; - - tri!(self.scan_integer128(&mut buf)); - - let value = match buf.parse() { - Ok(int) => visitor.visit_i128(int), - Err(_) => { - return Err(self.error(ErrorCode::NumberOutOfRange)); - } - }; - - match value { - Ok(value) => Ok(value), - Err(err) => Err(self.fix_position(err)), - } - } - - pub(crate) fn do_deserialize_u128<'any, V>(&mut self, visitor: V) -> Result<V::Value> - where - V: de::Visitor<'any>, - { - match tri!(self.parse_whitespace()) { - Some(b'-') => { - return Err(self.peek_error(ErrorCode::NumberOutOfRange)); - } - Some(_) => {} - None => { - return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); - } - } - - let mut buf = String::new(); - tri!(self.scan_integer128(&mut buf)); - - let value = match buf.parse() { - Ok(int) => visitor.visit_u128(int), - Err(_) => { - return Err(self.error(ErrorCode::NumberOutOfRange)); - } - }; - - match value { - Ok(value) => Ok(value), - Err(err) => Err(self.fix_position(err)), - } - } - fn scan_integer128(&mut self, buf: &mut String) -> Result<()> { match tri!(self.next_char_or_null()) { b'0' => { @@ -934,7 +860,7 @@ impl<'de, R: Read<'de>> Deserializer<R> { if !positive { buf.push('-'); } - tri!(self.scan_integer(&mut buf)); + self.scan_integer(&mut buf)?; if positive { if let Ok(unsigned) = buf.parse() { return Ok(ParserNumber::U64(unsigned)); @@ -987,7 +913,7 @@ impl<'de, R: Read<'de>> Deserializer<R> { fn scan_number(&mut self, buf: &mut String) -> Result<()> { match tri!(self.peek_or_null()) { b'.' => self.scan_decimal(buf), - e @ (b'e' | b'E') => self.scan_exponent(e as char, buf), + e @ b'e' | e @ b'E' => self.scan_exponent(e as char, buf), _ => Ok(()), } } @@ -1012,7 +938,7 @@ impl<'de, R: Read<'de>> Deserializer<R> { } match tri!(self.peek_or_null()) { - e @ (b'e' | b'E') => self.scan_exponent(e as char, buf), + e @ b'e' | e @ b'E' => self.scan_exponent(e as char, buf), _ => Ok(()), } } @@ -1133,7 +1059,7 @@ impl<'de, R: Read<'de>> Deserializer<R> { tri!(self.read.ignore_str()); None } - frame @ (b'[' | b'{') => { + frame @ b'[' | frame @ b'{' => { self.scratch.extend(enclosing.take()); self.eat_char(); Some(frame) @@ -1278,9 +1204,9 @@ impl<'de, R: Read<'de>> Deserializer<R> { where V: de::Visitor<'de>, { - tri!(self.parse_whitespace()); + self.parse_whitespace()?; self.read.begin_raw_buffering(); - tri!(self.ignore_value()); + self.ignore_value()?; self.read.end_raw_buffering(visitor) } } @@ -1332,15 +1258,11 @@ static POW10: [f64; 309] = [ macro_rules! deserialize_number { ($method:ident) => { - deserialize_number!($method, deserialize_number); - }; - - ($method:ident, $using:ident) => { fn $method<V>(self, visitor: V) -> Result<V::Value> where V: de::Visitor<'de>, { - self.$using(visitor) + self.deserialize_number(visitor) } }; } @@ -1502,9 +1424,77 @@ impl<'de, 'a, R: Read<'de>> de::Deserializer<'de> for &'a mut Deserializer<R> { deserialize_number!(deserialize_f64); #[cfg(feature = "float_roundtrip")] - deserialize_number!(deserialize_f32, do_deserialize_f32); - deserialize_number!(deserialize_i128, do_deserialize_i128); - deserialize_number!(deserialize_u128, do_deserialize_u128); + fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.single_precision = true; + let val = self.deserialize_number(visitor); + self.single_precision = false; + val + } + + fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let mut buf = String::new(); + + match tri!(self.parse_whitespace()) { + Some(b'-') => { + self.eat_char(); + buf.push('-'); + } + Some(_) => {} + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + tri!(self.scan_integer128(&mut buf)); + + let value = match buf.parse() { + Ok(int) => visitor.visit_i128(int), + Err(_) => { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + match tri!(self.parse_whitespace()) { + Some(b'-') => { + return Err(self.peek_error(ErrorCode::NumberOutOfRange)); + } + Some(_) => {} + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + } + + let mut buf = String::new(); + tri!(self.scan_integer128(&mut buf)); + + let value = match buf.parse() { + Ok(int) => visitor.visit_u128(int), + Err(_) => { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } fn deserialize_char<V>(self, visitor: V) -> Result<V::Value> where @@ -2128,47 +2118,24 @@ struct MapKey<'a, R: 'a> { de: &'a mut Deserializer<R>, } -macro_rules! deserialize_numeric_key { - ($method:ident) => { - fn $method<V>(self, visitor: V) -> Result<V::Value> - where - V: de::Visitor<'de>, - { - self.deserialize_number(visitor) - } - }; - - ($method:ident, $delegate:ident) => { +macro_rules! deserialize_integer_key { + ($method:ident => $visit:ident) => { fn $method<V>(self, visitor: V) -> Result<V::Value> where V: de::Visitor<'de>, { self.de.eat_char(); - - match tri!(self.de.peek()) { - Some(b'0'..=b'9' | b'-') => {} - _ => return Err(self.de.error(ErrorCode::ExpectedNumericKey)), - } - - let value = tri!(self.de.$delegate(visitor)); - - match tri!(self.de.peek()) { - Some(b'"') => self.de.eat_char(), - _ => return Err(self.de.peek_error(ErrorCode::ExpectedDoubleQuote)), + self.de.scratch.clear(); + let string = tri!(self.de.read.parse_str(&mut self.de.scratch)); + match (string.parse(), string) { + (Ok(integer), _) => visitor.$visit(integer), + (Err(_), Reference::Borrowed(s)) => visitor.visit_borrowed_str(s), + (Err(_), Reference::Copied(s)) => visitor.visit_str(s), } - - Ok(value) } }; } -impl<'de, 'a, R> MapKey<'a, R> -where - R: Read<'de>, -{ - deserialize_numeric_key!(deserialize_number, deserialize_number); -} - impl<'de, 'a, R> de::Deserializer<'de> for MapKey<'a, R> where R: Read<'de>, @@ -2188,56 +2155,16 @@ where } } - deserialize_numeric_key!(deserialize_i8); - deserialize_numeric_key!(deserialize_i16); - deserialize_numeric_key!(deserialize_i32); - deserialize_numeric_key!(deserialize_i64); - deserialize_numeric_key!(deserialize_i128, deserialize_i128); - deserialize_numeric_key!(deserialize_u8); - deserialize_numeric_key!(deserialize_u16); - deserialize_numeric_key!(deserialize_u32); - deserialize_numeric_key!(deserialize_u64); - deserialize_numeric_key!(deserialize_u128, deserialize_u128); - #[cfg(not(feature = "float_roundtrip"))] - deserialize_numeric_key!(deserialize_f32); - #[cfg(feature = "float_roundtrip")] - deserialize_numeric_key!(deserialize_f32, deserialize_f32); - deserialize_numeric_key!(deserialize_f64); - - fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value> - where - V: de::Visitor<'de>, - { - self.de.eat_char(); - - let peek = match tri!(self.de.next_char()) { - Some(b) => b, - None => { - return Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)); - } - }; - - let value = match peek { - b't' => { - tri!(self.de.parse_ident(b"rue\"")); - visitor.visit_bool(true) - } - b'f' => { - tri!(self.de.parse_ident(b"alse\"")); - visitor.visit_bool(false) - } - _ => { - self.de.scratch.clear(); - let s = tri!(self.de.read.parse_str(&mut self.de.scratch)); - Err(de::Error::invalid_type(Unexpected::Str(&s), &visitor)) - } - }; - - match value { - Ok(value) => Ok(value), - Err(err) => Err(self.de.fix_position(err)), - } - } + deserialize_integer_key!(deserialize_i8 => visit_i8); + deserialize_integer_key!(deserialize_i16 => visit_i16); + deserialize_integer_key!(deserialize_i32 => visit_i32); + deserialize_integer_key!(deserialize_i64 => visit_i64); + deserialize_integer_key!(deserialize_i128 => visit_i128); + deserialize_integer_key!(deserialize_u8 => visit_u8); + deserialize_integer_key!(deserialize_u16 => visit_u16); + deserialize_integer_key!(deserialize_u32 => visit_u32); + deserialize_integer_key!(deserialize_u64 => visit_u64); + deserialize_integer_key!(deserialize_u128 => visit_u128); #[inline] fn deserialize_option<V>(self, visitor: V) -> Result<V::Value> @@ -2294,8 +2221,8 @@ where } forward_to_deserialize_any! { - char str string unit unit_struct seq tuple tuple_struct map struct - identifier ignored_any + bool f32 f64 char str string unit unit_struct seq tuple tuple_struct map + struct identifier ignored_any } } @@ -2391,8 +2318,8 @@ where fn peek_end_of_value(&mut self) -> Result<()> { match tri!(self.de.peek()) { - Some(b' ' | b'\n' | b'\t' | b'\r' | b'"' | b'[' | b']' | b'{' | b'}' | b',' | b':') - | None => Ok(()), + Some(b' ') | Some(b'\n') | Some(b'\t') | Some(b'\r') | Some(b'"') | Some(b'[') + | Some(b']') | Some(b'{') | Some(b'}') | Some(b',') | Some(b':') | None => Ok(()), Some(_) => { let position = self.de.read.peek_position(); Err(Error::syntax( @@ -2442,7 +2369,7 @@ where if self_delineated_value { Ok(value) } else { - self.peek_end_of_value().map(|()| value) + self.peek_end_of_value().map(|_| value) } } Err(e) => { @@ -2481,9 +2408,9 @@ where Ok(value) } -/// Deserialize an instance of type `T` from an I/O stream of JSON. +/// Deserialize an instance of type `T` from an IO stream of JSON. /// -/// The content of the I/O stream is deserialized directly from the stream +/// The content of the IO stream is deserialized directly from the stream /// without being buffered in memory by serde_json. /// /// When reading from a source against which short reads are not efficient, such diff --git a/src/error.rs b/src/error.rs index fbf9eb1..0898baf 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,8 +9,6 @@ use core::str::FromStr; use serde::{de, ser}; #[cfg(feature = "std")] use std::error; -#[cfg(feature = "std")] -use std::io::ErrorKind; /// This type represents all possible errors that can occur when serializing or /// deserializing JSON data. @@ -38,16 +36,15 @@ impl Error { /// The first character in the input and any characters immediately /// following a newline character are in column 1. /// - /// Note that errors may occur in column 0, for example if a read from an - /// I/O stream fails immediately following a previously read newline - /// character. + /// Note that errors may occur in column 0, for example if a read from an IO + /// stream fails immediately following a previously read newline character. pub fn column(&self) -> usize { self.err.column } /// Categorizes the cause of this error. /// - /// - `Category::Io` - failure to read or write bytes on an I/O stream + /// - `Category::Io` - failure to read or write bytes on an IO stream /// - `Category::Syntax` - input that is not syntactically valid JSON /// - `Category::Data` - input data that is semantically incorrect /// - `Category::Eof` - unexpected end of the input data @@ -64,15 +61,12 @@ impl Error { | ErrorCode::ExpectedObjectCommaOrEnd | ErrorCode::ExpectedSomeIdent | ErrorCode::ExpectedSomeValue - | ErrorCode::ExpectedDoubleQuote | ErrorCode::InvalidEscape | ErrorCode::InvalidNumber | ErrorCode::NumberOutOfRange | ErrorCode::InvalidUnicodeCodePoint | ErrorCode::ControlCharacterWhileParsingString | ErrorCode::KeyMustBeAString - | ErrorCode::ExpectedNumericKey - | ErrorCode::FloatKeyMustBeFinite | ErrorCode::LoneLeadingSurrogateInHexEscape | ErrorCode::TrailingComma | ErrorCode::TrailingCharacters @@ -82,7 +76,7 @@ impl Error { } /// Returns true if this error was caused by a failure to read or write - /// bytes on an I/O stream. + /// bytes on an IO stream. pub fn is_io(&self) -> bool { self.classify() == Category::Io } @@ -110,61 +104,12 @@ impl Error { pub fn is_eof(&self) -> bool { self.classify() == Category::Eof } - - /// The kind reported by the underlying standard library I/O error, if this - /// error was caused by a failure to read or write bytes on an I/O stream. - /// - /// # Example - /// - /// ``` - /// use serde_json::Value; - /// use std::io::{self, ErrorKind, Read}; - /// use std::process; - /// - /// struct ReaderThatWillTimeOut<'a>(&'a [u8]); - /// - /// impl<'a> Read for ReaderThatWillTimeOut<'a> { - /// fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - /// if self.0.is_empty() { - /// Err(io::Error::new(ErrorKind::TimedOut, "timed out")) - /// } else { - /// self.0.read(buf) - /// } - /// } - /// } - /// - /// fn main() { - /// let reader = ReaderThatWillTimeOut(br#" {"k": "#); - /// - /// let _: Value = match serde_json::from_reader(reader) { - /// Ok(value) => value, - /// Err(error) => { - /// if error.io_error_kind() == Some(ErrorKind::TimedOut) { - /// // Maybe this application needs to retry certain kinds of errors. - /// - /// # return; - /// } else { - /// eprintln!("error: {}", error); - /// process::exit(1); - /// } - /// } - /// }; - /// } - /// ``` - #[cfg(feature = "std")] - pub fn io_error_kind(&self) -> Option<ErrorKind> { - if let ErrorCode::Io(io_error) = &self.err.code { - Some(io_error.kind()) - } else { - None - } - } } /// Categorizes the cause of a `serde_json::Error`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Category { - /// The error was caused by a failure to read or write bytes on an I/O + /// The error was caused by a failure to read or write bytes on an IO /// stream. Io, @@ -189,8 +134,8 @@ pub enum Category { impl From<Error> for io::Error { /// Convert a `serde_json::Error` into an `io::Error`. /// - /// JSON syntax and data errors are turned into `InvalidData` I/O errors. - /// EOF errors are turned into `UnexpectedEof` I/O errors. + /// JSON syntax and data errors are turned into `InvalidData` IO errors. + /// EOF errors are turned into `UnexpectedEof` IO errors. /// /// ``` /// use std::io; @@ -220,8 +165,8 @@ impl From<Error> for io::Error { } else { match j.classify() { Category::Io => unreachable!(), - Category::Syntax | Category::Data => io::Error::new(ErrorKind::InvalidData, j), - Category::Eof => io::Error::new(ErrorKind::UnexpectedEof, j), + Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, j), + Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, j), } } } @@ -237,7 +182,7 @@ pub(crate) enum ErrorCode { /// Catchall for syntax error messages Message(Box<str>), - /// Some I/O error occurred while serializing or deserializing. + /// Some IO error occurred while serializing or deserializing. Io(io::Error), /// EOF while parsing a list. @@ -267,9 +212,6 @@ pub(crate) enum ErrorCode { /// Expected this character to start a JSON value. ExpectedSomeValue, - /// Expected this character to be a `"`. - ExpectedDoubleQuote, - /// Invalid hex escape code. InvalidEscape, @@ -288,12 +230,6 @@ pub(crate) enum ErrorCode { /// Object key is not a string. KeyMustBeAString, - /// Contents of key were supposed to be a number. - ExpectedNumericKey, - - /// Object key is a non-finite float value. - FloatKeyMustBeFinite, - /// Lone leading surrogate in hex escape. LoneLeadingSurrogateInHexEscape, @@ -360,7 +296,6 @@ impl Display for ErrorCode { ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"), ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"), ErrorCode::ExpectedSomeValue => f.write_str("expected value"), - ErrorCode::ExpectedDoubleQuote => f.write_str("expected `\"`"), ErrorCode::InvalidEscape => f.write_str("invalid escape"), ErrorCode::InvalidNumber => f.write_str("invalid number"), ErrorCode::NumberOutOfRange => f.write_str("number out of range"), @@ -369,12 +304,6 @@ impl Display for ErrorCode { f.write_str("control character (\\u0000-\\u001F) found while parsing a string") } ErrorCode::KeyMustBeAString => f.write_str("key must be a string"), - ErrorCode::ExpectedNumericKey => { - f.write_str("invalid value: expected key to be a number in quotes") - } - ErrorCode::FloatKeyMustBeFinite => { - f.write_str("float key must be finite (got NaN or +/-inf)") - } ErrorCode::LoneLeadingSurrogateInHexEscape => { f.write_str("lone leading surrogate in hex escape") } @@ -438,20 +367,11 @@ impl de::Error for Error { #[cold] fn invalid_type(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self { - Error::custom(format_args!( - "invalid type: {}, expected {}", - JsonUnexpected(unexp), - exp, - )) - } - - #[cold] - fn invalid_value(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self { - Error::custom(format_args!( - "invalid value: {}, expected {}", - JsonUnexpected(unexp), - exp, - )) + if let de::Unexpected::Unit = unexp { + Error::custom(format_args!("invalid type: null, expected {}", exp)) + } else { + Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp)) + } } } @@ -462,22 +382,6 @@ impl ser::Error for Error { } } -struct JsonUnexpected<'a>(de::Unexpected<'a>); - -impl<'a> Display for JsonUnexpected<'a> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match self.0 { - de::Unexpected::Unit => formatter.write_str("null"), - de::Unexpected::Float(value) => write!( - formatter, - "floating point `{}`", - ryu::Buffer::new().format(value), - ), - unexp => Display::fmt(&unexp, formatter), - } - } -} - // Parse our own error message that looks like "{} at line {} column {}" to work // around erased-serde round-tripping the error through de::Error::custom. fn make_error(mut msg: String) -> Error { diff --git a/src/io/core.rs b/src/io/core.rs index 54c8ddf..465ab8b 100644 --- a/src/io/core.rs +++ b/src/io/core.rs @@ -9,7 +9,7 @@ pub enum ErrorKind { Other, } -// I/O errors can never occur in no-std mode. All our no-std I/O implementations +// IO errors can never occur in no-std mode. All our no-std IO implementations // are infallible. pub struct Error; diff --git a/src/lexical/algorithm.rs b/src/lexical/algorithm.rs index eaa5e7e..a2cbf18 100644 --- a/src/lexical/algorithm.rs +++ b/src/lexical/algorithm.rs @@ -51,10 +51,7 @@ where // Compute the product of the power, if it overflows, // prematurely return early, otherwise, if we didn't overshoot, // we can get an exact value. - let value = match mantissa.checked_mul(power) { - None => return None, - Some(value) => value, - }; + let value = mantissa.checked_mul(power)?; if value >> mantissa_size != 0 { None } else { diff --git a/src/lexical/digit.rs b/src/lexical/digit.rs index 3d150a1..882aa9e 100644 --- a/src/lexical/digit.rs +++ b/src/lexical/digit.rs @@ -11,8 +11,5 @@ pub(crate) fn to_digit(c: u8) -> Option<u32> { // Add digit to mantissa. #[inline] pub(crate) fn add_digit(value: u64, digit: u32) -> Option<u64> { - match value.checked_mul(10) { - None => None, - Some(n) => n.checked_add(digit as u64), - } + value.checked_mul(10)?.checked_add(digit as u64) } diff --git a/src/lexical/errors.rs b/src/lexical/errors.rs index f4f41cd..cad4bd3 100644 --- a/src/lexical/errors.rs +++ b/src/lexical/errors.rs @@ -5,7 +5,8 @@ //! This estimates the error in a floating-point representation. //! //! This implementation is loosely based off the Golang implementation, -//! found here: <https://golang.org/src/strconv/atof.go> +//! found here: +//! https://golang.org/src/strconv/atof.go use super::float::*; use super::num::*; diff --git a/src/lexical/math.rs b/src/lexical/math.rs index d7122bf..37cc1d2 100644 --- a/src/lexical/math.rs +++ b/src/lexical/math.rs @@ -336,7 +336,7 @@ mod small { pub fn imul(x: &mut Vec<Limb>, y: Limb) { // Multiply iteratively over all elements, adding the carry each time. let mut carry: Limb = 0; - for xi in &mut *x { + for xi in x.iter_mut() { carry = scalar::imul(xi, y, carry); } @@ -482,7 +482,7 @@ mod small { let rshift = bits - n; let lshift = n; let mut prev: Limb = 0; - for xi in &mut *x { + for xi in x.iter_mut() { let tmp = *xi; *xi <<= lshift; *xi |= prev >> rshift; diff --git a/src/lexical/num.rs b/src/lexical/num.rs index af10afd..e47e003 100644 --- a/src/lexical/num.rs +++ b/src/lexical/num.rs @@ -223,7 +223,7 @@ pub trait Float: Number { const NEGATIVE_INFINITY_BITS: Self::Unsigned; /// Size of the significand (mantissa) without hidden bit. const MANTISSA_SIZE: i32; - /// Bias of the exponent + /// Bias of the exponet const EXPONENT_BIAS: i32; /// Exponent portion of a denormal float. const DENORMAL_EXPONENT: i32; @@ -55,9 +55,10 @@ //! ``` //! //! A string of JSON data can be parsed into a `serde_json::Value` by the -//! [`serde_json::from_str`][from_str] function. There is also [`from_slice`] -//! for parsing from a byte slice &\[u8\] and [`from_reader`] for parsing from -//! any `io::Read` like a File or a TCP stream. +//! [`serde_json::from_str`][from_str] function. There is also +//! [`from_slice`][from_slice] for parsing from a byte slice &[u8] and +//! [`from_reader`][from_reader] for parsing from any `io::Read` like a File or +//! a TCP stream. //! //! ``` //! use serde_json::{Result, Value}; @@ -299,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.113")] +#![doc(html_root_url = "https://docs.rs/serde_json/1.0.94")] // Ignored clippy lints #![allow( clippy::collapsible_else_if, @@ -314,13 +315,18 @@ clippy::match_single_binding, clippy::needless_doctest_main, clippy::needless_late_init, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/8366 + clippy::ptr_arg, clippy::return_self_not_must_use, clippy::transmute_ptr_to_ptr, - clippy::unconditional_recursion, // https://github.com/rust-lang/rust-clippy/issues/12133 - clippy::unnecessary_wraps + clippy::unnecessary_wraps, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704 + clippy::unnested_or_patterns, )] // Ignored clippy_pedantic lints #![allow( + // buggy + clippy::iter_not_returning_iterator, // https://github.com/rust-lang/rust-clippy/issues/8285 // Deserializer::from_str, into_iter clippy::should_implement_trait, // integer and float ser/de requires these sorts of casts @@ -356,8 +362,6 @@ clippy::missing_errors_doc, clippy::must_use_candidate, )] -// Restrictions -#![deny(clippy::question_mark_used)] #![allow(non_upper_case_globals)] #![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] @@ -366,7 +370,6 @@ extern crate alloc; #[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[doc(inline)] pub use crate::de::from_reader; #[doc(inline)] @@ -376,7 +379,6 @@ pub use crate::error::{Error, Result}; #[doc(inline)] pub use crate::ser::{to_string, to_string_pretty, to_vec, to_vec_pretty}; #[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[doc(inline)] pub use crate::ser::{to_writer, to_writer_pretty, Serializer}; #[doc(inline)] diff --git a/src/macros.rs b/src/macros.rs index e8c6cd2..5287998 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -10,8 +10,7 @@ /// "features": [ /// "serde", /// "json" -/// ], -/// "homepage": null +/// ] /// } /// }); /// ``` @@ -11,7 +11,7 @@ use alloc::string::String; use core::borrow::Borrow; use core::fmt::{self, Debug}; use core::hash::Hash; -use core::iter::FusedIterator; +use core::iter::{FromIterator, FusedIterator}; #[cfg(feature = "preserve_order")] use core::mem; use core::ops; @@ -106,6 +106,7 @@ impl Map<String, Value> { /// The key may be any borrowed form of the map's key type, but the ordering /// on the borrowed form *must* match the ordering on the key type. #[inline] + #[cfg(any(feature = "preserve_order", not(no_btreemap_get_key_value)))] pub fn get_key_value<Q>(&self, key: &Q) -> Option<(&String, &Value)> where String: Borrow<Q>, @@ -130,12 +131,6 @@ impl Map<String, Value> { /// /// The key may be any borrowed form of the map's key type, but the ordering /// on the borrowed form *must* match the ordering on the key type. - /// - /// If serde_json's "preserve_order" is enabled, `.remove(key)` is - /// equivalent to [`.swap_remove(key)`][Self::swap_remove], replacing this - /// entry's position with the last element. If you need to preserve the - /// relative order of the keys in the map, use - /// [`.shift_remove(key)`][Self::shift_remove] instead. #[inline] pub fn remove<Q>(&mut self, key: &Q) -> Option<Value> where @@ -143,7 +138,7 @@ impl Map<String, Value> { Q: ?Sized + Ord + Eq + Hash, { #[cfg(feature = "preserve_order")] - return self.swap_remove(key); + return self.map.swap_remove(key); #[cfg(not(feature = "preserve_order"))] return self.map.remove(key); } @@ -153,86 +148,49 @@ impl Map<String, Value> { /// /// The key may be any borrowed form of the map's key type, but the ordering /// on the borrowed form *must* match the ordering on the key type. - /// - /// If serde_json's "preserve_order" is enabled, `.remove_entry(key)` is - /// equivalent to [`.swap_remove_entry(key)`][Self::swap_remove_entry], - /// replacing this entry's position with the last element. If you need to - /// preserve the relative order of the keys in the map, use - /// [`.shift_remove_entry(key)`][Self::shift_remove_entry] instead. - #[inline] pub fn remove_entry<Q>(&mut self, key: &Q) -> Option<(String, Value)> where String: Borrow<Q>, Q: ?Sized + Ord + Eq + Hash, { - #[cfg(feature = "preserve_order")] - return self.swap_remove_entry(key); - #[cfg(not(feature = "preserve_order"))] + #[cfg(any(feature = "preserve_order", not(no_btreemap_remove_entry)))] return self.map.remove_entry(key); - } - - /// Removes and returns the value corresponding to the key from the map. - /// - /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the - /// last element of the map and popping it off. This perturbs the position - /// of what used to be the last element! - #[cfg(feature = "preserve_order")] - #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] - #[inline] - pub fn swap_remove<Q>(&mut self, key: &Q) -> Option<Value> - where - String: Borrow<Q>, - Q: ?Sized + Ord + Eq + Hash, - { - self.map.swap_remove(key) - } - - /// Remove and return the key-value pair. - /// - /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the - /// last element of the map and popping it off. This perturbs the position - /// of what used to be the last element! - #[cfg(feature = "preserve_order")] - #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] - #[inline] - pub fn swap_remove_entry<Q>(&mut self, key: &Q) -> Option<(String, Value)> - where - String: Borrow<Q>, - Q: ?Sized + Ord + Eq + Hash, - { - self.map.swap_remove_entry(key) - } - - /// Removes and returns the value corresponding to the key from the map. - /// - /// Like [`Vec::remove`], the entry is removed by shifting all of the - /// elements that follow it, preserving their relative order. This perturbs - /// the index of all of those elements! - #[cfg(feature = "preserve_order")] - #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] - #[inline] - pub fn shift_remove<Q>(&mut self, key: &Q) -> Option<Value> - where - String: Borrow<Q>, - Q: ?Sized + Ord + Eq + Hash, - { - self.map.shift_remove(key) - } + #[cfg(all( + not(feature = "preserve_order"), + no_btreemap_remove_entry, + not(no_btreemap_get_key_value), + ))] + { + let (key, _value) = self.map.get_key_value(key)?; + let key = key.clone(); + let value = self.map.remove::<String>(&key)?; + Some((key, value)) + } + #[cfg(all( + not(feature = "preserve_order"), + no_btreemap_remove_entry, + no_btreemap_get_key_value, + ))] + { + use core::ops::{Bound, RangeBounds}; + + struct Key<'a, Q: ?Sized>(&'a Q); + + impl<'a, Q: ?Sized> RangeBounds<Q> for Key<'a, Q> { + fn start_bound(&self) -> Bound<&Q> { + Bound::Included(self.0) + } + fn end_bound(&self) -> Bound<&Q> { + Bound::Included(self.0) + } + } - /// Remove and return the key-value pair. - /// - /// Like [`Vec::remove`], the entry is removed by shifting all of the - /// elements that follow it, preserving their relative order. This perturbs - /// the index of all of those elements! - #[cfg(feature = "preserve_order")] - #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] - #[inline] - pub fn shift_remove_entry<Q>(&mut self, key: &Q) -> Option<(String, Value)> - where - String: Borrow<Q>, - Q: ?Sized + Ord + Eq + Hash, - { - self.map.shift_remove_entry(key) + let mut range = self.map.range(Key(key)); + let (key, _value) = range.next()?; + let key = key.clone(); + let value = self.map.remove::<String>(&key)?; + Some((key, value)) + } } /// Moves all elements from other into self, leaving other empty. @@ -318,6 +276,7 @@ impl Map<String, Value> { /// /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` /// returns `false`. + #[cfg(not(no_btreemap_retain))] #[inline] pub fn retain<F>(&mut self, f: F) where diff --git a/src/number.rs b/src/number.rs index b0231a8..21a7641 100644 --- a/src/number.rs +++ b/src/number.rs @@ -279,62 +279,6 @@ impl Number { } } - /// Returns the exact original JSON representation that this Number was - /// parsed from. - /// - /// For numbers constructed not via parsing, such as by `From<i32>`, returns - /// the JSON representation that serde\_json would serialize for this - /// number. - /// - /// ``` - /// # use serde_json::Number; - /// for value in [ - /// "7", - /// "12.34", - /// "34e-56789", - /// "0.0123456789000000012345678900000001234567890000123456789", - /// "343412345678910111213141516171819202122232425262728293034", - /// "-343412345678910111213141516171819202122232425262728293031", - /// ] { - /// let number: Number = serde_json::from_str(value).unwrap(); - /// assert_eq!(number.as_str(), value); - /// } - /// ``` - #[cfg(feature = "arbitrary_precision")] - #[cfg_attr(docsrs, doc(cfg(feature = "arbitrary_precision")))] - pub fn as_str(&self) -> &str { - &self.n - } - - pub(crate) fn as_f32(&self) -> Option<f32> { - #[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::<f32>().ok().filter(|float| float.is_finite()) - } - - pub(crate) fn from_f32(f: f32) -> Option<Number> { - 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)] @@ -388,8 +332,8 @@ impl Serialize for Number { { use serde::ser::SerializeStruct; - let mut s = tri!(serializer.serialize_struct(TOKEN, 1)); - tri!(s.serialize_field(TOKEN, &self.n)); + let mut s = serializer.serialize_struct(TOKEN, 1)?; + s.serialize_field(TOKEN, &self.n)?; s.end() } } @@ -433,11 +377,11 @@ impl<'de> Deserialize<'de> for Number { where V: de::MapAccess<'de>, { - let value = tri!(visitor.next_key::<NumberKey>()); + let value = visitor.next_key::<NumberKey>()?; if value.is_none() { return Err(de::Error::invalid_type(Unexpected::Map, &self)); } - let v: NumberFromString = tri!(visitor.next_value()); + let v: NumberFromString = visitor.next_value()?; Ok(v.value) } } @@ -476,7 +420,7 @@ impl<'de> de::Deserialize<'de> for NumberKey { } } - tri!(deserializer.deserialize_identifier(FieldVisitor)); + deserializer.deserialize_identifier(FieldVisitor)?; Ok(NumberKey) } } @@ -579,7 +523,7 @@ macro_rules! deserialize_number { where V: de::Visitor<'de>, { - visitor.$visit(tri!(self.n.parse().map_err(|_| invalid_number()))) + visitor.$visit(self.n.parse().map_err(|_| invalid_number())?) } }; } @@ -177,9 +177,11 @@ impl RawValue { /// - the input has no leading or trailing whitespace, and /// - the input has capacity equal to its length. pub fn from_string(json: String) -> Result<Box<Self>, Error> { - let borrowed = tri!(crate::from_str::<&Self>(&json)); - if borrowed.json.len() < json.len() { - return Ok(borrowed.to_owned()); + { + let borrowed = crate::from_str::<&Self>(&json)?; + if borrowed.json.len() < json.len() { + return Ok(borrowed.to_owned()); + } } Ok(Self::from_owned(json.into_boxed_str())) } @@ -285,7 +287,7 @@ pub fn to_raw_value<T>(value: &T) -> Result<Box<RawValue>, Error> where T: ?Sized + Serialize, { - let json_string = tri!(crate::to_string(value)); + let json_string = crate::to_string(value)?; Ok(RawValue::from_owned(json_string.into_boxed_str())) } @@ -296,8 +298,8 @@ impl Serialize for RawValue { where S: Serializer, { - let mut s = tri!(serializer.serialize_struct(TOKEN, 1)); - tri!(s.serialize_field(TOKEN, &self.json)); + let mut s = serializer.serialize_struct(TOKEN, 1)?; + s.serialize_field(TOKEN, &self.json)?; s.end() } } @@ -320,7 +322,7 @@ impl<'de: 'a, 'a> Deserialize<'de> for &'a RawValue { where V: MapAccess<'de>, { - let value = tri!(visitor.next_key::<RawKey>()); + let value = visitor.next_key::<RawKey>()?; if value.is_none() { return Err(de::Error::invalid_type(Unexpected::Map, &self)); } @@ -350,7 +352,7 @@ impl<'de> Deserialize<'de> for Box<RawValue> { where V: MapAccess<'de>, { - let value = tri!(visitor.next_key::<RawKey>()); + let value = visitor.next_key::<RawKey>()?; if value.is_none() { return Err(de::Error::invalid_type(Unexpected::Map, &self)); } @@ -390,7 +392,7 @@ impl<'de> Deserialize<'de> for RawKey { } } - tri!(deserializer.deserialize_identifier(FieldVisitor)); + deserializer.deserialize_identifier(FieldVisitor)?; Ok(RawKey) } } @@ -527,251 +529,3 @@ impl<'de> MapAccess<'de> for BorrowedRawDeserializer<'de> { seed.deserialize(BorrowedStrDeserializer::new(self.raw_value.take().unwrap())) } } - -impl<'de> IntoDeserializer<'de, Error> for &'de RawValue { - type Deserializer = &'de RawValue; - - fn into_deserializer(self) -> Self::Deserializer { - self - } -} - -impl<'de> Deserializer<'de> for &'de RawValue { - type Error = Error; - - fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_any(visitor) - } - - fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_bool(visitor) - } - - fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_i8(visitor) - } - - fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_i16(visitor) - } - - fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_i32(visitor) - } - - fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_i64(visitor) - } - - fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_i128(visitor) - } - - fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_u8(visitor) - } - - fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_u16(visitor) - } - - fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_u32(visitor) - } - - fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_u64(visitor) - } - - fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_u128(visitor) - } - - fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_f32(visitor) - } - - fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_f64(visitor) - } - - fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_char(visitor) - } - - fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_str(visitor) - } - - fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_string(visitor) - } - - fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_bytes(visitor) - } - - fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_byte_buf(visitor) - } - - fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_option(visitor) - } - - fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_unit(visitor) - } - - fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_unit_struct(name, visitor) - } - - fn deserialize_newtype_struct<V>( - self, - name: &'static str, - visitor: V, - ) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_newtype_struct(name, visitor) - } - - fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_seq(visitor) - } - - fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_tuple(len, visitor) - } - - fn deserialize_tuple_struct<V>( - self, - name: &'static str, - len: usize, - visitor: V, - ) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_tuple_struct(name, len, visitor) - } - - fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_map(visitor) - } - - fn deserialize_struct<V>( - self, - name: &'static str, - fields: &'static [&'static str], - visitor: V, - ) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_struct(name, fields, visitor) - } - - fn deserialize_enum<V>( - self, - name: &'static str, - variants: &'static [&'static str], - visitor: V, - ) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_enum(name, variants, visitor) - } - - fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_identifier(visitor) - } - - fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - crate::Deserializer::from_str(&self.json).deserialize_ignored_any(visitor) - } -} diff --git a/src/read.rs b/src/read.rs index 7446f28..fc3a3ca 100644 --- a/src/read.rs +++ b/src/read.rs @@ -81,7 +81,7 @@ pub trait Read<'de>: private::Sealed { #[doc(hidden)] fn ignore_str(&mut self) -> Result<()>; - /// Assumes the previous byte was a hex escape sequence ('\u') in a string. + /// Assumes the previous byte was a hex escape sequnce ('\u') in a string. /// Parses next hexadecimal sequence. #[doc(hidden)] fn decode_hex_escape(&mut self) -> Result<u16>; @@ -189,9 +189,12 @@ where #[inline] fn serialize_bytes(self, value: &[u8]) -> Result<()> { - self.formatter - .write_byte_array(&mut self.writer, value) - .map_err(Error::io) + use serde::ser::SerializeSeq; + let mut seq = tri!(self.serialize_seq(Some(value.len()))); + for byte in value { + tri!(seq.serialize_element(byte)); + } + seq.end() } #[inline] @@ -436,15 +439,17 @@ where .formatter .begin_string(&mut self.writer) .map_err(Error::io)); - let mut adapter = Adapter { - writer: &mut self.writer, - formatter: &mut self.formatter, - error: None, - }; - match write!(adapter, "{}", value) { - Ok(()) => debug_assert!(adapter.error.is_none()), - Err(fmt::Error) => { - return Err(Error::io(adapter.error.expect("there should be an error"))); + { + let mut adapter = Adapter { + writer: &mut self.writer, + formatter: &mut self.formatter, + error: None, + }; + match write!(adapter, "{}", value) { + Ok(()) => debug_assert!(adapter.error.is_none()), + Err(fmt::Error) => { + return Err(Error::io(adapter.error.expect("there should be an error"))); + } } } self.formatter @@ -784,10 +789,6 @@ fn key_must_be_a_string() -> Error { Error::syntax(ErrorCode::KeyMustBeAString, 0, 0) } -fn float_key_must_be_finite() -> Error { - Error::syntax(ErrorCode::FloatKeyMustBeFinite, 0, 0) -} - impl<'a, W, F> ser::Serializer for MapKeySerializer<'a, W, F> where W: io::Write, @@ -827,21 +828,8 @@ where type SerializeStruct = Impossible<(), Error>; type SerializeStructVariant = Impossible<(), Error>; - fn serialize_bool(self, value: bool) -> Result<()> { - tri!(self - .ser - .formatter - .begin_string(&mut self.ser.writer) - .map_err(Error::io)); - tri!(self - .ser - .formatter - .write_bool(&mut self.ser.writer, value) - .map_err(Error::io)); - self.ser - .formatter - .end_string(&mut self.ser.writer) - .map_err(Error::io) + fn serialize_bool(self, _value: bool) -> Result<()> { + Err(key_must_be_a_string()) } fn serialize_i8(self, value: i8) -> Result<()> { @@ -1014,46 +1002,12 @@ where .map_err(Error::io) } - fn serialize_f32(self, value: f32) -> Result<()> { - if !value.is_finite() { - return Err(float_key_must_be_finite()); - } - - tri!(self - .ser - .formatter - .begin_string(&mut self.ser.writer) - .map_err(Error::io)); - tri!(self - .ser - .formatter - .write_f32(&mut self.ser.writer, value) - .map_err(Error::io)); - self.ser - .formatter - .end_string(&mut self.ser.writer) - .map_err(Error::io) + fn serialize_f32(self, _value: f32) -> Result<()> { + Err(key_must_be_a_string()) } - fn serialize_f64(self, value: f64) -> Result<()> { - if !value.is_finite() { - return Err(float_key_must_be_finite()); - } - - tri!(self - .ser - .formatter - .begin_string(&mut self.ser.writer) - .map_err(Error::io)); - tri!(self - .ser - .formatter - .write_f64(&mut self.ser.writer, value) - .map_err(Error::io)); - self.ser - .formatter - .end_string(&mut self.ser.writer) - .map_err(Error::io) + fn serialize_f64(self, _value: f64) -> Result<()> { + Err(key_must_be_a_string()) } fn serialize_char(self, value: char) -> Result<()> { @@ -1089,11 +1043,11 @@ where Err(key_must_be_a_string()) } - fn serialize_some<T>(self, value: &T) -> Result<()> + fn serialize_some<T>(self, _value: &T) -> Result<()> where T: ?Sized + Serialize, { - value.serialize(self) + Err(key_must_be_a_string()) } fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> { @@ -1780,24 +1734,6 @@ pub trait Formatter { writer.write_all(s) } - /// Writes the representation of a byte array. Formatters can choose whether - /// to represent bytes as a JSON array of integers (the default), or some - /// JSON string encoding like hex or base64. - fn write_byte_array<W>(&mut self, writer: &mut W, value: &[u8]) -> io::Result<()> - where - W: ?Sized + io::Write, - { - tri!(self.begin_array(writer)); - let mut first = true; - for byte in value { - tri!(self.begin_array_value(writer, first)); - tri!(self.write_u8(writer, *byte)); - tri!(self.end_array_value(writer)); - first = false; - } - self.end_array(writer) - } - /// Called before every array. Writes a `[` to the specified /// writer. #[inline] @@ -2126,9 +2062,7 @@ static ESCAPE: [u8; 256] = [ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F ]; -/// Serialize the given data structure as JSON into the I/O stream. -/// -/// Serialization guarantees it only feeds valid UTF-8 sequences to the writer. +/// Serialize the given data structure as JSON into the IO stream. /// /// # Errors /// @@ -2145,11 +2079,9 @@ where value.serialize(&mut ser) } -/// Serialize the given data structure as pretty-printed JSON into the I/O +/// Serialize the given data structure as pretty-printed JSON into the IO /// stream. /// -/// Serialization guarantees it only feeds valid UTF-8 sequences to the writer. -/// /// # Errors /// /// Serialization can fail if `T`'s implementation of `Serialize` decides to diff --git a/src/value/de.rs b/src/value/de.rs index 1e8b5ac..9c266d0 100644 --- a/src/value/de.rs +++ b/src/value/de.rs @@ -1,4 +1,4 @@ -use crate::error::{Error, ErrorCode}; +use crate::error::Error; use crate::map::Map; use crate::number::Number; use crate::value::Value; @@ -106,15 +106,15 @@ impl<'de> Deserialize<'de> for Value { where V: MapAccess<'de>, { - match tri!(visitor.next_key_seed(KeyClassifier)) { + match visitor.next_key_seed(KeyClassifier)? { #[cfg(feature = "arbitrary_precision")] Some(KeyClass::Number) => { - let number: NumberFromString = tri!(visitor.next_value()); + let number: NumberFromString = visitor.next_value()?; Ok(Value::Number(number.value)) } #[cfg(feature = "raw_value")] Some(KeyClass::RawValue) => { - let value = tri!(visitor.next_value_seed(crate::raw::BoxedFromString)); + let value = visitor.next_value_seed(crate::raw::BoxedFromString)?; crate::from_str(value.get()).map_err(de::Error::custom) } Some(KeyClass::Map(first_key)) => { @@ -482,14 +482,6 @@ impl<'de> IntoDeserializer<'de, Error> for Value { } } -impl<'de> IntoDeserializer<'de, Error> for &'de Value { - type Deserializer = Self; - - fn into_deserializer(self) -> Self::Deserializer { - self - } -} - struct VariantDeserializer { value: Option<Value>, } @@ -1128,30 +1120,18 @@ struct MapKeyDeserializer<'de> { key: Cow<'de, str>, } -macro_rules! deserialize_numeric_key { - ($method:ident) => { - deserialize_numeric_key!($method, deserialize_number); - }; - - ($method:ident, $using:ident) => { +macro_rules! deserialize_integer_key { + ($method:ident => $visit:ident) => { fn $method<V>(self, visitor: V) -> Result<V::Value, Error> where V: Visitor<'de>, { - let mut de = crate::Deserializer::from_str(&self.key); - - match tri!(de.peek()) { - Some(b'0'..=b'9' | b'-') => {} - _ => return Err(Error::syntax(ErrorCode::ExpectedNumericKey, 0, 0)), - } - - let number = tri!(de.$using(visitor)); - - if tri!(de.peek()).is_some() { - return Err(Error::syntax(ErrorCode::ExpectedNumericKey, 0, 0)); + match (self.key.parse(), self.key) { + (Ok(integer), _) => visitor.$visit(integer), + (Err(_), Cow::Borrowed(s)) => visitor.visit_borrowed_str(s), + #[cfg(any(feature = "std", feature = "alloc"))] + (Err(_), Cow::Owned(s)) => visitor.visit_string(s), } - - Ok(number) } }; } @@ -1166,38 +1146,16 @@ impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> { BorrowedCowStrDeserializer::new(self.key).deserialize_any(visitor) } - deserialize_numeric_key!(deserialize_i8); - deserialize_numeric_key!(deserialize_i16); - deserialize_numeric_key!(deserialize_i32); - deserialize_numeric_key!(deserialize_i64); - deserialize_numeric_key!(deserialize_u8); - deserialize_numeric_key!(deserialize_u16); - deserialize_numeric_key!(deserialize_u32); - deserialize_numeric_key!(deserialize_u64); - #[cfg(not(feature = "float_roundtrip"))] - deserialize_numeric_key!(deserialize_f32); - deserialize_numeric_key!(deserialize_f64); - - #[cfg(feature = "float_roundtrip")] - deserialize_numeric_key!(deserialize_f32, do_deserialize_f32); - deserialize_numeric_key!(deserialize_i128, do_deserialize_i128); - deserialize_numeric_key!(deserialize_u128, do_deserialize_u128); - - fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Error> - where - V: Visitor<'de>, - { - if self.key == "true" { - visitor.visit_bool(true) - } else if self.key == "false" { - visitor.visit_bool(false) - } else { - Err(serde::de::Error::invalid_type( - Unexpected::Str(&self.key), - &visitor, - )) - } - } + deserialize_integer_key!(deserialize_i8 => visit_i8); + deserialize_integer_key!(deserialize_i16 => visit_i16); + deserialize_integer_key!(deserialize_i32 => visit_i32); + deserialize_integer_key!(deserialize_i64 => visit_i64); + deserialize_integer_key!(deserialize_i128 => visit_i128); + deserialize_integer_key!(deserialize_u8 => visit_u8); + deserialize_integer_key!(deserialize_u16 => visit_u16); + deserialize_integer_key!(deserialize_u32 => visit_u32); + deserialize_integer_key!(deserialize_u64 => visit_u64); + deserialize_integer_key!(deserialize_u128 => visit_u128); #[inline] fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error> @@ -1235,8 +1193,8 @@ impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> { } forward_to_deserialize_any! { - char str string bytes byte_buf unit unit_struct seq tuple tuple_struct - map struct identifier ignored_any + bool f32 f64 char str string bytes byte_buf unit unit_struct seq tuple + tuple_struct map struct identifier ignored_any } } @@ -1369,7 +1327,7 @@ impl<'de> de::EnumAccess<'de> for BorrowedCowStrDeserializer<'de> { where T: de::DeserializeSeed<'de>, { - let value = tri!(seed.deserialize(self)); + let value = seed.deserialize(self)?; Ok((value, UnitOnly)) } } diff --git a/src/value/from.rs b/src/value/from.rs index ed1e333..c5a6a39 100644 --- a/src/value/from.rs +++ b/src/value/from.rs @@ -4,6 +4,7 @@ use crate::number::Number; use alloc::borrow::Cow; use alloc::string::{String, ToString}; use alloc::vec::Vec; +use core::iter::FromIterator; macro_rules! from_integer { ($($ty:ident)*) => { @@ -28,8 +29,7 @@ from_integer! { } impl From<f32> for Value { - /// Convert 32-bit floating point number to `Value::Number`, or - /// `Value::Null` if infinite or NaN. + /// Convert 32-bit floating point number to `Value` /// /// # Examples /// @@ -40,13 +40,12 @@ impl From<f32> for Value { /// let x: Value = f.into(); /// ``` fn from(f: f32) -> Self { - Number::from_f32(f).map_or(Value::Null, Value::Number) + From::from(f as f64) } } impl From<f64> for Value { - /// Convert 64-bit floating point number to `Value::Number`, or - /// `Value::Null` if infinite or NaN. + /// Convert 64-bit floating point number to `Value` /// /// # Examples /// @@ -62,7 +61,7 @@ impl From<f64> for Value { } impl From<bool> for Value { - /// Convert boolean to `Value::Bool`. + /// Convert boolean to `Value` /// /// # Examples /// @@ -78,7 +77,7 @@ impl From<bool> for Value { } impl From<String> for Value { - /// Convert `String` to `Value::String`. + /// Convert `String` to `Value` /// /// # Examples /// @@ -93,8 +92,8 @@ impl From<String> for Value { } } -impl From<&str> for Value { - /// Convert string slice to `Value::String`. +impl<'a> From<&'a str> for Value { + /// Convert string slice to `Value` /// /// # Examples /// @@ -110,7 +109,7 @@ impl From<&str> for Value { } impl<'a> From<Cow<'a, str>> for Value { - /// Convert copy-on-write string to `Value::String`. + /// Convert copy-on-write string to `Value` /// /// # Examples /// @@ -135,7 +134,7 @@ impl<'a> From<Cow<'a, str>> for Value { } impl From<Number> for Value { - /// Convert `Number` to `Value::Number`. + /// Convert `Number` to `Value` /// /// # Examples /// @@ -151,7 +150,7 @@ impl From<Number> for Value { } impl From<Map<String, Value>> for Value { - /// Convert map (with string keys) to `Value::Object`. + /// Convert map (with string keys) to `Value` /// /// # Examples /// @@ -168,7 +167,7 @@ impl From<Map<String, Value>> for Value { } impl<T: Into<Value>> From<Vec<T>> for Value { - /// Convert a `Vec` to `Value::Array`. + /// Convert a `Vec` to `Value` /// /// # Examples /// @@ -183,8 +182,8 @@ impl<T: Into<Value>> From<Vec<T>> for Value { } } -impl<T: Clone + Into<Value>> From<&[T]> for Value { - /// Convert a slice to `Value::Array`. +impl<'a, T: Clone + Into<Value>> From<&'a [T]> for Value { + /// Convert a slice to `Value` /// /// # Examples /// @@ -194,13 +193,13 @@ impl<T: Clone + Into<Value>> From<&[T]> for Value { /// let v: &[&str] = &["lorem", "ipsum", "dolor"]; /// let x: Value = v.into(); /// ``` - fn from(f: &[T]) -> Self { + fn from(f: &'a [T]) -> Self { Value::Array(f.iter().cloned().map(Into::into).collect()) } } impl<T: Into<Value>> FromIterator<T> for Value { - /// Create a `Value::Array` by collecting an iterator of array elements. + /// Convert an iteratable type to a `Value` /// /// # Examples /// @@ -230,7 +229,7 @@ impl<T: Into<Value>> FromIterator<T> for Value { } impl<K: Into<String>, V: Into<Value>> FromIterator<(K, V)> for Value { - /// Create a `Value::Object` by collecting an iterator of key-value pairs. + /// Convert an iteratable type to a `Value` /// /// # Examples /// @@ -250,7 +249,7 @@ impl<K: Into<String>, V: Into<Value>> FromIterator<(K, V)> for Value { } impl From<()> for Value { - /// Convert `()` to `Value::Null`. + /// Convert `()` to `Value` /// /// # Examples /// diff --git a/src/value/index.rs b/src/value/index.rs index 891ca8e..c74042b 100644 --- a/src/value/index.rs +++ b/src/value/index.rs @@ -116,7 +116,7 @@ impl Index for String { } } -impl<T> Index for &T +impl<'a, T> Index for &'a T where T: ?Sized + Index, { diff --git a/src/value/mod.rs b/src/value/mod.rs index b3f51ea..470b6b2 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -106,7 +106,6 @@ pub use crate::map::Map; pub use crate::number::Number; #[cfg(feature = "raw_value")] -#[cfg_attr(docsrs, doc(cfg(feature = "raw_value")))] pub use crate::raw::{to_raw_value, RawValue}; /// Represents any valid JSON value. @@ -183,11 +182,11 @@ impl Debug for Value { Value::Number(number) => Debug::fmt(number, formatter), Value::String(string) => write!(formatter, "String({:?})", string), Value::Array(vec) => { - tri!(formatter.write_str("Array ")); + formatter.write_str("Array ")?; Debug::fmt(vec, formatter) } Value::Object(map) => { - tri!(formatter.write_str("Object ")); + formatter.write_str("Object ")?; Debug::fmt(map, formatter) } } @@ -515,28 +514,6 @@ impl Value { } } - /// If the `Value` is a Number, returns the associated [`Number`]. Returns - /// None otherwise. - /// - /// ``` - /// # use serde_json::{json, Number}; - /// # - /// let v = json!({ "a": 1, "b": 2.2, "c": -3, "d": "4" }); - /// - /// assert_eq!(v["a"].as_number(), Some(&Number::from(1u64))); - /// assert_eq!(v["b"].as_number(), Some(&Number::from_f64(2.2).unwrap())); - /// assert_eq!(v["c"].as_number(), Some(&Number::from(-3i64))); - /// - /// // The string `"4"` is not a number. - /// assert_eq!(v["d"].as_number(), None); - /// ``` - pub fn as_number(&self) -> Option<&Number> { - match self { - Value::Number(number) => Some(number), - _ => None, - } - } - /// Returns true if the `Value` is an integer between `i64::MIN` and /// `i64::MAX`. /// @@ -912,6 +889,7 @@ mod ser; /// ``` /// use serde::Serialize; /// use serde_json::json; +/// /// use std::error::Error; /// /// #[derive(Serialize)] @@ -920,7 +898,7 @@ mod ser; /// location: String, /// } /// -/// fn compare_json_values() -> Result<(), Box<dyn Error>> { +/// fn compare_json_values() -> Result<(), Box<Error>> { /// let u = User { /// fingerprint: "0xF9BA143B95FF6D82".to_owned(), /// location: "Menlo Park, CA".to_owned(), diff --git a/src/value/partial_eq.rs b/src/value/partial_eq.rs index 46c1dbc..b4ef84c 100644 --- a/src/value/partial_eq.rs +++ b/src/value/partial_eq.rs @@ -9,13 +9,6 @@ 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) } @@ -34,7 +27,7 @@ impl PartialEq<str> for Value { } } -impl PartialEq<&str> for Value { +impl<'a> PartialEq<&'a str> for Value { fn eq(&self, other: &&str) -> bool { eq_str(self, *other) } @@ -46,7 +39,7 @@ impl PartialEq<Value> for str { } } -impl PartialEq<Value> for &str { +impl<'a> PartialEq<Value> for &'a str { fn eq(&self, other: &Value) -> bool { eq_str(other, *self) } @@ -97,7 +90,6 @@ macro_rules! partialeq_numeric { partialeq_numeric! { eq_i64[i8 i16 i32 i64 isize] eq_u64[u8 u16 u32 u64 usize] - eq_f32[f32] - eq_f64[f64] + eq_f64[f32 f64] eq_bool[bool] } diff --git a/src/value/ser.rs b/src/value/ser.rs index 835fa90..a29814e 100644 --- a/src/value/ser.rs +++ b/src/value/ser.rs @@ -1,9 +1,12 @@ 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}; use alloc::vec::Vec; +#[cfg(not(feature = "arbitrary_precision"))] +use core::convert::TryFrom; use core::fmt::Display; use core::result; use serde::ser::{Impossible, Serialize}; @@ -146,13 +149,13 @@ impl serde::Serializer for Serializer { } #[inline] - fn serialize_f32(self, float: f32) -> Result<Value> { - Ok(Value::from(float)) + fn serialize_f32(self, value: f32) -> Result<Value> { + self.serialize_f64(value as f64) } #[inline] - fn serialize_f64(self, float: f64) -> Result<Value> { - Ok(Value::from(float)) + fn serialize_f64(self, value: f64) -> Result<Value> { + Ok(Number::from_f64(value).map_or(Value::Null, Value::Number)) } #[inline] @@ -449,10 +452,6 @@ fn key_must_be_a_string() -> Error { Error::syntax(ErrorCode::KeyMustBeAString, 0, 0) } -fn float_key_must_be_finite() -> Error { - Error::syntax(ErrorCode::FloatKeyMustBeFinite, 0, 0) -} - impl serde::Serializer for MapKeySerializer { type Ok = String; type Error = Error; @@ -483,8 +482,8 @@ impl serde::Serializer for MapKeySerializer { value.serialize(self) } - fn serialize_bool(self, value: bool) -> Result<String> { - Ok(value.to_string()) + fn serialize_bool(self, _value: bool) -> Result<String> { + Err(key_must_be_a_string()) } fn serialize_i8(self, value: i8) -> Result<String> { @@ -519,20 +518,12 @@ impl serde::Serializer for MapKeySerializer { Ok(value.to_string()) } - fn serialize_f32(self, value: f32) -> Result<String> { - if value.is_finite() { - Ok(ryu::Buffer::new().format_finite(value).to_owned()) - } else { - Err(float_key_must_be_finite()) - } + fn serialize_f32(self, _value: f32) -> Result<String> { + Err(key_must_be_a_string()) } - fn serialize_f64(self, value: f64) -> Result<String> { - if value.is_finite() { - Ok(ryu::Buffer::new().format_finite(value).to_owned()) - } else { - Err(float_key_must_be_finite()) - } + fn serialize_f64(self, _value: f64) -> Result<String> { + Err(key_must_be_a_string()) } #[inline] @@ -650,7 +641,7 @@ impl serde::ser::SerializeStruct for SerializeMap { #[cfg(feature = "arbitrary_precision")] SerializeMap::Number { out_value } => { if key == crate::number::TOKEN { - *out_value = Some(tri!(value.serialize(NumberValueEmitter))); + *out_value = Some(value.serialize(NumberValueEmitter)?); Ok(()) } else { Err(invalid_number()) @@ -659,7 +650,7 @@ impl serde::ser::SerializeStruct for SerializeMap { #[cfg(feature = "raw_value")] SerializeMap::RawValue { out_value } => { if key == crate::raw::TOKEN { - *out_value = Some(tri!(value.serialize(RawValueEmitter))); + *out_value = Some(value.serialize(RawValueEmitter)?); Ok(()) } else { Err(invalid_raw_value()) diff --git a/tests/lexical.rs b/tests/lexical.rs index 368c844..d3dfb85 100644 --- a/tests/lexical.rs +++ b/tests/lexical.rs @@ -26,6 +26,11 @@ extern crate alloc; #[path = "../src/lexical/mod.rs"] mod lexical; +mod lib { + pub use std::vec::Vec; + pub use std::{cmp, iter, mem, ops}; +} + #[path = "lexical/algorithm.rs"] mod algorithm; diff --git a/tests/lexical/parse.rs b/tests/lexical/parse.rs index 03ec1a9..80ca25e 100644 --- a/tests/lexical/parse.rs +++ b/tests/lexical/parse.rs @@ -1,7 +1,7 @@ // Adapted from https://github.com/Alexhuszagh/rust-lexical. use crate::lexical::num::Float; -use crate::lexical::{parse_concise_float, parse_truncated_float}; +use crate::lexical::parse::{parse_concise_float, parse_truncated_float}; use core::f64; use core::fmt::Debug; diff --git a/tests/map.rs b/tests/map.rs index 538cd16..ae01969 100644 --- a/tests/map.rs +++ b/tests/map.rs @@ -35,6 +35,7 @@ fn test_append() { assert!(val.is_empty()); } +#[cfg(not(no_btreemap_retain))] #[test] fn test_retain() { let mut v: Value = from_str(r#"{"b":null,"a":null,"c":null}"#).unwrap(); diff --git a/tests/regression/issue1004.rs b/tests/regression/issue1004.rs deleted file mode 100644 index c09fb96..0000000 --- a/tests/regression/issue1004.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![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(); - - // If the f32 were cast to f64 by Value before serialization, then this - // would incorrectly serialize as 5.550000190734863. - assert_eq!(json, "5.55"); -} diff --git a/tests/regression/issue845.rs b/tests/regression/issue845.rs index e8b0c0f..56037ae 100644 --- a/tests/regression/issue845.rs +++ b/tests/regression/issue845.rs @@ -1,6 +1,7 @@ #![allow(clippy::trait_duplication_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/8757 use serde::{Deserialize, Deserializer}; +use std::convert::TryFrom; use std::fmt::{self, Display}; use std::marker::PhantomData; use std::str::FromStr; diff --git a/tests/test.rs b/tests/test.rs index 05b7f86..6c08cc8 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -14,6 +14,9 @@ clippy::vec_init_then_push, clippy::zero_sized_map_values )] +#![cfg_attr(feature = "trace-macros", feature(trace_macros))] +#[cfg(feature = "trace-macros")] +trace_macros!(true); #[macro_use] mod macros; @@ -30,12 +33,11 @@ use serde_json::{ from_reader, from_slice, from_str, from_value, json, to_string, to_string_pretty, to_value, to_vec, Deserializer, Number, Value, }; +use std::collections::hash_map::DefaultHasher; use std::collections::BTreeMap; #[cfg(feature = "raw_value")] use std::collections::HashMap; use std::fmt::{self, Debug}; -use std::hash::BuildHasher; -#[cfg(feature = "raw_value")] use std::hash::{Hash, Hasher}; use std::io; use std::iter; @@ -51,7 +53,7 @@ macro_rules! treemap { () => { BTreeMap::new() }; - ($($k:expr => $v:expr),+ $(,)?) => { + ($($k:expr => $v:expr),+) => { { let mut m = BTreeMap::new(); $( @@ -158,29 +160,17 @@ fn test_write_f64() { #[test] fn test_encode_nonfinite_float_yields_null() { - let v = to_value(::std::f64::NAN.copysign(1.0)).unwrap(); - assert!(v.is_null()); - - let v = to_value(::std::f64::NAN.copysign(-1.0)).unwrap(); + let v = to_value(::std::f64::NAN).unwrap(); assert!(v.is_null()); let v = to_value(::std::f64::INFINITY).unwrap(); assert!(v.is_null()); - let v = to_value(-::std::f64::INFINITY).unwrap(); - assert!(v.is_null()); - - let v = to_value(::std::f32::NAN.copysign(1.0)).unwrap(); - assert!(v.is_null()); - - let v = to_value(::std::f32::NAN.copysign(-1.0)).unwrap(); + let v = to_value(::std::f32::NAN).unwrap(); assert!(v.is_null()); let v = to_value(::std::f32::INFINITY).unwrap(); assert!(v.is_null()); - - let v = to_value(-::std::f32::INFINITY).unwrap(); - assert!(v.is_null()); } #[test] @@ -274,7 +264,7 @@ fn test_write_object() { ( treemap!( "a".to_string() => true, - "b".to_string() => false, + "b".to_string() => false ), "{\"a\":true,\"b\":false}", ), @@ -285,7 +275,7 @@ fn test_write_object() { treemap![ "a".to_string() => treemap![], "b".to_string() => treemap![], - "c".to_string() => treemap![], + "c".to_string() => treemap![] ], "{\"a\":{},\"b\":{},\"c\":{}}", ), @@ -294,10 +284,10 @@ fn test_write_object() { "a".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![], + "c".to_string() => treemap![] ], "b".to_string() => treemap![], - "c".to_string() => treemap![], + "c".to_string() => treemap![] ], "{\"a\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}},\"b\":{},\"c\":{}}", ), @@ -307,9 +297,9 @@ fn test_write_object() { "b".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![], + "c".to_string() => treemap![] ], - "c".to_string() => treemap![], + "c".to_string() => treemap![] ], "{\"a\":{},\"b\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}},\"c\":{}}", ), @@ -320,8 +310,8 @@ fn test_write_object() { "c".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![], - ], + "c".to_string() => treemap![] + ] ], "{\"a\":{},\"b\":{},\"c\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}}}", ), @@ -334,7 +324,7 @@ fn test_write_object() { treemap![ "a".to_string() => treemap![], "b".to_string() => treemap![], - "c".to_string() => treemap![], + "c".to_string() => treemap![] ], pretty_str!({ "a": {}, @@ -347,10 +337,10 @@ fn test_write_object() { "a".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![], + "c".to_string() => treemap![] ], "b".to_string() => treemap![], - "c".to_string() => treemap![], + "c".to_string() => treemap![] ], pretty_str!({ "a": { @@ -374,9 +364,9 @@ fn test_write_object() { "b".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![], + "c".to_string() => treemap![] ], - "c".to_string() => treemap![], + "c".to_string() => treemap![] ], pretty_str!({ "a": {}, @@ -401,8 +391,8 @@ fn test_write_object() { "c".to_string() => treemap![ "a".to_string() => treemap!["a" => vec![1,2,3]], "b".to_string() => treemap![], - "c".to_string() => treemap![], - ], + "c".to_string() => treemap![] + ] ], pretty_str!({ "a": {}, @@ -433,7 +423,7 @@ fn test_write_object() { ( treemap!( "a".to_string() => true, - "b".to_string() => false, + "b".to_string() => false ), pretty_str!( { "a": true, @@ -1202,8 +1192,8 @@ fn test_parse_object() { treemap!( "a".to_string() => treemap!( "b".to_string() => 3u64, - "c".to_string() => 4, - ), + "c".to_string() => 4 + ) ), )]); @@ -1379,7 +1369,7 @@ fn test_parse_enum() { ), treemap!( "a".to_string() => Animal::Dog, - "b".to_string() => Animal::Frog("Henry".to_string(), vec![]), + "b".to_string() => Animal::Frog("Henry".to_string(), vec![]) ), )]); } @@ -1462,6 +1452,7 @@ fn test_serialize_seq_with_no_len() { where T: ser::Serialize, { + #[inline] fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -1488,6 +1479,7 @@ fn test_serialize_seq_with_no_len() { formatter.write_str("array") } + #[inline] fn visit_unit<E>(self) -> Result<MyVec<T>, E> where E: de::Error, @@ -1495,6 +1487,7 @@ fn test_serialize_seq_with_no_len() { Ok(MyVec(Vec::new())) } + #[inline] fn visit_seq<V>(self, mut visitor: V) -> Result<MyVec<T>, V::Error> where V: de::SeqAccess<'de>, @@ -1545,6 +1538,7 @@ fn test_serialize_map_with_no_len() { K: ser::Serialize + Ord, V: ser::Serialize, { + #[inline] fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer, @@ -1572,6 +1566,7 @@ fn test_serialize_map_with_no_len() { formatter.write_str("map") } + #[inline] fn visit_unit<E>(self) -> Result<MyMap<K, V>, E> where E: de::Error, @@ -1579,6 +1574,7 @@ fn test_serialize_map_with_no_len() { Ok(MyMap(BTreeMap::new())) } + #[inline] fn visit_map<Visitor>(self, mut visitor: Visitor) -> Result<MyMap<K, V>, Visitor::Error> where Visitor: de::MapAccess<'de>, @@ -1665,11 +1661,22 @@ fn test_deserialize_from_stream() { } #[test] +fn test_serialize_rejects_bool_keys() { + let map = treemap!( + true => 2, + false => 4 + ); + + let err = to_vec(&map).unwrap_err(); + assert_eq!(err.to_string(), "key must be a string"); +} + +#[test] fn test_serialize_rejects_adt_keys() { let map = treemap!( Some("a") => 2, Some("b") => 4, - None => 6, + None => 6 ); let err = to_vec(&map).unwrap_err(); @@ -1883,41 +1890,23 @@ fn test_integer_key() { // map with integer keys let map = treemap!( 1 => 2, - -1 => 6, + -1 => 6 ); let j = r#"{"-1":6,"1":2}"#; test_encode_ok(&[(&map, j)]); test_parse_ok(vec![(j, map)]); - test_parse_err::<BTreeMap<i32, ()>>(&[ - ( - r#"{"x":null}"#, - "invalid value: expected key to be a number in quotes at line 1 column 2", - ), - ( - r#"{" 123":null}"#, - "invalid value: expected key to be a number in quotes at line 1 column 2", - ), - (r#"{"123 ":null}"#, "expected `\"` at line 1 column 6"), - ]); - - let err = from_value::<BTreeMap<i32, ()>>(json!({" 123":null})).unwrap_err(); - assert_eq!( - err.to_string(), - "invalid value: expected key to be a number in quotes", - ); - - let err = from_value::<BTreeMap<i32, ()>>(json!({"123 ":null})).unwrap_err(); - assert_eq!( - err.to_string(), - "invalid value: expected key to be a number in quotes", - ); + let j = r#"{"x":null}"#; + test_parse_err::<BTreeMap<i32, ()>>(&[( + j, + "invalid type: string \"x\", expected i32 at line 1 column 4", + )]); } #[test] fn test_integer128_key() { let map = treemap! { - 100000000000000000000000000000000000000u128 => (), + 100000000000000000000000000000000000000u128 => () }; let j = r#"{"100000000000000000000000000000000000000":null}"#; assert_eq!(to_string(&map).unwrap(), j); @@ -1925,107 +1914,24 @@ fn test_integer128_key() { } #[test] -fn test_float_key() { - #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)] +fn test_deny_float_key() { + #[derive(Eq, PartialEq, Ord, PartialOrd)] struct Float; impl Serialize for Float { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { - serializer.serialize_f32(1.23) - } - } - impl<'de> Deserialize<'de> for Float { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: de::Deserializer<'de>, - { - f32::deserialize(deserializer).map(|_| Float) + serializer.serialize_f32(1.0) } } // map with float key - let map = treemap!(Float => "x".to_owned()); - let j = r#"{"1.23":"x"}"#; - - test_encode_ok(&[(&map, j)]); - test_parse_ok(vec![(j, map)]); - - let j = r#"{"x": null}"#; - test_parse_err::<BTreeMap<Float, ()>>(&[( - j, - "invalid value: expected key to be a number in quotes at line 1 column 2", - )]); -} - -#[test] -fn test_deny_non_finite_f32_key() { - // We store float bits so that we can derive Ord, and other traits. In a - // real context the code might involve a crate like ordered-float. - - #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)] - struct F32Bits(u32); - impl Serialize for F32Bits { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - serializer.serialize_f32(f32::from_bits(self.0)) - } - } - - let map = treemap!(F32Bits(f32::INFINITY.to_bits()) => "x".to_owned()); - assert!(serde_json::to_string(&map).is_err()); - assert!(serde_json::to_value(map).is_err()); - - let map = treemap!(F32Bits(f32::NEG_INFINITY.to_bits()) => "x".to_owned()); - assert!(serde_json::to_string(&map).is_err()); - assert!(serde_json::to_value(map).is_err()); - - let map = treemap!(F32Bits(f32::NAN.to_bits()) => "x".to_owned()); - assert!(serde_json::to_string(&map).is_err()); + let map = treemap!(Float => "x"); assert!(serde_json::to_value(map).is_err()); } #[test] -fn test_deny_non_finite_f64_key() { - // We store float bits so that we can derive Ord, and other traits. In a - // real context the code might involve a crate like ordered-float. - - #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)] - struct F64Bits(u64); - impl Serialize for F64Bits { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - serializer.serialize_f64(f64::from_bits(self.0)) - } - } - - let map = treemap!(F64Bits(f64::INFINITY.to_bits()) => "x".to_owned()); - assert!(serde_json::to_string(&map).is_err()); - assert!(serde_json::to_value(map).is_err()); - - let map = treemap!(F64Bits(f64::NEG_INFINITY.to_bits()) => "x".to_owned()); - assert!(serde_json::to_string(&map).is_err()); - assert!(serde_json::to_value(map).is_err()); - - let map = treemap!(F64Bits(f64::NAN.to_bits()) => "x".to_owned()); - assert!(serde_json::to_string(&map).is_err()); - assert!(serde_json::to_value(map).is_err()); -} - -#[test] -fn test_boolean_key() { - let map = treemap!(false => 0, true => 1); - let j = r#"{"false":0,"true":1}"#; - test_encode_ok(&[(&map, j)]); - test_parse_ok(vec![(j, map)]); -} - -#[test] fn test_borrowed_key() { let map: BTreeMap<&str, ()> = from_str("{\"borrowed\":null}").unwrap(); let expected = treemap! { "borrowed" => () }; @@ -2048,7 +1954,7 @@ fn test_effectively_string_keys() { } let map = treemap! { Enum::One => 1, - Enum::Two => 2, + Enum::Two => 2 }; let expected = r#"{"One":1,"Two":2}"#; test_encode_ok(&[(&map, expected)]); @@ -2058,7 +1964,7 @@ fn test_effectively_string_keys() { struct Wrapper(String); let map = treemap! { Wrapper("zero".to_owned()) => 0, - Wrapper("one".to_owned()) => 1, + Wrapper("one".to_owned()) => 1 }; let expected = r#"{"one":1,"zero":0}"#; test_encode_ok(&[(&map, expected)]); @@ -2479,27 +2385,25 @@ fn test_value_into_deserializer() { let mut map = BTreeMap::new(); map.insert("inner", json!({ "string": "Hello World" })); - let outer = Outer::deserialize(serde::de::value::MapDeserializer::new( - map.iter().map(|(k, v)| (*k, v)), - )) - .unwrap(); - assert_eq!(outer.inner.string, "Hello World"); - let outer = Outer::deserialize(map.into_deserializer()).unwrap(); assert_eq!(outer.inner.string, "Hello World"); } #[test] fn hash_positive_and_negative_zero() { - let rand = std::hash::RandomState::new(); + fn hash(obj: impl Hash) -> u64 { + let mut hasher = DefaultHasher::new(); + obj.hash(&mut hasher); + hasher.finish() + } let k1 = serde_json::from_str::<Number>("0.0").unwrap(); let k2 = serde_json::from_str::<Number>("-0.0").unwrap(); if cfg!(feature = "arbitrary_precision") { assert_ne!(k1, k2); - assert_ne!(rand.hash_one(k1), rand.hash_one(k2)); + assert_ne!(hash(k1), hash(k2)); } else { assert_eq!(k1, k2); - assert_eq!(rand.hash_one(k1), rand.hash_one(k2)); + assert_eq!(hash(k1), hash(k2)); } } diff --git a/tests/ui/parse_key.stderr b/tests/ui/parse_key.stderr index 15662dc..f10c218 100644 --- a/tests/ui/parse_key.stderr +++ b/tests/ui/parse_key.stderr @@ -2,4 +2,4 @@ error[E0609]: no field `s` on type `&'static str` --> tests/ui/parse_key.rs:4:16 | 4 | json!({ "".s : true }); - | ^ unknown field + | ^ |