No bug - Upgrade serde_json to 1.0.140, r=supply-chain-reviewers

I'm need to bring in a new version for an upcoming UniFFI upgrade.

Differential Revision: https://phabricator.services.mozilla.com/D247387
This commit is contained in:
Ben Dean-Kawamura
2025-05-02 13:24:41 +00:00
committed by bdeankawamura@mozilla.com
parent 7a6fcba5cc
commit fb372f016e
43 changed files with 1730 additions and 731 deletions

5
Cargo.lock generated
View File

@@ -5998,12 +5998,13 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.116"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"indexmap",
"itoa",
"memchr",
"ryu",
"serde",
]

View File

@@ -6802,7 +6802,7 @@ end = "2025-05-31"
criteria = "safe-to-deploy"
user-id = 3618 # David Tolnay (dtolnay)
start = "2019-02-28"
end = "2024-04-25"
end = "2026-04-30"
[[trusted.serde_repr]]
criteria = "safe-to-deploy"

View File

@@ -606,8 +606,8 @@ user-login = "dtolnay"
user-name = "David Tolnay"
[[publisher.serde_json]]
version = "1.0.116"
when = "2024-04-16"
version = "1.0.140"
when = "2025-03-03"
user-id = 3618
user-login = "dtolnay"
user-name = "David Tolnay"

File diff suppressed because one or more lines are too long

417
third_party/rust/serde_json/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,417 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "automod"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edf3ee19dbc0a46d740f6f0926bde8c50f02bdbc7b536842da28f6ac56513a8b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "cc"
version = "1.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "dissimilar"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "indexmap"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "indoc"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
[[package]]
name = "itoa"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "libc"
version = "0.2.170"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "psm"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88"
dependencies = [
"cc",
]
[[package]]
name = "quote"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ref-cast"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "rustversion"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
[[package]]
name = "ryu"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
[[package]]
name = "serde"
version = "1.0.218"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_bytes"
version = "0.11.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "364fec0df39c49a083c9a8a18a23a6bcfd9af130fe9fe321d18520a0d113e09e"
dependencies = [
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.218"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "serde_json"
version = "1.0.140"
dependencies = [
"automod",
"indexmap",
"indoc",
"itoa",
"memchr",
"ref-cast",
"rustversion",
"ryu",
"serde",
"serde_bytes",
"serde_derive",
"serde_stacker",
"trybuild",
]
[[package]]
name = "serde_spanned"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
dependencies = [
"serde",
]
[[package]]
name = "serde_stacker"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69c8defe6c780725cce4ec6ad3bd91e321baf6fa4e255df1f31e345d507ef01a"
dependencies = [
"serde",
"stacker",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "stacker"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9156ebd5870ef293bfb43f91c7a74528d363ec0d424afe24160ed5a4343d08a"
dependencies = [
"cc",
"cfg-if",
"libc",
"psm",
"windows-sys",
]
[[package]]
name = "syn"
version = "2.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "target-triple"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790"
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "toml"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "trybuild"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b812699e0c4f813b872b373a4471717d9eb550da14b311058a4d9cf4173cbca6"
dependencies = [
"dissimilar",
"glob",
"serde",
"serde_derive",
"serde_json 1.0.139",
"target-triple",
"termcolor",
"toml",
]
[[package]]
name = "unicode-ident"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1"
dependencies = [
"memchr",
]

View File

@@ -13,11 +13,17 @@
edition = "2021"
rust-version = "1.56"
name = "serde_json"
version = "1.0.116"
version = "1.0.140"
authors = [
"Erick Tryzelaar <erick.tryzelaar@gmail.com>",
"David Tolnay <dtolnay@gmail.com>",
]
build = "build.rs"
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "A JSON serialization file format"
documentation = "https://docs.rs/serde_json"
readme = "README.md"
@@ -41,25 +47,79 @@ features = [
"unbounded_depth",
]
rustdoc-args = [
"--cfg",
"docsrs",
"--generate-link-to-definition",
"--extern-html-root-url=core=https://doc.rust-lang.org",
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
"--extern-html-root-url=std=https://doc.rust-lang.org",
]
targets = ["x86_64-unknown-linux-gnu"]
[package.metadata.playground]
features = ["raw_value"]
features = [
"float_roundtrip",
"raw_value",
"unbounded_depth",
]
[features]
alloc = ["serde/alloc"]
arbitrary_precision = []
default = ["std"]
float_roundtrip = []
preserve_order = [
"indexmap",
"std",
]
raw_value = []
std = [
"memchr/std",
"serde/std",
]
unbounded_depth = []
[lib]
doc-scrape-examples = false
name = "serde_json"
path = "src/lib.rs"
[[test]]
name = "compiletest"
path = "tests/compiletest.rs"
[[test]]
name = "debug"
path = "tests/debug.rs"
[[test]]
name = "lexical"
path = "tests/lexical.rs"
[[test]]
name = "map"
path = "tests/map.rs"
[[test]]
name = "regression"
path = "tests/regression.rs"
[[test]]
name = "stream"
path = "tests/stream.rs"
[[test]]
name = "test"
path = "tests/test.rs"
[dependencies.indexmap]
version = "2.2.1"
version = "2.2.3"
optional = true
[dependencies.itoa]
version = "1.0"
[dependencies.memchr]
version = "2"
default-features = false
[dependencies.ryu]
version = "1.0"
@@ -95,16 +155,3 @@ version = "0.1.8"
[dev-dependencies.trybuild]
version = "1.0.81"
features = ["diff"]
[features]
alloc = ["serde/alloc"]
arbitrary_precision = []
default = ["std"]
float_roundtrip = []
preserve_order = [
"indexmap",
"std",
]
raw_value = []
std = ["serde/std"]
unbounded_depth = []

View File

@@ -3,15 +3,27 @@ use std::env;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
// Decide ideal limb width for arithmetic in the float parser. Refer to
// 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" => {
println!("cargo:rustc-cfg=limb_width_64");
}
_ => {
println!("cargo:rustc-cfg=limb_width_32");
}
println!("cargo:rustc-check-cfg=cfg(fast_arithmetic, values(\"32\", \"64\"))");
// Decide ideal limb width for arithmetic in the float parser and string
// parser.
let target_arch = env::var_os("CARGO_CFG_TARGET_ARCH").unwrap();
let target_pointer_width = env::var_os("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap();
if target_arch == "aarch64"
|| target_arch == "loongarch64"
|| target_arch == "mips64"
|| target_arch == "powerpc64"
|| target_arch == "wasm32"
|| target_arch == "x86_64"
|| target_pointer_width == "64"
{
// The above list of architectures are ones that have native support for
// 64-bit arithmetic, but which have some targets using a smaller
// pointer width. Examples include aarch64-unknown-linux-gnu_ilp32 and
// x86_64-unknown-linux-gnux32. So our choice of limb width is not
// equivalent to using usize everywhere.
println!("cargo:rustc-cfg=fast_arithmetic=\"64\"");
} else {
println!("cargo:rustc-cfg=fast_arithmetic=\"32\"");
}
}

View File

@@ -45,11 +45,17 @@ where
/// Create a JSON deserializer from one of the possible serde_json input
/// sources.
///
/// When reading from a source against which short reads are not efficient, such
/// as a [`File`], you will want to apply your own buffering because serde_json
/// will not buffer the input. See [`std::io::BufReader`].
///
/// Typically it is more convenient to use one of these methods instead:
///
/// - Deserializer::from_str
/// - Deserializer::from_slice
/// - Deserializer::from_reader
///
/// [`File`]: std::fs::File
pub fn new(read: R) -> Self {
Deserializer {
read,
@@ -362,7 +368,7 @@ impl<'de, R: Read<'de>> Deserializer<R> {
None => {
return Err(self.peek_error(ErrorCode::EofWhileParsingValue));
}
};
}
tri!(self.scan_integer128(&mut buf));
@@ -1378,7 +1384,7 @@ macro_rules! check_recursion {
};
}
impl<'de, 'a, R: Read<'de>> de::Deserializer<'de> for &'a mut Deserializer<R> {
impl<'de, R: Read<'de>> de::Deserializer<'de> for &mut Deserializer<R> {
type Error = Error;
#[inline]
@@ -1575,7 +1581,10 @@ impl<'de, 'a, R: Read<'de>> de::Deserializer<'de> for &'a mut Deserializer<R> {
///
/// The behavior of serde_json is specified to fail on non-UTF-8 strings
/// when deserializing into Rust UTF-8 string types such as String, and
/// succeed with non-UTF-8 bytes when deserializing using this method.
/// succeed with the bytes representing the [WTF-8] encoding of code points
/// when deserializing using this method.
///
/// [WTF-8]: https://simonsapin.github.io/wtf-8
///
/// Escape sequences are processed as usual, and for `\uXXXX` escapes it is
/// still checked if the hex number represents a valid Unicode code point.
@@ -1870,8 +1879,9 @@ impl<'de, 'a, R: Read<'de>> de::Deserializer<'de> for &'a mut Deserializer<R> {
Some(b'{') => {
check_recursion! {
self.eat_char();
let value = tri!(visitor.visit_enum(VariantAccess::new(self)));
let ret = visitor.visit_enum(VariantAccess::new(self));
}
let value = tri!(ret);
match tri!(self.parse_whitespace()) {
Some(b'}') => {
@@ -1922,31 +1932,37 @@ impl<'de, 'a, R: Read<'de> + 'a> de::SeqAccess<'de> for SeqAccess<'a, R> {
where
T: de::DeserializeSeed<'de>,
{
let peek = match tri!(self.de.parse_whitespace()) {
Some(b']') => {
return Ok(None);
}
Some(b',') if !self.first => {
self.de.eat_char();
tri!(self.de.parse_whitespace())
}
Some(b) => {
if self.first {
self.first = false;
Some(b)
} else {
return Err(self.de.peek_error(ErrorCode::ExpectedListCommaOrEnd));
}
}
fn has_next_element<'de, 'a, R: Read<'de> + 'a>(
seq: &mut SeqAccess<'a, R>,
) -> Result<bool> {
let peek = match tri!(seq.de.parse_whitespace()) {
Some(b) => b,
None => {
return Err(self.de.peek_error(ErrorCode::EofWhileParsingList));
return Err(seq.de.peek_error(ErrorCode::EofWhileParsingList));
}
};
match peek {
Some(b']') => Err(self.de.peek_error(ErrorCode::TrailingComma)),
Some(_) => Ok(Some(tri!(seed.deserialize(&mut *self.de)))),
None => Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)),
if peek == b']' {
Ok(false)
} else if seq.first {
seq.first = false;
Ok(true)
} else if peek == b',' {
seq.de.eat_char();
match tri!(seq.de.parse_whitespace()) {
Some(b']') => Err(seq.de.peek_error(ErrorCode::TrailingComma)),
Some(_) => Ok(true),
None => Err(seq.de.peek_error(ErrorCode::EofWhileParsingValue)),
}
} else {
Err(seq.de.peek_error(ErrorCode::ExpectedListCommaOrEnd))
}
}
if tri!(has_next_element(self)) {
Ok(Some(tri!(seed.deserialize(&mut *self.de))))
} else {
Ok(None)
}
}
}
@@ -1969,32 +1985,40 @@ impl<'de, 'a, R: Read<'de> + 'a> de::MapAccess<'de> for MapAccess<'a, R> {
where
K: de::DeserializeSeed<'de>,
{
let peek = match tri!(self.de.parse_whitespace()) {
Some(b'}') => {
return Ok(None);
}
Some(b',') if !self.first => {
self.de.eat_char();
tri!(self.de.parse_whitespace())
}
Some(b) => {
if self.first {
self.first = false;
Some(b)
} else {
return Err(self.de.peek_error(ErrorCode::ExpectedObjectCommaOrEnd));
}
}
fn has_next_key<'de, 'a, R: Read<'de> + 'a>(map: &mut MapAccess<'a, R>) -> Result<bool> {
let peek = match tri!(map.de.parse_whitespace()) {
Some(b) => b,
None => {
return Err(self.de.peek_error(ErrorCode::EofWhileParsingObject));
return Err(map.de.peek_error(ErrorCode::EofWhileParsingObject));
}
};
match peek {
Some(b'"') => seed.deserialize(MapKey { de: &mut *self.de }).map(Some),
Some(b'}') => Err(self.de.peek_error(ErrorCode::TrailingComma)),
Some(_) => Err(self.de.peek_error(ErrorCode::KeyMustBeAString)),
None => Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)),
if peek == b'}' {
Ok(false)
} else if map.first {
map.first = false;
if peek == b'"' {
Ok(true)
} else {
Err(map.de.peek_error(ErrorCode::KeyMustBeAString))
}
} else if peek == b',' {
map.de.eat_char();
match tri!(map.de.parse_whitespace()) {
Some(b'"') => Ok(true),
Some(b'}') => Err(map.de.peek_error(ErrorCode::TrailingComma)),
Some(_) => Err(map.de.peek_error(ErrorCode::KeyMustBeAString)),
None => Err(map.de.peek_error(ErrorCode::EofWhileParsingValue)),
}
} else {
Err(map.de.peek_error(ErrorCode::ExpectedObjectCommaOrEnd))
}
}
if tri!(has_next_key(self)) {
Ok(Some(tri!(seed.deserialize(MapKey { de: &mut *self.de }))))
} else {
Ok(None)
}
}
@@ -2499,10 +2523,7 @@ where
/// reading a file completely into memory and then applying [`from_str`]
/// or [`from_slice`] on it. See [issue #160].
///
/// [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html
/// [`std::io::BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html
/// [`from_str`]: ./fn.from_str.html
/// [`from_slice`]: ./fn.from_slice.html
/// [`File`]: std::fs::File
/// [issue #160]: https://github.com/serde-rs/json/issues/160
///
/// # Example
@@ -2549,6 +2570,7 @@ where
/// use serde::Deserialize;
///
/// use std::error::Error;
/// use std::io::BufReader;
/// use std::net::{TcpListener, TcpStream};
///
/// #[derive(Deserialize, Debug)]
@@ -2557,8 +2579,8 @@ where
/// location: String,
/// }
///
/// fn read_user_from_stream(tcp_stream: TcpStream) -> Result<User, Box<dyn Error>> {
/// let mut de = serde_json::Deserializer::from_reader(tcp_stream);
/// fn read_user_from_stream(stream: &mut BufReader<TcpStream>) -> Result<User, Box<dyn Error>> {
/// let mut de = serde_json::Deserializer::from_reader(stream);
/// let u = User::deserialize(&mut de)?;
///
/// Ok(u)
@@ -2569,8 +2591,9 @@ where
/// # fn fake_main() {
/// let listener = TcpListener::bind("127.0.0.1:4000").unwrap();
///
/// for stream in listener.incoming() {
/// println!("{:#?}", read_user_from_stream(stream.unwrap()));
/// for tcp_stream in listener.incoming() {
/// let mut buffered = BufReader::new(tcp_stream.unwrap());
/// println!("{:#?}", read_user_from_stream(&mut buffered));
/// }
/// }
/// ```

View File

@@ -75,13 +75,13 @@ where
// FLOAT OPS
/// Calculate `b` from a a representation of `b` as a float.
/// Calculate `b` from a representation of `b` as a float.
#[inline]
pub(super) fn b_extended<F: Float>(f: F) -> ExtendedFloat {
ExtendedFloat::from_float(f)
}
/// Calculate `b+h` from a a representation of `b` as a float.
/// Calculate `b+h` from a representation of `b` as a float.
#[inline]
pub(super) fn bh_extended<F: Float>(f: F) -> ExtendedFloat {
// None of these can overflow.

View File

@@ -2,8 +2,8 @@
//! Precalculated large powers for limbs.
#[cfg(limb_width_32)]
#[cfg(fast_arithmetic = "32")]
pub(crate) use super::large_powers32::*;
#[cfg(limb_width_64)]
#[cfg(fast_arithmetic = "64")]
pub(crate) use super::large_powers64::*;

View File

@@ -37,29 +37,29 @@ use core::{cmp, iter, mem};
// sparc64 (`UMUL` only supported double-word arguments).
// 32-BIT LIMB
#[cfg(limb_width_32)]
#[cfg(fast_arithmetic = "32")]
pub type Limb = u32;
#[cfg(limb_width_32)]
#[cfg(fast_arithmetic = "32")]
pub const POW5_LIMB: &[Limb] = &POW5_32;
#[cfg(limb_width_32)]
#[cfg(fast_arithmetic = "32")]
pub const POW10_LIMB: &[Limb] = &POW10_32;
#[cfg(limb_width_32)]
#[cfg(fast_arithmetic = "32")]
type Wide = u64;
// 64-BIT LIMB
#[cfg(limb_width_64)]
#[cfg(fast_arithmetic = "64")]
pub type Limb = u64;
#[cfg(limb_width_64)]
#[cfg(fast_arithmetic = "64")]
pub const POW5_LIMB: &[Limb] = &POW5_64;
#[cfg(limb_width_64)]
#[cfg(fast_arithmetic = "64")]
pub const POW10_LIMB: &[Limb] = &POW10_64;
#[cfg(limb_width_64)]
#[cfg(fast_arithmetic = "64")]
type Wide = u128;
/// Cast to limb type.
@@ -79,14 +79,14 @@ fn as_wide<T: Integer>(t: T) -> Wide {
/// Split u64 into limbs, in little-endian order.
#[inline]
#[cfg(limb_width_32)]
#[cfg(fast_arithmetic = "32")]
fn split_u64(x: u64) -> [Limb; 2] {
[as_limb(x), as_limb(x >> 32)]
}
/// Split u64 into limbs, in little-endian order.
#[inline]
#[cfg(limb_width_64)]
#[cfg(fast_arithmetic = "64")]
fn split_u64(x: u64) -> [Limb; 1] {
[as_limb(x)]
}
@@ -272,9 +272,7 @@ mod scalar {
mod small {
use super::*;
// MULTIPLICATIION
/// ADDITION
// ADDITION
/// Implied AddAssign implementation for adding a small integer to bigint.
///

View File

@@ -28,10 +28,10 @@ pub(crate) mod rounding;
mod shift;
mod small_powers;
#[cfg(limb_width_32)]
#[cfg(fast_arithmetic = "32")]
mod large_powers32;
#[cfg(limb_width_64)]
#[cfg(fast_arithmetic = "64")]
mod large_powers64;
// API

View File

@@ -206,8 +206,6 @@ pub trait Float: Number {
// MASKS
/// Bitmask for the sign bit.
const SIGN_MASK: Self::Unsigned;
/// Bitmask for the exponent, including the hidden bit.
const EXPONENT_MASK: Self::Unsigned;
/// Bitmask for the hidden bit in exponent, which is an implicit 1 in the fraction.
@@ -219,8 +217,6 @@ pub trait Float: Number {
/// Positive infinity as bits.
const INFINITY_BITS: Self::Unsigned;
/// Positive infinity as bits.
const NEGATIVE_INFINITY_BITS: Self::Unsigned;
/// Size of the significand (mantissa) without hidden bit.
const MANTISSA_SIZE: i32;
/// Bias of the exponent
@@ -315,12 +311,10 @@ impl Float for f32 {
const ZERO: f32 = 0.0;
const MAX_DIGITS: usize = 114;
const SIGN_MASK: u32 = 0x80000000;
const EXPONENT_MASK: u32 = 0x7F800000;
const HIDDEN_BIT_MASK: u32 = 0x00800000;
const MANTISSA_MASK: u32 = 0x007FFFFF;
const INFINITY_BITS: u32 = 0x7F800000;
const NEGATIVE_INFINITY_BITS: u32 = Self::INFINITY_BITS | Self::SIGN_MASK;
const MANTISSA_SIZE: i32 = 23;
const EXPONENT_BIAS: i32 = 127 + Self::MANTISSA_SIZE;
const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS;
@@ -374,12 +368,10 @@ impl Float for f64 {
const ZERO: f64 = 0.0;
const MAX_DIGITS: usize = 769;
const SIGN_MASK: u64 = 0x8000000000000000;
const EXPONENT_MASK: u64 = 0x7FF0000000000000;
const HIDDEN_BIT_MASK: u64 = 0x0010000000000000;
const MANTISSA_MASK: u64 = 0x000FFFFFFFFFFFFF;
const INFINITY_BITS: u64 = 0x7FF0000000000000;
const NEGATIVE_INFINITY_BITS: u64 = Self::INFINITY_BITS | Self::SIGN_MASK;
const MANTISSA_SIZE: i32 = 52;
const EXPONENT_BIAS: i32 = 1023 + Self::MANTISSA_SIZE;
const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS;

View File

@@ -3,19 +3,19 @@
//! Pre-computed small powers.
// 32 BIT
#[cfg(limb_width_32)]
#[cfg(fast_arithmetic = "32")]
pub(crate) const POW5_32: [u32; 14] = [
1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625,
1220703125,
];
#[cfg(limb_width_32)]
#[cfg(fast_arithmetic = "32")]
pub(crate) const POW10_32: [u32; 10] = [
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
];
// 64 BIT
#[cfg(limb_width_64)]
#[cfg(fast_arithmetic = "64")]
pub(crate) const POW5_64: [u64; 28] = [
1,
5,

View File

@@ -299,13 +299,14 @@
//! [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.116")]
#![doc(html_root_url = "https://docs.rs/serde_json/1.0.140")]
// Ignored clippy lints
#![allow(
clippy::collapsible_else_if,
clippy::comparison_chain,
clippy::deprecated_cfg_attr,
clippy::doc_markdown,
clippy::elidable_lifetime_names,
clippy::excessive_precision,
clippy::explicit_auto_deref,
clippy::float_cmp,
@@ -314,8 +315,10 @@
clippy::match_single_binding,
clippy::needless_doctest_main,
clippy::needless_late_init,
clippy::needless_lifetimes,
clippy::return_self_not_must_use,
clippy::transmute_ptr_to_ptr,
clippy::unbuffered_bytes,
clippy::unconditional_recursion, // https://github.com/rust-lang/rust-clippy/issues/12133
clippy::unnecessary_wraps
)]
@@ -340,6 +343,7 @@
clippy::wildcard_imports,
// things are often more readable this way
clippy::cast_lossless,
clippy::items_after_statements,
clippy::module_name_repetitions,
clippy::redundant_else,
clippy::shadow_unrelated,
@@ -373,6 +377,13 @@ extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
// Not public API. Used from macro-generated code.
#[doc(hidden)]
pub mod __private {
#[doc(hidden)]
pub use alloc::vec;
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[doc(inline)]

View File

@@ -50,11 +50,11 @@
/// "comma -->",
/// ]);
/// ```
#[macro_export(local_inner_macros)]
#[macro_export]
macro_rules! json {
// Hide distracting implementation details from the generated rustdoc.
($($json:tt)+) => {
json_internal!($($json)+)
$crate::json_internal!($($json)+)
};
}
@@ -65,7 +65,7 @@ macro_rules! json {
//
// Changes are fine as long as `json_internal!` does not call any new helper
// macros and can still be invoked as `json_internal!($($json)+)`.
#[macro_export(local_inner_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! json_internal {
//////////////////////////////////////////////////////////////////////////
@@ -77,57 +77,57 @@ macro_rules! json_internal {
// Done with trailing comma.
(@array [$($elems:expr,)*]) => {
json_internal_vec![$($elems,)*]
$crate::__private::vec![$($elems,)*]
};
// Done without trailing comma.
(@array [$($elems:expr),*]) => {
json_internal_vec![$($elems),*]
$crate::__private::vec![$($elems),*]
};
// Next element is `null`.
(@array [$($elems:expr,)*] null $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*)
$crate::json_internal!(@array [$($elems,)* $crate::json_internal!(null)] $($rest)*)
};
// Next element is `true`.
(@array [$($elems:expr,)*] true $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*)
$crate::json_internal!(@array [$($elems,)* $crate::json_internal!(true)] $($rest)*)
};
// Next element is `false`.
(@array [$($elems:expr,)*] false $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*)
$crate::json_internal!(@array [$($elems,)* $crate::json_internal!(false)] $($rest)*)
};
// Next element is an array.
(@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*)
$crate::json_internal!(@array [$($elems,)* $crate::json_internal!([$($array)*])] $($rest)*)
};
// Next element is a map.
(@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*)
$crate::json_internal!(@array [$($elems,)* $crate::json_internal!({$($map)*})] $($rest)*)
};
// Next element is an expression followed by comma.
(@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*)
$crate::json_internal!(@array [$($elems,)* $crate::json_internal!($next),] $($rest)*)
};
// Last element is an expression with no trailing comma.
(@array [$($elems:expr,)*] $last:expr) => {
json_internal!(@array [$($elems,)* json_internal!($last)])
$crate::json_internal!(@array [$($elems,)* $crate::json_internal!($last)])
};
// Comma after the most recent element.
(@array [$($elems:expr),*] , $($rest:tt)*) => {
json_internal!(@array [$($elems,)*] $($rest)*)
$crate::json_internal!(@array [$($elems,)*] $($rest)*)
};
// Unexpected token after most recent element.
(@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => {
json_unexpected!($unexpected)
$crate::json_unexpected!($unexpected)
};
//////////////////////////////////////////////////////////////////////////
@@ -146,12 +146,12 @@ macro_rules! json_internal {
// Insert the current entry followed by trailing comma.
(@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
let _ = $object.insert(($($key)+).into(), $value);
json_internal!(@object $object () ($($rest)*) ($($rest)*));
$crate::json_internal!(@object $object () ($($rest)*) ($($rest)*));
};
// Current entry followed by unexpected token.
(@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => {
json_unexpected!($unexpected);
$crate::json_unexpected!($unexpected);
};
// Insert the last entry without trailing comma.
@@ -161,78 +161,78 @@ macro_rules! json_internal {
// Next value is `null`.
(@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*);
$crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!(null)) $($rest)*);
};
// Next value is `true`.
(@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*);
$crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!(true)) $($rest)*);
};
// Next value is `false`.
(@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*);
$crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!(false)) $($rest)*);
};
// Next value is an array.
(@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*);
$crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!([$($array)*])) $($rest)*);
};
// Next value is a map.
(@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*);
$crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!({$($map)*})) $($rest)*);
};
// Next value is an expression followed by comma.
(@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*);
$crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!($value)) , $($rest)*);
};
// Last value is an expression with no trailing comma.
(@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!($value)));
$crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!($value)));
};
// Missing value for last entry. Trigger a reasonable error message.
(@object $object:ident ($($key:tt)+) (:) $copy:tt) => {
// "unexpected end of macro invocation"
json_internal!();
$crate::json_internal!();
};
// Missing colon and value for last entry. Trigger a reasonable error
// message.
(@object $object:ident ($($key:tt)+) () $copy:tt) => {
// "unexpected end of macro invocation"
json_internal!();
$crate::json_internal!();
};
// Misplaced colon. Trigger a reasonable error message.
(@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => {
// Takes no arguments so "no rules expected the token `:`".
json_unexpected!($colon);
$crate::json_unexpected!($colon);
};
// Found a comma inside a key. Trigger a reasonable error message.
(@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
// Takes no arguments so "no rules expected the token `,`".
json_unexpected!($comma);
$crate::json_unexpected!($comma);
};
// Key is fully parenthesized. This avoids clippy double_parens false
// positives because the parenthesization may be necessary here.
(@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*));
$crate::json_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*));
};
// Refuse to absorb colon token into key expression.
(@object $object:ident ($($key:tt)*) (: $($unexpected:tt)+) $copy:tt) => {
json_expect_expr_comma!($($unexpected)+);
$crate::json_expect_expr_comma!($($unexpected)+);
};
// Munch a token into the current key.
(@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*));
$crate::json_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*));
};
//////////////////////////////////////////////////////////////////////////
@@ -254,11 +254,11 @@ macro_rules! json_internal {
};
([]) => {
$crate::Value::Array(json_internal_vec![])
$crate::Value::Array($crate::__private::vec![])
};
([ $($tt:tt)+ ]) => {
$crate::Value::Array(json_internal!(@array [] $($tt)+))
$crate::Value::Array($crate::json_internal!(@array [] $($tt)+))
};
({}) => {
@@ -268,7 +268,7 @@ macro_rules! json_internal {
({ $($tt:tt)+ }) => {
$crate::Value::Object({
let mut object = $crate::Map::new();
json_internal!(@object object () ($($tt)+) ($($tt)+));
$crate::json_internal!(@object object () ($($tt)+) ($($tt)+));
object
})
};
@@ -280,9 +280,8 @@ macro_rules! json_internal {
};
}
// The json_internal macro above cannot invoke vec directly because it uses
// local_inner_macros. A vec invocation there would resolve to $crate::vec.
// Instead invoke vec here outside of local_inner_macros.
// Used by old versions of Rocket.
// Unused since https://github.com/rwf2/Rocket/commit/c74bcfd40a47b35330db6cafb88e4f3da83e0d17
#[macro_export]
#[doc(hidden)]
macro_rules! json_internal_vec {

View File

@@ -3,14 +3,17 @@
//! By default the map is backed by a [`BTreeMap`]. Enable the `preserve_order`
//! feature of serde_json to use [`IndexMap`] instead.
//!
//! [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html
//! [`IndexMap`]: https://docs.rs/indexmap/*/indexmap/map/struct.IndexMap.html
//! [`BTreeMap`]: std::collections::BTreeMap
//! [`IndexMap`]: indexmap::IndexMap
use crate::error::Error;
use crate::value::Value;
use alloc::string::String;
#[cfg(feature = "preserve_order")]
use alloc::vec::Vec;
use core::borrow::Borrow;
use core::fmt::{self, Debug};
use core::hash::Hash;
use core::hash::{Hash, Hasher};
use core::iter::FusedIterator;
#[cfg(feature = "preserve_order")]
use core::mem;
@@ -125,6 +128,19 @@ impl Map<String, Value> {
self.map.insert(k, v)
}
/// Insert a key-value pair in the map at the given index.
///
/// If the map did not have this key present, `None` is returned.
///
/// If the map did have this key present, the key is moved to the new
/// position, the value is updated, and the old value is returned.
#[cfg(feature = "preserve_order")]
#[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))]
#[inline]
pub fn shift_insert(&mut self, index: usize, k: String, v: Value) -> Option<Value> {
self.map.shift_insert(index, k, v)
}
/// Removes a key from the map, returning the value at the key if the key
/// was previously in the map.
///
@@ -322,6 +338,14 @@ impl Map<String, Value> {
}
}
/// Gets an iterator over the values of the map.
#[inline]
pub fn into_values(self) -> IntoValues {
IntoValues {
iter: self.map.into_values(),
}
}
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)`
@@ -333,6 +357,29 @@ impl Map<String, Value> {
{
self.map.retain(f);
}
/// Sorts this map's entries in-place using `str`'s usual ordering.
///
/// If serde_json's "preserve_order" feature is not enabled, this method
/// does no work because all JSON maps are always kept in a sorted state.
///
/// If serde_json's "preserve_order" feature is enabled, this method
/// destroys the original source order or insertion order of this map in
/// favor of an alphanumerical order that matches how a BTreeMap with the
/// same contents would be ordered. This takes **O(n log n + c)** time where
/// _n_ is the length of the map and _c_ is the capacity.
///
/// Other maps nested within the values of this map are not sorted. If you
/// need the entire data structure to be sorted at all levels, you must also
/// call
/// <code>map.[values_mut]\().for_each([Value::sort_all_objects])</code>.
///
/// [values_mut]: Map::values_mut
#[inline]
pub fn sort_keys(&mut self) {
#[cfg(feature = "preserve_order")]
self.map.sort_unstable_keys();
}
}
#[allow(clippy::derivable_impls)] // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7655
@@ -368,6 +415,22 @@ impl PartialEq for Map<String, Value> {
impl Eq for Map<String, Value> {}
impl Hash for Map<String, Value> {
fn hash<H: Hasher>(&self, state: &mut H) {
#[cfg(not(feature = "preserve_order"))]
{
self.map.hash(state);
}
#[cfg(feature = "preserve_order")]
{
let mut kv = Vec::from_iter(&self.map);
kv.sort_unstable_by(|a, b| a.0.cmp(b.0));
kv.hash(state);
}
}
}
/// Access an element of this map. Panics if the given key is not present in the
/// map.
///
@@ -384,7 +447,7 @@ impl Eq for Map<String, Value> {}
/// }
/// # ;
/// ```
impl<'a, Q> ops::Index<&'a Q> for Map<String, Value>
impl<Q> ops::Index<&Q> for Map<String, Value>
where
String: Borrow<Q>,
Q: ?Sized + Ord + Eq + Hash,
@@ -407,7 +470,7 @@ where
/// #
/// map["key"] = json!("value");
/// ```
impl<'a, Q> ops::IndexMut<&'a Q> for Map<String, Value>
impl<Q> ops::IndexMut<&Q> for Map<String, Value>
where
String: Borrow<Q>,
Q: ?Sized + Ord + Eq + Hash,
@@ -535,13 +598,28 @@ macro_rules! delegate_iterator {
}
}
impl<'de> de::IntoDeserializer<'de, Error> for Map<String, Value> {
type Deserializer = Self;
fn into_deserializer(self) -> Self::Deserializer {
self
}
}
impl<'de> de::IntoDeserializer<'de, Error> for &'de Map<String, Value> {
type Deserializer = Self;
fn into_deserializer(self) -> Self::Deserializer {
self
}
}
//////////////////////////////////////////////////////////////////////////////
/// A view into a single entry in a map, which may either be vacant or occupied.
/// This enum is constructed from the [`entry`] method on [`Map`].
///
/// [`entry`]: struct.Map.html#method.entry
/// [`Map`]: struct.Map.html
/// [`entry`]: Map::entry
pub enum Entry<'a> {
/// A vacant Entry.
Vacant(VacantEntry<'a>),
@@ -550,15 +628,11 @@ pub enum Entry<'a> {
}
/// A vacant Entry. It is part of the [`Entry`] enum.
///
/// [`Entry`]: enum.Entry.html
pub struct VacantEntry<'a> {
vacant: VacantEntryImpl<'a>,
}
/// An occupied Entry. It is part of the [`Entry`] enum.
///
/// [`Entry`]: enum.Entry.html
pub struct OccupiedEntry<'a> {
occupied: OccupiedEntryImpl<'a>,
}
@@ -845,6 +919,12 @@ impl<'a> OccupiedEntry<'a> {
/// Takes the value of the entry out of the map, and returns it.
///
/// If serde_json's "preserve_order" is enabled, `.remove()` is
/// equivalent to [`.swap_remove()`][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()`][Self::shift_remove] instead.
///
/// # Examples
///
/// ```
@@ -865,10 +945,101 @@ impl<'a> OccupiedEntry<'a> {
#[inline]
pub fn remove(self) -> Value {
#[cfg(feature = "preserve_order")]
return self.occupied.swap_remove();
return self.swap_remove();
#[cfg(not(feature = "preserve_order"))]
return self.occupied.remove();
}
/// Takes the value of the entry out of the map, and returns it.
///
/// 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!
///
/// [`Vec::swap_remove`]: std::vec::Vec::swap_remove
#[cfg(feature = "preserve_order")]
#[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))]
#[inline]
pub fn swap_remove(self) -> Value {
self.occupied.swap_remove()
}
/// Takes the value of the entry out of the map, and returns it.
///
/// 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!
///
/// [`Vec::remove`]: std::vec::Vec::remove
#[cfg(feature = "preserve_order")]
#[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))]
#[inline]
pub fn shift_remove(self) -> Value {
self.occupied.shift_remove()
}
/// Removes the entry from the map, returning the stored key and value.
///
/// If serde_json's "preserve_order" is enabled, `.remove_entry()` is
/// equivalent to [`.swap_remove_entry()`][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()`][Self::shift_remove_entry] instead.
///
/// # Examples
///
/// ```
/// # use serde_json::json;
/// #
/// use serde_json::map::Entry;
///
/// let mut map = serde_json::Map::new();
/// map.insert("serde".to_owned(), json!(12));
///
/// match map.entry("serde") {
/// Entry::Occupied(occupied) => {
/// let (key, value) = occupied.remove_entry();
/// assert_eq!(key, "serde");
/// assert_eq!(value, 12);
/// }
/// Entry::Vacant(_) => unimplemented!(),
/// }
/// ```
#[inline]
pub fn remove_entry(self) -> (String, Value) {
#[cfg(feature = "preserve_order")]
return self.swap_remove_entry();
#[cfg(not(feature = "preserve_order"))]
return self.occupied.remove_entry();
}
/// Removes the entry from the map, returning the stored key and value.
///
/// 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!
///
/// [`Vec::swap_remove`]: std::vec::Vec::swap_remove
#[cfg(feature = "preserve_order")]
#[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))]
#[inline]
pub fn swap_remove_entry(self) -> (String, Value) {
self.occupied.swap_remove_entry()
}
/// Removes the entry from the map, returning the stored key and value.
///
/// 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!
///
/// [`Vec::remove`]: std::vec::Vec::remove
#[cfg(feature = "preserve_order")]
#[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))]
#[inline]
pub fn shift_remove_entry(self) -> (String, Value) {
self.occupied.shift_remove_entry()
}
}
//////////////////////////////////////////////////////////////////////////////
@@ -987,3 +1158,17 @@ type ValuesMutImpl<'a> = btree_map::ValuesMut<'a, String, Value>;
type ValuesMutImpl<'a> = indexmap::map::ValuesMut<'a, String, Value>;
delegate_iterator!((ValuesMut<'a>) => &'a mut Value);
//////////////////////////////////////////////////////////////////////////////
/// An owning iterator over a serde_json::Map's values.
pub struct IntoValues {
iter: IntoValuesImpl,
}
#[cfg(not(feature = "preserve_order"))]
type IntoValuesImpl = btree_map::IntoValues<String, Value>;
#[cfg(feature = "preserve_order")]
type IntoValuesImpl = indexmap::map::IntoValues<String, Value>;
delegate_iterator!((IntoValues) => Value);

View File

@@ -78,22 +78,6 @@ impl Number {
///
/// For any Number on which `is_i64` returns true, `as_i64` is guaranteed to
/// return the integer value.
///
/// ```
/// # use serde_json::json;
/// #
/// let big = i64::MAX as u64 + 10;
/// let v = json!({ "a": 64, "b": big, "c": 256.0 });
///
/// assert!(v["a"].is_i64());
///
/// // Greater than i64::MAX.
/// assert!(!v["b"].is_i64());
///
/// // Numbers with a decimal point are not considered integers.
/// assert!(!v["c"].is_i64());
/// ```
#[inline]
pub fn is_i64(&self) -> bool {
#[cfg(not(feature = "arbitrary_precision"))]
match self.n {
@@ -109,21 +93,6 @@ impl Number {
///
/// For any Number on which `is_u64` returns true, `as_u64` is guaranteed to
/// return the integer value.
///
/// ```
/// # use serde_json::json;
/// #
/// let v = json!({ "a": 64, "b": -64, "c": 256.0 });
///
/// assert!(v["a"].is_u64());
///
/// // Negative integer.
/// assert!(!v["b"].is_u64());
///
/// // Numbers with a decimal point are not considered integers.
/// assert!(!v["c"].is_u64());
/// ```
#[inline]
pub fn is_u64(&self) -> bool {
#[cfg(not(feature = "arbitrary_precision"))]
match self.n {
@@ -141,19 +110,6 @@ impl Number {
///
/// Currently this function returns true if and only if both `is_i64` and
/// `is_u64` return false but this is not a guarantee in the future.
///
/// ```
/// # use serde_json::json;
/// #
/// let v = json!({ "a": 256.0, "b": 64, "c": -64 });
///
/// assert!(v["a"].is_f64());
///
/// // Integers.
/// assert!(!v["b"].is_f64());
/// assert!(!v["c"].is_f64());
/// ```
#[inline]
pub fn is_f64(&self) -> bool {
#[cfg(not(feature = "arbitrary_precision"))]
match self.n {
@@ -173,18 +129,6 @@ impl Number {
/// If the `Number` is an integer, represent it as i64 if possible. Returns
/// None otherwise.
///
/// ```
/// # use serde_json::json;
/// #
/// let big = i64::MAX as u64 + 10;
/// let v = json!({ "a": 64, "b": big, "c": 256.0 });
///
/// assert_eq!(v["a"].as_i64(), Some(64));
/// assert_eq!(v["b"].as_i64(), None);
/// assert_eq!(v["c"].as_i64(), None);
/// ```
#[inline]
pub fn as_i64(&self) -> Option<i64> {
#[cfg(not(feature = "arbitrary_precision"))]
match self.n {
@@ -204,17 +148,6 @@ impl Number {
/// If the `Number` is an integer, represent it as u64 if possible. Returns
/// None otherwise.
///
/// ```
/// # use serde_json::json;
/// #
/// let v = json!({ "a": 64, "b": -64, "c": 256.0 });
///
/// assert_eq!(v["a"].as_u64(), Some(64));
/// assert_eq!(v["b"].as_u64(), None);
/// assert_eq!(v["c"].as_u64(), None);
/// ```
#[inline]
pub fn as_u64(&self) -> Option<u64> {
#[cfg(not(feature = "arbitrary_precision"))]
match self.n {
@@ -226,17 +159,6 @@ impl Number {
}
/// Represents the number as f64 if possible. Returns None otherwise.
///
/// ```
/// # use serde_json::json;
/// #
/// let v = json!({ "a": 256.0, "b": 64, "c": -64 });
///
/// assert_eq!(v["a"].as_f64(), Some(256.0));
/// assert_eq!(v["b"].as_f64(), Some(64.0));
/// assert_eq!(v["c"].as_f64(), Some(-64.0));
/// ```
#[inline]
pub fn as_f64(&self) -> Option<f64> {
#[cfg(not(feature = "arbitrary_precision"))]
match self.n {
@@ -252,15 +174,12 @@ impl Number {
/// numbers.
///
/// ```
/// # use std::f64;
/// #
/// # use serde_json::Number;
/// #
/// assert!(Number::from_f64(256.0).is_some());
///
/// assert!(Number::from_f64(f64::NAN).is_none());
/// ```
#[inline]
pub fn from_f64(f: f64) -> Option<Number> {
if f.is_finite() {
let n = {
@@ -279,6 +198,87 @@ impl Number {
}
}
/// If the `Number` is an integer, represent it as i128 if possible. Returns
/// None otherwise.
pub fn as_i128(&self) -> Option<i128> {
#[cfg(not(feature = "arbitrary_precision"))]
match self.n {
N::PosInt(n) => Some(n as i128),
N::NegInt(n) => Some(n as i128),
N::Float(_) => None,
}
#[cfg(feature = "arbitrary_precision")]
self.n.parse().ok()
}
/// If the `Number` is an integer, represent it as u128 if possible. Returns
/// None otherwise.
pub fn as_u128(&self) -> Option<u128> {
#[cfg(not(feature = "arbitrary_precision"))]
match self.n {
N::PosInt(n) => Some(n as u128),
N::NegInt(_) | N::Float(_) => None,
}
#[cfg(feature = "arbitrary_precision")]
self.n.parse().ok()
}
/// Converts an `i128` to a `Number`. Numbers smaller than i64::MIN or
/// larger than u64::MAX can only be represented in `Number` if serde_json's
/// "arbitrary_precision" feature is enabled.
///
/// ```
/// # use serde_json::Number;
/// #
/// assert!(Number::from_i128(256).is_some());
/// ```
pub fn from_i128(i: i128) -> Option<Number> {
let n = {
#[cfg(not(feature = "arbitrary_precision"))]
{
if let Ok(u) = u64::try_from(i) {
N::PosInt(u)
} else if let Ok(i) = i64::try_from(i) {
N::NegInt(i)
} else {
return None;
}
}
#[cfg(feature = "arbitrary_precision")]
{
i.to_string()
}
};
Some(Number { n })
}
/// Converts a `u128` to a `Number`. Numbers greater than u64::MAX can only
/// be represented in `Number` if serde_json's "arbitrary_precision" feature
/// is enabled.
///
/// ```
/// # use serde_json::Number;
/// #
/// assert!(Number::from_u128(256).is_some());
/// ```
pub fn from_u128(i: u128) -> Option<Number> {
let n = {
#[cfg(not(feature = "arbitrary_precision"))]
{
if let Ok(u) = u64::try_from(i) {
N::PosInt(u)
} else {
return None;
}
}
#[cfg(feature = "arbitrary_precision")]
{
i.to_string()
}
};
Some(Number { n })
}
/// Returns the exact original JSON representation that this Number was
/// parsed from.
///
@@ -368,7 +368,6 @@ impl Debug for Number {
impl Serialize for Number {
#[cfg(not(feature = "arbitrary_precision"))]
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
@@ -381,7 +380,6 @@ impl Serialize for Number {
}
#[cfg(feature = "arbitrary_precision")]
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
@@ -409,17 +407,30 @@ impl<'de> Deserialize<'de> for Number {
formatter.write_str("a JSON number")
}
#[inline]
fn visit_i64<E>(self, value: i64) -> Result<Number, E> {
Ok(value.into())
}
#[inline]
fn visit_i128<E>(self, value: i128) -> Result<Number, E>
where
E: de::Error,
{
Number::from_i128(value)
.ok_or_else(|| de::Error::custom("JSON number out of range"))
}
fn visit_u64<E>(self, value: u64) -> Result<Number, E> {
Ok(value.into())
}
#[inline]
fn visit_u128<E>(self, value: u128) -> Result<Number, E>
where
E: de::Error,
{
Number::from_u128(value)
.ok_or_else(|| de::Error::custom("JSON number out of range"))
}
fn visit_f64<E>(self, value: f64) -> Result<Number, E>
where
E: de::Error,
@@ -428,7 +439,6 @@ impl<'de> Deserialize<'de> for Number {
}
#[cfg(feature = "arbitrary_precision")]
#[inline]
fn visit_map<V>(self, mut visitor: V) -> Result<Number, V::Error>
where
V: de::MapAccess<'de>,
@@ -522,7 +532,6 @@ fn invalid_number() -> Error {
macro_rules! deserialize_any {
(@expand [$($num_string:tt)*]) => {
#[cfg(not(feature = "arbitrary_precision"))]
#[inline]
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
where
V: Visitor<'de>,
@@ -535,7 +544,6 @@ macro_rules! deserialize_any {
}
#[cfg(feature = "arbitrary_precision")]
#[inline]
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
where V: Visitor<'de>
{
@@ -543,6 +551,10 @@ macro_rules! deserialize_any {
return visitor.visit_u64(u);
} else if let Some(i) = self.as_i64() {
return visitor.visit_i64(i);
} else if let Some(u) = self.as_u128() {
return visitor.visit_u128(u);
} else if let Some(i) = self.as_i128() {
return visitor.visit_i128(i);
} else if let Some(f) = self.as_f64() {
if ryu::Buffer::new().format_finite(f) == self.n || f.to_string() == self.n {
return visitor.visit_f64(f);
@@ -609,7 +621,7 @@ impl<'de> Deserializer<'de> for Number {
}
}
impl<'de, 'a> Deserializer<'de> for &'a Number {
impl<'de> Deserializer<'de> for &Number {
type Error = Error;
deserialize_any!(ref);
@@ -692,7 +704,7 @@ impl From<ParserNumber> for Number {
}
#[cfg(feature = "arbitrary_precision")]
{
f.to_string()
ryu::Buffer::new().format_finite(f).to_owned()
}
}
ParserNumber::U64(u) => {
@@ -702,7 +714,7 @@ impl From<ParserNumber> for Number {
}
#[cfg(feature = "arbitrary_precision")]
{
u.to_string()
itoa::Buffer::new().format(u).to_owned()
}
}
ParserNumber::I64(i) => {
@@ -712,7 +724,7 @@ impl From<ParserNumber> for Number {
}
#[cfg(feature = "arbitrary_precision")]
{
i.to_string()
itoa::Buffer::new().format(i).to_owned()
}
}
#[cfg(feature = "arbitrary_precision")]
@@ -728,7 +740,6 @@ macro_rules! impl_from_unsigned {
) => {
$(
impl From<$ty> for Number {
#[inline]
fn from(u: $ty) -> Self {
let n = {
#[cfg(not(feature = "arbitrary_precision"))]
@@ -751,7 +762,6 @@ macro_rules! impl_from_signed {
) => {
$(
impl From<$ty> for Number {
#[inline]
fn from(i: $ty) -> Self {
let n = {
#[cfg(not(feature = "arbitrary_precision"))]

View File

@@ -99,9 +99,9 @@ use serde::ser::{Serialize, SerializeStruct, Serializer};
/// the boxed form of `RawValue` instead. This is almost as efficient but
/// involves buffering the raw value from the I/O stream into memory.
///
/// [`serde_json::from_str`]: ../fn.from_str.html
/// [`serde_json::from_slice`]: ../fn.from_slice.html
/// [`serde_json::from_reader`]: ../fn.from_reader.html
/// [`serde_json::from_str`]: crate::from_str
/// [`serde_json::from_slice`]: crate::from_slice
/// [`serde_json::from_reader`]: crate::from_reader
///
/// ```
/// # use serde::Deserialize;
@@ -119,7 +119,7 @@ pub struct RawValue {
}
impl RawValue {
fn from_borrowed(json: &str) -> &Self {
const fn from_borrowed(json: &str) -> &Self {
unsafe { mem::transmute::<&str, &RawValue>(json) }
}
@@ -148,7 +148,7 @@ impl ToOwned for RawValue {
impl Default for Box<RawValue> {
fn default() -> Self {
RawValue::from_borrowed("null").to_owned()
RawValue::NULL.to_owned()
}
}
@@ -168,6 +168,13 @@ impl Display for RawValue {
}
impl RawValue {
/// A constant RawValue with the JSON value `null`.
pub const NULL: &'static RawValue = RawValue::from_borrowed("null");
/// A constant RawValue with the JSON value `true`.
pub const TRUE: &'static RawValue = RawValue::from_borrowed("true");
/// A constant RawValue with the JSON value `false`.
pub const FALSE: &'static RawValue = RawValue::from_borrowed("false");
/// Convert an owned `String` of JSON data to an owned `RawValue`.
///
/// This function is equivalent to `serde_json::from_str::<Box<RawValue>>`

View File

@@ -1,7 +1,7 @@
use crate::error::{Error, ErrorCode, Result};
use alloc::vec::Vec;
use core::char;
use core::cmp;
use core::mem;
use core::ops::Deref;
use core::str;
@@ -191,6 +191,12 @@ where
R: io::Read,
{
/// Create a JSON input source to read from a std::io input stream.
///
/// When reading from a source against which short reads are not efficient, such
/// as a [`File`], you will want to apply your own buffering because serde_json
/// will not buffer the input. See [`std::io::BufReader`].
///
/// [`File`]: std::fs::File
pub fn new(reader: R) -> Self {
IoRead {
iter: LineColIterator::new(reader.bytes()),
@@ -221,7 +227,7 @@ where
{
loop {
let ch = tri!(next_or_eof(self));
if !ESCAPE[ch as usize] {
if !is_escape(ch, true) {
scratch.push(ch);
continue;
}
@@ -342,7 +348,7 @@ where
fn ignore_str(&mut self) -> Result<()> {
loop {
let ch = tri!(next_or_eof(self));
if !ESCAPE[ch as usize] {
if !is_escape(ch, true) {
continue;
}
match ch {
@@ -360,17 +366,15 @@ where
}
fn decode_hex_escape(&mut self) -> Result<u16> {
let mut n = 0;
for _ in 0..4 {
match decode_hex_val(tri!(next_or_eof(self))) {
None => return error(self, ErrorCode::InvalidEscape),
Some(val) => {
n = (n << 4) + val;
let a = tri!(next_or_eof(self));
let b = tri!(next_or_eof(self));
let c = tri!(next_or_eof(self));
let d = tri!(next_or_eof(self));
match decode_four_hex_digits(a, b, c, d) {
Some(val) => Ok(val),
None => error(self, ErrorCode::InvalidEscape),
}
}
}
Ok(n)
}
#[cfg(feature = "raw_value")]
fn begin_raw_buffering(&mut self) {
@@ -415,19 +419,73 @@ impl<'a> SliceRead<'a> {
}
fn position_of_index(&self, i: usize) -> Position {
let mut position = Position { line: 1, column: 0 };
for ch in &self.slice[..i] {
match *ch {
b'\n' => {
position.line += 1;
position.column = 0;
}
_ => {
position.column += 1;
let start_of_line = match memchr::memrchr(b'\n', &self.slice[..i]) {
Some(position) => position + 1,
None => 0,
};
Position {
line: 1 + memchr::memchr_iter(b'\n', &self.slice[..start_of_line]).count(),
column: i - start_of_line,
}
}
fn skip_to_escape(&mut self, forbid_control_characters: bool) {
// Immediately bail-out on empty strings and consecutive escapes (e.g. \u041b\u0435)
if self.index == self.slice.len()
|| is_escape(self.slice[self.index], forbid_control_characters)
{
return;
}
self.index += 1;
let rest = &self.slice[self.index..];
if !forbid_control_characters {
self.index += memchr::memchr2(b'"', b'\\', rest).unwrap_or(rest.len());
return;
}
// We wish to find the first byte in range 0x00..=0x1F or " or \. Ideally, we'd use
// something akin to memchr3, but the memchr crate does not support this at the moment.
// Therefore, we use a variation on Mycroft's algorithm [1] to provide performance better
// than a naive loop. It runs faster than equivalent two-pass memchr2+SWAR code on
// benchmarks and it's cross-platform, so probably the right fit.
// [1]: https://groups.google.com/forum/#!original/comp.lang.c/2HtQXvg7iKc/xOJeipH6KLMJ
#[cfg(fast_arithmetic = "64")]
type Chunk = u64;
#[cfg(fast_arithmetic = "32")]
type Chunk = u32;
const STEP: usize = mem::size_of::<Chunk>();
const ONE_BYTES: Chunk = Chunk::MAX / 255; // 0x0101...01
for chunk in rest.chunks_exact(STEP) {
let chars = Chunk::from_le_bytes(chunk.try_into().unwrap());
let contains_ctrl = chars.wrapping_sub(ONE_BYTES * 0x20) & !chars;
let chars_quote = chars ^ (ONE_BYTES * Chunk::from(b'"'));
let contains_quote = chars_quote.wrapping_sub(ONE_BYTES) & !chars_quote;
let chars_backslash = chars ^ (ONE_BYTES * Chunk::from(b'\\'));
let contains_backslash = chars_backslash.wrapping_sub(ONE_BYTES) & !chars_backslash;
let masked = (contains_ctrl | contains_quote | contains_backslash) & (ONE_BYTES << 7);
if masked != 0 {
// SAFETY: chunk is in-bounds for slice
self.index = unsafe { chunk.as_ptr().offset_from(self.slice.as_ptr()) } as usize
+ masked.trailing_zeros() as usize / 8;
return;
}
}
self.index += rest.len() / STEP * STEP;
self.skip_to_escape_slow();
}
#[cold]
#[inline(never)]
fn skip_to_escape_slow(&mut self) {
while self.index < self.slice.len() && !is_escape(self.slice[self.index], true) {
self.index += 1;
}
position
}
/// The big optimization here over IoRead is that if the string contains no
@@ -447,9 +505,7 @@ impl<'a> SliceRead<'a> {
let mut start = self.index;
loop {
while self.index < self.slice.len() && !ESCAPE[self.slice[self.index] as usize] {
self.index += 1;
}
self.skip_to_escape(validate);
if self.index == self.slice.len() {
return error(self, ErrorCode::EofWhileParsingString);
}
@@ -475,13 +531,11 @@ impl<'a> SliceRead<'a> {
}
_ => {
self.index += 1;
if validate {
return error(self, ErrorCode::ControlCharacterWhileParsingString);
}
}
}
}
}
}
impl<'a> private::Sealed for SliceRead<'a> {}
@@ -543,9 +597,7 @@ impl<'a> Read<'a> for SliceRead<'a> {
fn ignore_str(&mut self) -> Result<()> {
loop {
while self.index < self.slice.len() && !ESCAPE[self.slice[self.index] as usize] {
self.index += 1;
}
self.skip_to_escape(true);
if self.index == self.slice.len() {
return error(self, ErrorCode::EofWhileParsingString);
}
@@ -565,25 +617,22 @@ impl<'a> Read<'a> for SliceRead<'a> {
}
}
#[inline]
fn decode_hex_escape(&mut self) -> Result<u16> {
if self.index + 4 > self.slice.len() {
match self.slice[self.index..] {
[a, b, c, d, ..] => {
self.index += 4;
match decode_four_hex_digits(a, b, c, d) {
Some(val) => Ok(val),
None => error(self, ErrorCode::InvalidEscape),
}
}
_ => {
self.index = self.slice.len();
return error(self, ErrorCode::EofWhileParsingString);
}
let mut n = 0;
for _ in 0..4 {
let ch = decode_hex_val(self.slice[self.index]);
self.index += 1;
match ch {
None => return error(self, ErrorCode::InvalidEscape),
Some(val) => {
n = (n << 4) + val;
error(self, ErrorCode::EofWhileParsingString)
}
}
}
Ok(n)
}
#[cfg(feature = "raw_value")]
fn begin_raw_buffering(&mut self) {
@@ -708,9 +757,9 @@ impl<'a> Read<'a> for StrRead<'a> {
//////////////////////////////////////////////////////////////////////////////
impl<'a, 'de, R> private::Sealed for &'a mut R where R: Read<'de> {}
impl<'de, R> private::Sealed for &mut R where R: Read<'de> {}
impl<'a, 'de, R> Read<'de> for &'a mut R
impl<'de, R> Read<'de> for &mut R
where
R: Read<'de>,
{
@@ -784,33 +833,9 @@ pub trait Fused: private::Sealed {}
impl<'a> Fused for SliceRead<'a> {}
impl<'a> Fused for StrRead<'a> {}
// Lookup table of bytes that must be escaped. A value of true at index i means
// that byte i requires an escape sequence in the input.
static ESCAPE: [bool; 256] = {
const CT: bool = true; // control character \x00..=\x1F
const QU: bool = true; // quote \x22
const BS: bool = true; // backslash \x5C
const __: bool = false; // allow unescaped
[
// 1 2 3 4 5 6 7 8 9 A B C D E F
CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, // 0
CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, // 1
__, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4
__, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, // 5
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
]
};
fn is_escape(ch: u8, including_control_characters: bool) -> bool {
ch == b'"' || ch == b'\\' || (including_control_characters && ch < 0x20)
}
fn next_or_eof<'de, R>(read: &mut R) -> Result<u8>
where
@@ -862,30 +887,43 @@ fn parse_escape<'de, R: Read<'de>>(
b'n' => scratch.push(b'\n'),
b'r' => scratch.push(b'\r'),
b't' => scratch.push(b'\t'),
b'u' => {
fn encode_surrogate(scratch: &mut Vec<u8>, n: u16) {
scratch.extend_from_slice(&[
(n >> 12 & 0b0000_1111) as u8 | 0b1110_0000,
(n >> 6 & 0b0011_1111) as u8 | 0b1000_0000,
(n & 0b0011_1111) as u8 | 0b1000_0000,
]);
b'u' => return parse_unicode_escape(read, validate, scratch),
_ => return error(read, ErrorCode::InvalidEscape),
}
let c = match tri!(read.decode_hex_escape()) {
n @ 0xDC00..=0xDFFF => {
return if validate {
error(read, ErrorCode::LoneLeadingSurrogateInHexEscape)
} else {
encode_surrogate(scratch, n);
Ok(())
};
}
/// Parses a JSON \u escape and appends it into the scratch space. Assumes `\u`
/// has just been read.
#[cold]
fn parse_unicode_escape<'de, R: Read<'de>>(
read: &mut R,
validate: bool,
scratch: &mut Vec<u8>,
) -> Result<()> {
let mut n = tri!(read.decode_hex_escape());
// Non-BMP characters are encoded as a sequence of two hex escapes,
// representing UTF-16 surrogates. If deserializing a utf-8 string the
// surrogates are required to be paired, whereas deserializing a byte string
// accepts lone surrogates.
if validate && n >= 0xDC00 && n <= 0xDFFF {
// XXX: This is actually a trailing surrogate.
return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape);
}
// Non-BMP characters are encoded as a sequence of two hex
// escapes, representing UTF-16 surrogates. If deserializing a
// utf-8 string the surrogates are required to be paired,
// whereas deserializing a byte string accepts lone surrogates.
n1 @ 0xD800..=0xDBFF => {
loop {
if n < 0xD800 || n > 0xDBFF {
// Every u16 outside of the surrogate ranges is guaranteed to be a
// legal char.
push_wtf8_codepoint(n as u32, scratch);
return Ok(());
}
// n is a leading surrogate, we now expect a trailing surrogate.
let n1 = n;
if tri!(peek_or_eof(read)) == b'\\' {
read.discard();
} else {
@@ -893,7 +931,7 @@ fn parse_escape<'de, R: Read<'de>>(
read.discard();
error(read, ErrorCode::UnexpectedEndOfHexEscape)
} else {
encode_surrogate(scratch, n1);
push_wtf8_codepoint(n1 as u32, scratch);
Ok(())
};
}
@@ -905,12 +943,11 @@ fn parse_escape<'de, R: Read<'de>>(
read.discard();
error(read, ErrorCode::UnexpectedEndOfHexEscape)
} else {
encode_surrogate(scratch, n1);
// The \ prior to this byte started an escape sequence,
// so we need to parse that now. This recursive call
// does not blow the stack on malicious input because
// the escape is not \u, so it will be handled by one
// of the easy nonrecursive cases.
push_wtf8_codepoint(n1 as u32, scratch);
// The \ prior to this byte started an escape sequence, so we
// need to parse that now. This recursive call does not blow the
// stack on malicious input because the escape is not \u, so it
// will be handled by one of the easy nonrecursive cases.
parse_escape(read, validate, scratch)
};
}
@@ -918,32 +955,69 @@ fn parse_escape<'de, R: Read<'de>>(
let n2 = tri!(read.decode_hex_escape());
if n2 < 0xDC00 || n2 > 0xDFFF {
if validate {
return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape);
}
let n = (((n1 - 0xD800) as u32) << 10 | (n2 - 0xDC00) as u32) + 0x1_0000;
match char::from_u32(n) {
Some(c) => c,
None => {
return error(read, ErrorCode::InvalidUnicodeCodePoint);
}
}
push_wtf8_codepoint(n1 as u32, scratch);
// If n2 is a leading surrogate, we need to restart.
n = n2;
continue;
}
// Every u16 outside of the surrogate ranges above is guaranteed
// to be a legal char.
n => char::from_u32(n as u32).unwrap(),
// This value is in range U+10000..=U+10FFFF, which is always a valid
// codepoint.
let n = ((((n1 - 0xD800) as u32) << 10) | (n2 - 0xDC00) as u32) + 0x1_0000;
push_wtf8_codepoint(n, scratch);
return Ok(());
}
}
/// Adds a WTF-8 codepoint to the end of the buffer. This is a more efficient
/// implementation of String::push. The codepoint may be a surrogate.
#[inline]
fn push_wtf8_codepoint(n: u32, scratch: &mut Vec<u8>) {
if n < 0x80 {
scratch.push(n as u8);
return;
}
scratch.reserve(4);
// SAFETY: After the `reserve` call, `scratch` has at least 4 bytes of
// allocated but unintialized memory after its last initialized byte, which
// is where `ptr` points. All reachable match arms write `encoded_len` bytes
// to that region and update the length accordingly, and `encoded_len` is
// always <= 4.
unsafe {
let ptr = scratch.as_mut_ptr().add(scratch.len());
let encoded_len = match n {
0..=0x7F => unreachable!(),
0x80..=0x7FF => {
ptr.write(((n >> 6) & 0b0001_1111) as u8 | 0b1100_0000);
2
}
0x800..=0xFFFF => {
ptr.write(((n >> 12) & 0b0000_1111) as u8 | 0b1110_0000);
ptr.add(1)
.write(((n >> 6) & 0b0011_1111) as u8 | 0b1000_0000);
3
}
0x1_0000..=0x10_FFFF => {
ptr.write(((n >> 18) & 0b0000_0111) as u8 | 0b1111_0000);
ptr.add(1)
.write(((n >> 12) & 0b0011_1111) as u8 | 0b1000_0000);
ptr.add(2)
.write(((n >> 6) & 0b0011_1111) as u8 | 0b1000_0000);
4
}
0x11_0000.. => unreachable!(),
};
ptr.add(encoded_len - 1)
.write((n & 0b0011_1111) as u8 | 0b1000_0000);
scratch.extend_from_slice(c.encode_utf8(&mut [0_u8; 4]).as_bytes());
scratch.set_len(scratch.len() + encoded_len);
}
_ => {
return error(read, ErrorCode::InvalidEscape);
}
}
Ok(())
}
/// Parses a JSON escape sequence and discards the value. Assumes the previous
@@ -973,34 +1047,43 @@ where
Ok(())
}
static HEX: [u8; 256] = {
const __: u8 = 255; // not a hex digit
[
// 1 2 3 4 5 6 7 8 9 A B C D E F
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 0
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 1
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2
00, 01, 02, 03, 04, 05, 06, 07, 08, 09, __, __, __, __, __, __, // 3
__, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __, // 4
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 5
__, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __, // 6
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
]
};
fn decode_hex_val(val: u8) -> Option<u16> {
let n = HEX[val as usize] as u16;
if n == 255 {
None
} else {
Some(n)
const fn decode_hex_val_slow(val: u8) -> Option<u8> {
match val {
b'0'..=b'9' => Some(val - b'0'),
b'A'..=b'F' => Some(val - b'A' + 10),
b'a'..=b'f' => Some(val - b'a' + 10),
_ => None,
}
}
const fn build_hex_table(shift: usize) -> [i16; 256] {
let mut table = [0; 256];
let mut ch = 0;
while ch < 256 {
table[ch] = match decode_hex_val_slow(ch as u8) {
Some(val) => (val as i16) << shift,
None => -1,
};
ch += 1;
}
table
}
static HEX0: [i16; 256] = build_hex_table(0);
static HEX1: [i16; 256] = build_hex_table(4);
fn decode_four_hex_digits(a: u8, b: u8, c: u8, d: u8) -> Option<u16> {
let a = HEX1[a as usize] as i32;
let b = HEX0[b as usize] as i32;
let c = HEX1[c as usize] as i32;
let d = HEX0[d as usize] as i32;
let codepoint = ((a | b) << 8) | c | d;
// A single sign bit check.
if codepoint >= 0 {
Some(codepoint as u16)
} else {
None
}
}

View File

@@ -2,7 +2,9 @@
use crate::error::{Error, ErrorCode, Result};
use crate::io;
use alloc::string::{String, ToString};
use alloc::string::String;
#[cfg(feature = "raw_value")]
use alloc::string::ToString;
use alloc::vec::Vec;
use core::fmt::{self, Display};
use core::num::FpCategory;
@@ -1057,7 +1059,7 @@ where
}
fn serialize_char(self, value: char) -> Result<()> {
self.ser.serialize_str(&value.to_string())
self.ser.serialize_str(value.encode_utf8(&mut [0u8; 4]))
}
fn serialize_bytes(self, _value: &[u8]) -> Result<()> {
@@ -1686,6 +1688,20 @@ pub trait Formatter {
}
/// Writes a floating point value like `-31.26e+12` to the specified writer.
///
/// # Special cases
///
/// This function **does not** check for NaN or infinity. If the input
/// number is not a finite float, the printed representation will be some
/// correctly formatted but unspecified numerical value.
///
/// Please check [`is_finite`] yourself before calling this function, or
/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself
/// with a different `Formatter` method.
///
/// [`is_finite`]: f32::is_finite
/// [`is_nan`]: f32::is_nan
/// [`is_infinite`]: f32::is_infinite
#[inline]
fn write_f32<W>(&mut self, writer: &mut W, value: f32) -> io::Result<()>
where
@@ -1697,6 +1713,20 @@ pub trait Formatter {
}
/// Writes a floating point value like `-31.26e+12` to the specified writer.
///
/// # Special cases
///
/// This function **does not** check for NaN or infinity. If the input
/// number is not a finite float, the printed representation will be some
/// correctly formatted but unspecified numerical value.
///
/// Please check [`is_finite`] yourself before calling this function, or
/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself
/// with a different `Formatter` method.
///
/// [`is_finite`]: f64::is_finite
/// [`is_nan`]: f64::is_nan
/// [`is_infinite`]: f64::is_infinite
#[inline]
fn write_f64<W>(&mut self, writer: &mut W, value: f64) -> io::Result<()>
where

View File

@@ -11,8 +11,8 @@ use core::fmt;
use core::slice;
use core::str::FromStr;
use serde::de::{
self, Deserialize, DeserializeSeed, EnumAccess, Expected, IntoDeserializer, MapAccess,
SeqAccess, Unexpected, VariantAccess, Visitor,
self, Deserialize, DeserializeSeed, Deserializer as _, EnumAccess, Expected, IntoDeserializer,
MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor,
};
use serde::forward_to_deserialize_any;
@@ -44,11 +44,27 @@ impl<'de> Deserialize<'de> for Value {
Ok(Value::Number(value.into()))
}
fn visit_i128<E>(self, value: i128) -> Result<Value, E>
where
E: serde::de::Error,
{
let de = serde::de::value::I128Deserializer::new(value);
Number::deserialize(de).map(Value::Number)
}
#[inline]
fn visit_u64<E>(self, value: u64) -> Result<Value, E> {
Ok(Value::Number(value.into()))
}
fn visit_u128<E>(self, value: u128) -> Result<Value, E>
where
E: serde::de::Error,
{
let de = serde::de::value::U128Deserializer::new(value);
Number::deserialize(de).map(Value::Number)
}
#[inline]
fn visit_f64<E>(self, value: f64) -> Result<Value, E> {
Ok(Number::from_f64(value).map_or(Value::Null, Value::Number))
@@ -187,12 +203,15 @@ where
}
}
fn visit_object<'de, V>(object: Map<String, Value>, visitor: V) -> Result<V::Value, Error>
where
impl<'de> serde::Deserializer<'de> for Map<String, Value> {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let len = object.len();
let mut deserializer = MapDeserializer::new(object);
{
let len = self.len();
let mut deserializer = MapDeserializer::new(self);
let map = tri!(visitor.visit_map(&mut deserializer));
let remaining = deserializer.iter.len();
if remaining == 0 {
@@ -203,6 +222,54 @@ where
&"fewer elements in map",
))
}
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let mut iter = self.into_iter();
let (variant, value) = match iter.next() {
Some(v) => v,
None => {
return Err(serde::de::Error::invalid_value(
Unexpected::Map,
&"map with a single key",
));
}
};
// enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() {
return Err(serde::de::Error::invalid_value(
Unexpected::Map,
&"map with a single key",
));
}
visitor.visit_enum(EnumDeserializer {
variant,
value: Some(value),
})
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
drop(self);
visitor.visit_unit()
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct identifier
}
}
impl<'de> serde::Deserializer<'de> for Value {
@@ -222,7 +289,7 @@ impl<'de> serde::Deserializer<'de> for Value {
#[cfg(not(any(feature = "std", feature = "alloc")))]
Value::String(_) => unreachable!(),
Value::Array(v) => visit_array(v, visitor),
Value::Object(v) => visit_object(v, visitor),
Value::Object(v) => v.deserialize_any(visitor),
}
}
@@ -253,44 +320,24 @@ impl<'de> serde::Deserializer<'de> for Value {
#[inline]
fn deserialize_enum<V>(
self,
_name: &str,
_variants: &'static [&'static str],
name: &'static str,
variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
let (variant, value) = match self {
Value::Object(value) => {
let mut iter = value.into_iter();
let (variant, value) = match iter.next() {
Some(v) => v,
None => {
return Err(serde::de::Error::invalid_value(
Unexpected::Map,
&"map with a single key",
));
}
};
// enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() {
return Err(serde::de::Error::invalid_value(
Unexpected::Map,
&"map with a single key",
));
}
(variant, Some(value))
}
Value::String(variant) => (variant, None),
other => {
return Err(serde::de::Error::invalid_type(
match self {
Value::Object(value) => value.deserialize_enum(name, variants, visitor),
Value::String(variant) => visitor.visit_enum(EnumDeserializer {
variant,
value: None,
}),
other => Err(serde::de::Error::invalid_type(
other.unexpected(),
&"string or map",
));
)),
}
};
visitor.visit_enum(EnumDeserializer { variant, value })
}
#[inline]
@@ -420,7 +467,7 @@ impl<'de> serde::Deserializer<'de> for Value {
V: Visitor<'de>,
{
match self {
Value::Object(v) => visit_object(v, visitor),
Value::Object(v) => v.deserialize_any(visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
@@ -436,7 +483,7 @@ impl<'de> serde::Deserializer<'de> for Value {
{
match self {
Value::Array(v) => visit_array(v, visitor),
Value::Object(v) => visit_object(v, visitor),
Value::Object(v) => v.deserialize_any(visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
@@ -551,7 +598,7 @@ impl<'de> VariantAccess<'de> for VariantDeserializer {
V: Visitor<'de>,
{
match self.value {
Some(Value::Object(v)) => visit_object(v, visitor),
Some(Value::Object(v)) => v.deserialize_any(visitor),
Some(other) => Err(serde::de::Error::invalid_type(
other.unexpected(),
&"struct variant",
@@ -692,12 +739,15 @@ where
}
}
fn visit_object_ref<'de, V>(object: &'de Map<String, Value>, visitor: V) -> Result<V::Value, Error>
where
impl<'de> serde::Deserializer<'de> for &'de Map<String, Value> {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let len = object.len();
let mut deserializer = MapRefDeserializer::new(object);
{
let len = self.len();
let mut deserializer = MapRefDeserializer::new(self);
let map = tri!(visitor.visit_map(&mut deserializer));
let remaining = deserializer.iter.len();
if remaining == 0 {
@@ -708,6 +758,53 @@ where
&"fewer elements in map",
))
}
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let mut iter = self.into_iter();
let (variant, value) = match iter.next() {
Some(v) => v,
None => {
return Err(serde::de::Error::invalid_value(
Unexpected::Map,
&"map with a single key",
));
}
};
// enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() {
return Err(serde::de::Error::invalid_value(
Unexpected::Map,
&"map with a single key",
));
}
visitor.visit_enum(EnumRefDeserializer {
variant,
value: Some(value),
})
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct identifier
}
}
impl<'de> serde::Deserializer<'de> for &'de Value {
@@ -723,7 +820,7 @@ impl<'de> serde::Deserializer<'de> for &'de Value {
Value::Number(n) => n.deserialize_any(visitor),
Value::String(v) => visitor.visit_borrowed_str(v),
Value::Array(v) => visit_array_ref(v, visitor),
Value::Object(v) => visit_object_ref(v, visitor),
Value::Object(v) => v.deserialize_any(visitor),
}
}
@@ -752,44 +849,24 @@ impl<'de> serde::Deserializer<'de> for &'de Value {
fn deserialize_enum<V>(
self,
_name: &str,
_variants: &'static [&'static str],
name: &'static str,
variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
let (variant, value) = match self {
Value::Object(value) => {
let mut iter = value.into_iter();
let (variant, value) = match iter.next() {
Some(v) => v,
None => {
return Err(serde::de::Error::invalid_value(
Unexpected::Map,
&"map with a single key",
));
}
};
// enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() {
return Err(serde::de::Error::invalid_value(
Unexpected::Map,
&"map with a single key",
));
}
(variant, Some(value))
}
Value::String(variant) => (variant, None),
other => {
return Err(serde::de::Error::invalid_type(
match self {
Value::Object(value) => value.deserialize_enum(name, variants, visitor),
Value::String(variant) => visitor.visit_enum(EnumRefDeserializer {
variant,
value: None,
}),
other => Err(serde::de::Error::invalid_type(
other.unexpected(),
&"string or map",
));
)),
}
};
visitor.visit_enum(EnumRefDeserializer { variant, value })
}
#[inline]
@@ -917,7 +994,7 @@ impl<'de> serde::Deserializer<'de> for &'de Value {
V: Visitor<'de>,
{
match self {
Value::Object(v) => visit_object_ref(v, visitor),
Value::Object(v) => v.deserialize_any(visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
@@ -933,7 +1010,7 @@ impl<'de> serde::Deserializer<'de> for &'de Value {
{
match self {
Value::Array(v) => visit_array_ref(v, visitor),
Value::Object(v) => visit_object_ref(v, visitor),
Value::Object(v) => v.deserialize_any(visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
@@ -1031,7 +1108,7 @@ impl<'de> VariantAccess<'de> for VariantRefDeserializer<'de> {
V: Visitor<'de>,
{
match self.value {
Some(Value::Object(v)) => visit_object_ref(v, visitor),
Some(Value::Object(v)) => v.deserialize_any(visitor),
Some(other) => Err(serde::de::Error::invalid_type(
other.unexpected(),
&"struct variant",

View File

@@ -1,8 +1,8 @@
use super::Value;
use crate::map::Map;
use crate::number::Number;
use alloc::borrow::Cow;
use alloc::string::{String, ToString};
use alloc::borrow::{Cow, ToOwned};
use alloc::string::String;
use alloc::vec::Vec;
macro_rules! from_integer {
@@ -85,7 +85,7 @@ impl From<String> for Value {
/// ```
/// use serde_json::Value;
///
/// let s: String = "lorem".to_string();
/// let s: String = "lorem".to_owned();
/// let x: Value = s.into();
/// ```
fn from(f: String) -> Self {
@@ -105,7 +105,7 @@ impl From<&str> for Value {
/// let x: Value = s.into();
/// ```
fn from(f: &str) -> Self {
Value::String(f.to_string())
Value::String(f.to_owned())
}
}
@@ -126,7 +126,7 @@ impl<'a> From<Cow<'a, str>> for Value {
/// use serde_json::Value;
/// use std::borrow::Cow;
///
/// let s: Cow<str> = Cow::Owned("lorem".to_string());
/// let s: Cow<str> = Cow::Owned("lorem".to_owned());
/// let x: Value = s.into();
/// ```
fn from(f: Cow<'a, str>) -> Self {
@@ -159,7 +159,7 @@ impl From<Map<String, Value>> for Value {
/// use serde_json::{Map, Value};
///
/// let mut m = Map::new();
/// m.insert("Lorem".to_string(), "ipsum".into());
/// m.insert("Lorem".to_owned(), "ipsum".into());
/// let x: Value = m.into();
/// ```
fn from(f: Map<String, Value>) -> Self {
@@ -183,6 +183,12 @@ impl<T: Into<Value>> From<Vec<T>> for Value {
}
}
impl<T: Into<Value>, const N: usize> From<[T; N]> for Value {
fn from(array: [T; N]) -> Self {
Value::Array(array.into_iter().map(Into::into).collect())
}
}
impl<T: Clone + Into<Value>> From<&[T]> for Value {
/// Convert a slice to `Value::Array`.
///

View File

@@ -12,9 +12,9 @@ use core::ops;
/// trait is implemented for strings which are used as the index into a JSON
/// map, and for `usize` which is used as the index into a JSON array.
///
/// [`get`]: ../enum.Value.html#method.get
/// [`get_mut`]: ../enum.Value.html#method.get_mut
/// [square-bracket indexing operator]: ../enum.Value.html#impl-Index%3CI%3E
/// [`get`]: Value::get
/// [`get_mut`]: Value::get_mut
/// [square-bracket indexing operator]: Value#impl-Index%3CI%3E-for-Value
///
/// This trait is sealed and cannot be implemented for types outside of
/// `serde_json`.
@@ -137,7 +137,7 @@ mod private {
impl Sealed for usize {}
impl Sealed for str {}
impl Sealed for alloc::string::String {}
impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {}
impl<T> Sealed for &T where T: ?Sized + Sealed {}
}
/// Used in panic messages.

View File

@@ -112,7 +112,7 @@ pub use crate::raw::{to_raw_value, RawValue};
/// Represents any valid JSON value.
///
/// See the [`serde_json::value` module documentation](self) for usage examples.
#[derive(Clone, Eq, PartialEq)]
#[derive(Clone, Eq, PartialEq, Hash)]
pub enum Value {
/// Represents a JSON null value.
///
@@ -861,6 +861,32 @@ impl Value {
pub fn take(&mut self) -> Value {
mem::replace(self, Value::Null)
}
/// Reorders the entries of all `Value::Object` nested within this JSON
/// value according to `str`'s usual ordering.
///
/// If serde_json's "preserve_order" feature is not enabled, this method
/// does no work because all JSON maps are always kept in a sorted state.
///
/// If serde_json's "preserve_order" feature is enabled, this method
/// destroys the original source order or insertion order of the JSON
/// objects in favor of an alphanumerical order that matches how a BTreeMap
/// with the same contents would be ordered.
pub fn sort_all_objects(&mut self) {
#[cfg(feature = "preserve_order")]
{
match self {
Value::Object(map) => {
map.sort_keys();
map.values_mut().for_each(Value::sort_all_objects);
}
Value::Array(list) => {
list.iter_mut().for_each(Value::sort_all_objects);
}
_ => {}
}
}
}
}
/// The default value is `Value::Null`.

View File

@@ -2,30 +2,30 @@ use super::Value;
use alloc::string::String;
fn eq_i64(value: &Value, other: i64) -> bool {
value.as_i64().map_or(false, |i| i == other)
value.as_i64() == Some(other)
}
fn eq_u64(value: &Value, other: u64) -> bool {
value.as_u64().map_or(false, |i| i == other)
value.as_u64() == Some(other)
}
fn eq_f32(value: &Value, other: f32) -> bool {
match value {
Value::Number(n) => n.as_f32().map_or(false, |i| i == other),
Value::Number(n) => n.as_f32() == Some(other),
_ => false,
}
}
fn eq_f64(value: &Value, other: f64) -> bool {
value.as_f64().map_or(false, |i| i == other)
value.as_f64() == Some(other)
}
fn eq_bool(value: &Value, other: bool) -> bool {
value.as_bool().map_or(false, |i| i == other)
value.as_bool() == Some(other)
}
fn eq_str(value: &Value, other: &str) -> bool {
value.as_str().map_or(false, |i| i == other)
value.as_str() == Some(other)
}
impl PartialEq<str> for Value {

View File

@@ -261,9 +261,9 @@ impl serde::Serializer for Serializer {
})
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
Ok(SerializeMap::Map {
map: Map::new(),
map: Map::with_capacity(len.unwrap_or(0)),
next_key: None,
})
}
@@ -486,39 +486,47 @@ impl serde::Serializer for MapKeySerializer {
}
fn serialize_bool(self, value: bool) -> Result<String> {
Ok(value.to_string())
Ok(if value { "true" } else { "false" }.to_owned())
}
fn serialize_i8(self, value: i8) -> Result<String> {
Ok(value.to_string())
Ok(itoa::Buffer::new().format(value).to_owned())
}
fn serialize_i16(self, value: i16) -> Result<String> {
Ok(value.to_string())
Ok(itoa::Buffer::new().format(value).to_owned())
}
fn serialize_i32(self, value: i32) -> Result<String> {
Ok(value.to_string())
Ok(itoa::Buffer::new().format(value).to_owned())
}
fn serialize_i64(self, value: i64) -> Result<String> {
Ok(value.to_string())
Ok(itoa::Buffer::new().format(value).to_owned())
}
fn serialize_i128(self, value: i128) -> Result<String> {
Ok(itoa::Buffer::new().format(value).to_owned())
}
fn serialize_u8(self, value: u8) -> Result<String> {
Ok(value.to_string())
Ok(itoa::Buffer::new().format(value).to_owned())
}
fn serialize_u16(self, value: u16) -> Result<String> {
Ok(value.to_string())
Ok(itoa::Buffer::new().format(value).to_owned())
}
fn serialize_u32(self, value: u32) -> Result<String> {
Ok(value.to_string())
Ok(itoa::Buffer::new().format(value).to_owned())
}
fn serialize_u64(self, value: u64) -> Result<String> {
Ok(value.to_string())
Ok(itoa::Buffer::new().format(value).to_owned())
}
fn serialize_u128(self, value: u128) -> Result<String> {
Ok(itoa::Buffer::new().format(value).to_owned())
}
fn serialize_f32(self, value: f32) -> Result<String> {

View File

@@ -1,5 +1,5 @@
#[rustversion::attr(not(nightly), ignore)]
#[cfg_attr(miri, ignore)]
#[rustversion::attr(not(nightly), ignore = "requires nightly")]
#[cfg_attr(miri, ignore = "incompatible with miri")]
#[test]
fn ui() {
let t = trybuild::TestCases::new();

View File

@@ -12,6 +12,7 @@
clippy::let_underscore_untyped,
clippy::module_name_repetitions,
clippy::needless_late_init,
clippy::question_mark,
clippy::shadow_unrelated,
clippy::similar_names,
clippy::single_match_else,

View File

@@ -18,12 +18,12 @@ impl Math for Bigint {
}
}
#[cfg(limb_width_32)]
#[cfg(fast_arithmetic = "32")]
pub(crate) fn from_u32(x: &[u32]) -> Vec<Limb> {
x.iter().cloned().collect()
}
#[cfg(limb_width_64)]
#[cfg(fast_arithmetic = "64")]
pub(crate) fn from_u32(x: &[u32]) -> Vec<Limb> {
let mut v = Vec::<Limb>::default();
for xi in x.chunks(2) {

View File

@@ -63,7 +63,6 @@ fn check_float<T: Float>(x: T) {
assert!(T::from_bits(x.to_bits()) == x);
// Check properties
let _ = x.to_bits() & T::SIGN_MASK;
let _ = x.to_bits() & T::EXPONENT_MASK;
let _ = x.to_bits() & T::HIDDEN_BIT_MASK;
let _ = x.to_bits() & T::MANTISSA_MASK;

View File

@@ -15,6 +15,17 @@ fn test_preserve_order() {
assert_eq!(keys, EXPECTED);
}
#[test]
#[cfg(feature = "preserve_order")]
fn test_shift_insert() {
let mut v: Value = from_str(r#"{"b":null,"a":null,"c":null}"#).unwrap();
let val = v.as_object_mut().unwrap();
val.shift_insert(0, "d".to_owned(), Value::Null);
let keys: Vec<_> = val.keys().collect();
assert_eq!(keys, &["d", "b", "a", "c"]);
}
#[test]
fn test_append() {
// Sorted order

View File

@@ -1,3 +1,5 @@
#![allow(clippy::elidable_lifetime_names, clippy::needless_lifetimes)]
mod regression {
automod::dir!("tests/regression");
}

View File

@@ -1,4 +1,3 @@
#![cfg(not(feature = "preserve_order"))]
#![allow(clippy::assertions_on_result_states)]
use serde_json::{json, Deserializer, Value};

View File

@@ -1,12 +1,13 @@
#![cfg(not(feature = "preserve_order"))]
#![allow(
clippy::assertions_on_result_states,
clippy::byte_char_slices,
clippy::cast_precision_loss,
clippy::derive_partial_eq_without_eq,
clippy::excessive_precision,
clippy::float_cmp,
clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12257
clippy::items_after_statements,
clippy::large_digit_groups,
clippy::let_underscore_untyped,
clippy::shadow_unrelated,
clippy::too_many_lines,
@@ -268,11 +269,11 @@ fn test_write_list() {
fn test_write_object() {
test_encode_ok(&[
(treemap!(), "{}"),
(treemap!("a".to_string() => true), "{\"a\":true}"),
(treemap!("a".to_owned() => true), "{\"a\":true}"),
(
treemap!(
"a".to_string() => true,
"b".to_string() => false,
"a".to_owned() => true,
"b".to_owned() => false,
),
"{\"a\":true,\"b\":false}",
),
@@ -281,44 +282,44 @@ fn test_write_object() {
test_encode_ok(&[
(
treemap![
"a".to_string() => treemap![],
"b".to_string() => treemap![],
"c".to_string() => treemap![],
"a".to_owned() => treemap![],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![],
],
"{\"a\":{},\"b\":{},\"c\":{}}",
),
(
treemap![
"a".to_string() => treemap![
"a".to_string() => treemap!["a" => vec![1,2,3]],
"b".to_string() => treemap![],
"c".to_string() => treemap![],
"a".to_owned() => treemap![
"a".to_owned() => treemap!["a" => vec![1,2,3]],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![],
],
"b".to_string() => treemap![],
"c".to_string() => treemap![],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![],
],
"{\"a\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}},\"b\":{},\"c\":{}}",
),
(
treemap![
"a".to_string() => treemap![],
"b".to_string() => treemap![
"a".to_string() => treemap!["a" => vec![1,2,3]],
"b".to_string() => treemap![],
"c".to_string() => treemap![],
"a".to_owned() => treemap![],
"b".to_owned() => treemap![
"a".to_owned() => treemap!["a" => vec![1,2,3]],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![],
],
"c".to_string() => treemap![],
"c".to_owned() => treemap![],
],
"{\"a\":{},\"b\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}},\"c\":{}}",
),
(
treemap![
"a".to_string() => treemap![],
"b".to_string() => treemap![],
"c".to_string() => treemap![
"a".to_string() => treemap!["a" => vec![1,2,3]],
"b".to_string() => treemap![],
"c".to_string() => treemap![],
"a".to_owned() => treemap![],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![
"a".to_owned() => treemap!["a" => vec![1,2,3]],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![],
],
],
"{\"a\":{},\"b\":{},\"c\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}}}",
@@ -330,9 +331,9 @@ fn test_write_object() {
test_pretty_encode_ok(&[
(
treemap![
"a".to_string() => treemap![],
"b".to_string() => treemap![],
"c".to_string() => treemap![],
"a".to_owned() => treemap![],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![],
],
pretty_str!({
"a": {},
@@ -342,13 +343,13 @@ fn test_write_object() {
),
(
treemap![
"a".to_string() => treemap![
"a".to_string() => treemap!["a" => vec![1,2,3]],
"b".to_string() => treemap![],
"c".to_string() => treemap![],
"a".to_owned() => treemap![
"a".to_owned() => treemap!["a" => vec![1,2,3]],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![],
],
"b".to_string() => treemap![],
"c".to_string() => treemap![],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![],
],
pretty_str!({
"a": {
@@ -368,13 +369,13 @@ fn test_write_object() {
),
(
treemap![
"a".to_string() => treemap![],
"b".to_string() => treemap![
"a".to_string() => treemap!["a" => vec![1,2,3]],
"b".to_string() => treemap![],
"c".to_string() => treemap![],
"a".to_owned() => treemap![],
"b".to_owned() => treemap![
"a".to_owned() => treemap!["a" => vec![1,2,3]],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![],
],
"c".to_string() => treemap![],
"c".to_owned() => treemap![],
],
pretty_str!({
"a": {},
@@ -394,12 +395,12 @@ fn test_write_object() {
),
(
treemap![
"a".to_string() => treemap![],
"b".to_string() => treemap![],
"c".to_string() => treemap![
"a".to_string() => treemap!["a" => vec![1,2,3]],
"b".to_string() => treemap![],
"c".to_string() => treemap![],
"a".to_owned() => treemap![],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![
"a".to_owned() => treemap!["a" => vec![1,2,3]],
"b".to_owned() => treemap![],
"c".to_owned() => treemap![],
],
],
pretty_str!({
@@ -423,15 +424,15 @@ fn test_write_object() {
test_pretty_encode_ok(&[
(treemap!(), "{}"),
(
treemap!("a".to_string() => true),
treemap!("a".to_owned() => true),
pretty_str!({
"a": true
}),
),
(
treemap!(
"a".to_string() => true,
"b".to_string() => false,
"a".to_owned() => true,
"b".to_owned() => false,
),
pretty_str!( {
"a": true,
@@ -492,26 +493,26 @@ fn test_write_enum() {
test_encode_ok(&[
(Animal::Dog, "\"Dog\""),
(
Animal::Frog("Henry".to_string(), vec![]),
Animal::Frog("Henry".to_owned(), vec![]),
"{\"Frog\":[\"Henry\",[]]}",
),
(
Animal::Frog("Henry".to_string(), vec![349]),
Animal::Frog("Henry".to_owned(), vec![349]),
"{\"Frog\":[\"Henry\",[349]]}",
),
(
Animal::Frog("Henry".to_string(), vec![349, 102]),
Animal::Frog("Henry".to_owned(), vec![349, 102]),
"{\"Frog\":[\"Henry\",[349,102]]}",
),
(
Animal::Cat {
age: 5,
name: "Kate".to_string(),
name: "Kate".to_owned(),
},
"{\"Cat\":{\"age\":5,\"name\":\"Kate\"}}",
),
(
Animal::AntHive(vec!["Bob".to_string(), "Stuart".to_string()]),
Animal::AntHive(vec!["Bob".to_owned(), "Stuart".to_owned()]),
"{\"AntHive\":[\"Bob\",\"Stuart\"]}",
),
]);
@@ -519,7 +520,7 @@ fn test_write_enum() {
test_pretty_encode_ok(&[
(Animal::Dog, "\"Dog\""),
(
Animal::Frog("Henry".to_string(), vec![]),
Animal::Frog("Henry".to_owned(), vec![]),
pretty_str!({
"Frog": [
"Henry",
@@ -528,7 +529,7 @@ fn test_write_enum() {
}),
),
(
Animal::Frog("Henry".to_string(), vec![349]),
Animal::Frog("Henry".to_owned(), vec![349]),
pretty_str!({
"Frog": [
"Henry",
@@ -539,7 +540,7 @@ fn test_write_enum() {
}),
),
(
Animal::Frog("Henry".to_string(), vec![349, 102]),
Animal::Frog("Henry".to_owned(), vec![349, 102]),
pretty_str!({
"Frog": [
"Henry",
@@ -1090,15 +1091,15 @@ fn test_parse_string() {
),
(
&[b'"', b'\\', b'u', 250, 48, 51, 48, b'"'],
"invalid escape at line 1 column 4",
"invalid escape at line 1 column 7",
),
(
&[b'"', b'\\', b'u', 48, 250, 51, 48, b'"'],
"invalid escape at line 1 column 5",
"invalid escape at line 1 column 7",
),
(
&[b'"', b'\\', b'u', 48, 48, 250, 48, b'"'],
"invalid escape at line 1 column 6",
"invalid escape at line 1 column 7",
),
(
&[b'"', b'\\', b'u', 48, 48, 51, 250, b'"'],
@@ -1116,16 +1117,16 @@ fn test_parse_string() {
test_parse_ok(vec![
("\"\"", String::new()),
("\"foo\"", "foo".to_string()),
(" \"foo\" ", "foo".to_string()),
("\"\\\"\"", "\"".to_string()),
("\"\\b\"", "\x08".to_string()),
("\"\\n\"", "\n".to_string()),
("\"\\r\"", "\r".to_string()),
("\"\\t\"", "\t".to_string()),
("\"\\u12ab\"", "\u{12ab}".to_string()),
("\"\\uAB12\"", "\u{AB12}".to_string()),
("\"\\uD83C\\uDF95\"", "\u{1F395}".to_string()),
("\"foo\"", "foo".to_owned()),
(" \"foo\" ", "foo".to_owned()),
("\"\\\"\"", "\"".to_owned()),
("\"\\b\"", "\x08".to_owned()),
("\"\\n\"", "\n".to_owned()),
("\"\\r\"", "\r".to_owned()),
("\"\\t\"", "\t".to_owned()),
("\"\\u12ab\"", "\u{12ab}".to_owned()),
("\"\\uAB12\"", "\u{AB12}".to_owned()),
("\"\\uD83C\\uDF95\"", "\u{1F395}".to_owned()),
]);
}
@@ -1183,24 +1184,24 @@ fn test_parse_object() {
test_parse_ok(vec![
("{}", treemap!()),
("{ }", treemap!()),
("{\"a\":3}", treemap!("a".to_string() => 3u64)),
("{ \"a\" : 3 }", treemap!("a".to_string() => 3)),
("{\"a\":3}", treemap!("a".to_owned() => 3u64)),
("{ \"a\" : 3 }", treemap!("a".to_owned() => 3)),
(
"{\"a\":3,\"b\":4}",
treemap!("a".to_string() => 3, "b".to_string() => 4),
treemap!("a".to_owned() => 3, "b".to_owned() => 4),
),
(
" { \"a\" : 3 , \"b\" : 4 } ",
treemap!("a".to_string() => 3, "b".to_string() => 4),
treemap!("a".to_owned() => 3, "b".to_owned() => 4),
),
]);
test_parse_ok(vec![(
"{\"a\": {\"b\": 3, \"c\": 4}}",
treemap!(
"a".to_string() => treemap!(
"b".to_string() => 3u64,
"c".to_string() => 4,
"a".to_owned() => treemap!(
"b".to_owned() => 3u64,
"c".to_owned() => 4,
),
),
)]);
@@ -1247,7 +1248,7 @@ fn test_parse_struct() {
inner: vec![Inner {
a: (),
b: 2,
c: vec!["abc".to_string(), "xyz".to_string()],
c: vec!["abc".to_owned(), "xyz".to_owned()],
}],
},
),
@@ -1268,7 +1269,7 @@ fn test_parse_struct() {
inner: vec![Inner {
a: (),
b: 2,
c: vec!["abc".to_string(), "xyz".to_string()],
c: vec!["abc".to_owned(), "xyz".to_owned()],
}],
}
);
@@ -1282,7 +1283,7 @@ fn test_parse_struct() {
fn test_parse_option() {
test_parse_ok(vec![
("null", None::<String>),
("\"jodhpurs\"", Some("jodhpurs".to_string())),
("\"jodhpurs\"", Some("jodhpurs".to_owned())),
]);
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@@ -1337,29 +1338,29 @@ fn test_parse_enum() {
(" \"Dog\" ", Animal::Dog),
(
"{\"Frog\":[\"Henry\",[]]}",
Animal::Frog("Henry".to_string(), vec![]),
Animal::Frog("Henry".to_owned(), vec![]),
),
(
" { \"Frog\": [ \"Henry\" , [ 349, 102 ] ] } ",
Animal::Frog("Henry".to_string(), vec![349, 102]),
Animal::Frog("Henry".to_owned(), vec![349, 102]),
),
(
"{\"Cat\": {\"age\": 5, \"name\": \"Kate\"}}",
Animal::Cat {
age: 5,
name: "Kate".to_string(),
name: "Kate".to_owned(),
},
),
(
" { \"Cat\" : { \"age\" : 5 , \"name\" : \"Kate\" } } ",
Animal::Cat {
age: 5,
name: "Kate".to_string(),
name: "Kate".to_owned(),
},
),
(
" { \"AntHive\" : [\"Bob\", \"Stuart\"] } ",
Animal::AntHive(vec!["Bob".to_string(), "Stuart".to_string()]),
Animal::AntHive(vec!["Bob".to_owned(), "Stuart".to_owned()]),
),
]);
@@ -1376,8 +1377,8 @@ fn test_parse_enum() {
"}"
),
treemap!(
"a".to_string() => Animal::Dog,
"b".to_string() => Animal::Frog("Henry".to_string(), vec![]),
"a".to_owned() => Animal::Dog,
"b".to_owned() => Animal::Frog("Henry".to_owned(), vec![]),
),
)]);
}
@@ -1652,7 +1653,7 @@ fn test_deserialize_from_stream() {
let mut stream = TcpStream::connect("localhost:20000").unwrap();
let request = Message {
message: "hi there".to_string(),
message: "hi there".to_owned(),
};
to_writer(&mut stream, &request).unwrap();
@@ -1678,20 +1679,20 @@ fn test_serialize_rejects_adt_keys() {
fn test_bytes_ser() {
let buf = vec![];
let bytes = Bytes::new(&buf);
assert_eq!(to_string(&bytes).unwrap(), "[]".to_string());
assert_eq!(to_string(&bytes).unwrap(), "[]".to_owned());
let buf = vec![1, 2, 3];
let bytes = Bytes::new(&buf);
assert_eq!(to_string(&bytes).unwrap(), "[1,2,3]".to_string());
assert_eq!(to_string(&bytes).unwrap(), "[1,2,3]".to_owned());
}
#[test]
fn test_byte_buf_ser() {
let bytes = ByteBuf::new();
assert_eq!(to_string(&bytes).unwrap(), "[]".to_string());
assert_eq!(to_string(&bytes).unwrap(), "[]".to_owned());
let bytes = ByteBuf::from(vec![1, 2, 3]);
assert_eq!(to_string(&bytes).unwrap(), "[1,2,3]".to_string());
assert_eq!(to_string(&bytes).unwrap(), "[1,2,3]".to_owned());
}
#[test]
@@ -1706,7 +1707,7 @@ fn test_byte_buf_de() {
}
#[test]
fn test_byte_buf_de_lone_surrogate() {
fn test_byte_buf_de_invalid_surrogates() {
let bytes = ByteBuf::from(vec![237, 160, 188]);
let v: ByteBuf = from_str(r#""\ud83c""#).unwrap();
assert_eq!(v, bytes);
@@ -1719,23 +1720,54 @@ fn test_byte_buf_de_lone_surrogate() {
let v: ByteBuf = from_str(r#""\ud83c ""#).unwrap();
assert_eq!(v, bytes);
let bytes = ByteBuf::from(vec![237, 176, 129]);
let v: ByteBuf = from_str(r#""\udc01""#).unwrap();
assert_eq!(v, bytes);
let res = from_str::<ByteBuf>(r#""\ud83c\!""#);
assert!(res.is_err());
let res = from_str::<ByteBuf>(r#""\ud83c\u""#);
assert!(res.is_err());
let res = from_str::<ByteBuf>(r#""\ud83c\ud83c""#);
assert!(res.is_err());
// lone trailing surrogate
let bytes = ByteBuf::from(vec![237, 176, 129]);
let v: ByteBuf = from_str(r#""\udc01""#).unwrap();
assert_eq!(v, bytes);
// leading surrogate followed by other leading surrogate
let bytes = ByteBuf::from(vec![237, 160, 188, 237, 160, 188]);
let v: ByteBuf = from_str(r#""\ud83c\ud83c""#).unwrap();
assert_eq!(v, bytes);
// leading surrogate followed by "a" (U+0061) in \u encoding
let bytes = ByteBuf::from(vec![237, 160, 188, 97]);
let v: ByteBuf = from_str(r#""\ud83c\u0061""#).unwrap();
assert_eq!(v, bytes);
// leading surrogate followed by U+0080
let bytes = ByteBuf::from(vec![237, 160, 188, 194, 128]);
let v: ByteBuf = from_str(r#""\ud83c\u0080""#).unwrap();
assert_eq!(v, bytes);
// leading surrogate followed by U+FFFF
let bytes = ByteBuf::from(vec![237, 160, 188, 239, 191, 191]);
let v: ByteBuf = from_str(r#""\ud83c\uffff""#).unwrap();
assert_eq!(v, bytes);
}
#[test]
fn test_byte_buf_de_surrogate_pair() {
// leading surrogate followed by trailing surrogate
let bytes = ByteBuf::from(vec![240, 159, 128, 128]);
let v: ByteBuf = from_str(r#""\ud83c\udc00""#).unwrap();
assert_eq!(v, bytes);
// leading surrogate followed by a surrogate pair
let bytes = ByteBuf::from(vec![237, 160, 188, 240, 159, 128, 128]);
let v: ByteBuf = from_str(r#""\ud83c\ud83c\udc00""#).unwrap();
assert_eq!(v, bytes);
}
#[cfg(feature = "raw_value")]
#[test]
fn test_raw_de_lone_surrogate() {
fn test_raw_de_invalid_surrogates() {
use serde_json::value::RawValue;
assert!(from_str::<Box<RawValue>>(r#""\ud83c""#).is_ok());
@@ -1745,6 +1777,17 @@ fn test_raw_de_lone_surrogate() {
assert!(from_str::<Box<RawValue>>(r#""\udc01\!""#).is_err());
assert!(from_str::<Box<RawValue>>(r#""\udc01\u""#).is_err());
assert!(from_str::<Box<RawValue>>(r#""\ud83c\ud83c""#).is_ok());
assert!(from_str::<Box<RawValue>>(r#""\ud83c\u0061""#).is_ok());
assert!(from_str::<Box<RawValue>>(r#""\ud83c\u0080""#).is_ok());
assert!(from_str::<Box<RawValue>>(r#""\ud83c\uffff""#).is_ok());
}
#[cfg(feature = "raw_value")]
#[test]
fn test_raw_de_surrogate_pair() {
use serde_json::value::RawValue;
assert!(from_str::<Box<RawValue>>(r#""\ud83c\udc00""#).is_ok());
}
#[test]
@@ -2100,7 +2143,9 @@ fn issue_220() {
assert_eq!(from_str::<E>(r#"{"V": 0}"#).unwrap(), E::V(0));
}
macro_rules! number_partialeq_ok {
#[test]
fn test_partialeq_number() {
macro_rules! number_partialeq_ok {
($($n:expr)*) => {
$(
let value = to_value($n).unwrap();
@@ -2109,11 +2154,9 @@ macro_rules! number_partialeq_ok {
assert_eq!($n, value);
assert_ne!(value, s);
)*
};
}
}
#[test]
fn test_partialeq_number() {
number_partialeq_ok!(0 1 100
i8::MIN i8::MAX i16::MIN i16::MAX i32::MIN i32::MAX i64::MIN i64::MAX
u8::MIN u8::MAX u16::MIN u16::MAX u32::MIN u32::MAX u64::MIN u64::MAX
@@ -2124,13 +2167,6 @@ fn test_partialeq_number() {
);
}
#[test]
#[cfg(integer128)]
#[cfg(feature = "arbitrary_precision")]
fn test_partialeq_integer128() {
number_partialeq_ok!(i128::MIN i128::MAX u128::MIN u128::MAX)
}
#[test]
fn test_partialeq_string() {
let v = to_value("42").unwrap();
@@ -2318,9 +2354,9 @@ fn test_borrowed_raw_value() {
let array_from_str: Vec<&RawValue> =
serde_json::from_str(r#"["a", 42, {"foo": "bar"}, null]"#).unwrap();
assert_eq!(r#""a""#, array_from_str[0].get());
assert_eq!(r#"42"#, array_from_str[1].get());
assert_eq!("42", array_from_str[1].get());
assert_eq!(r#"{"foo": "bar"}"#, array_from_str[2].get());
assert_eq!(r#"null"#, array_from_str[3].get());
assert_eq!("null", array_from_str[3].get());
let array_to_string = serde_json::to_string(&array_from_str).unwrap();
assert_eq!(r#"["a",42,{"foo": "bar"},null]"#, array_to_string);
@@ -2397,16 +2433,16 @@ fn test_boxed_raw_value() {
let array_from_str: Vec<Box<RawValue>> =
serde_json::from_str(r#"["a", 42, {"foo": "bar"}, null]"#).unwrap();
assert_eq!(r#""a""#, array_from_str[0].get());
assert_eq!(r#"42"#, array_from_str[1].get());
assert_eq!("42", array_from_str[1].get());
assert_eq!(r#"{"foo": "bar"}"#, array_from_str[2].get());
assert_eq!(r#"null"#, array_from_str[3].get());
assert_eq!("null", array_from_str[3].get());
let array_from_reader: Vec<Box<RawValue>> =
serde_json::from_reader(br#"["a", 42, {"foo": "bar"}, null]"#.as_ref()).unwrap();
assert_eq!(r#""a""#, array_from_reader[0].get());
assert_eq!(r#"42"#, array_from_reader[1].get());
assert_eq!("42", array_from_reader[1].get());
assert_eq!(r#"{"foo": "bar"}"#, array_from_reader[2].get());
assert_eq!(r#"null"#, array_from_reader[3].get());
assert_eq!("null", array_from_reader[3].get());
let array_to_string = serde_json::to_string(&array_from_str).unwrap();
assert_eq!(r#"["a",42,{"foo": "bar"},null]"#, array_to_string);
@@ -2503,3 +2539,22 @@ fn hash_positive_and_negative_zero() {
assert_eq!(rand.hash_one(k1), rand.hash_one(k2));
}
}
#[test]
fn test_control_character_search() {
// Different space circumstances
for n in 0..16 {
for m in 0..16 {
test_parse_err::<String>(&[(
&format!("\"{}\n{}\"", " ".repeat(n), " ".repeat(m)),
"control character (\\u0000-\\u001F) found while parsing a string at line 2 column 0",
)]);
}
}
// Multiple occurrences
test_parse_err::<String>(&[(
"\"\t\n\r\"",
"control character (\\u0000-\\u001F) found while parsing a string at line 1 column 2",
)]);
}

View File

@@ -9,4 +9,4 @@ note: while trying to match `@`
|
| (@array [$($elems:expr,)*]) => {
| ^
= note: this error originates in the macro `json_internal` which comes from the expansion of the macro `json` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the macro `$crate::json_internal` which comes from the expansion of the macro `json` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@@ -1,4 +1,4 @@
error: no rules expected the token `"2"`
error: no rules expected `"2"`
--> tests/ui/missing_comma.rs:4:21
|
4 | json!({ "1": "" "2": "" });

View File

@@ -9,4 +9,4 @@ note: while trying to match `@`
|
| (@array [$($elems:expr,)*]) => {
| ^
= note: this error originates in the macro `json_internal` which comes from the expansion of the macro `json` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the macro `$crate::json_internal` which comes from the expansion of the macro `json` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@@ -1,4 +1,4 @@
error: no rules expected the token `~`
error: no rules expected `~`
--> tests/ui/parse_expr.rs:4:19
|
4 | json!({ "a" : ~ });

View File

@@ -1,4 +1,4 @@
error: no rules expected the token `=>`
error: no rules expected `=>`
--> tests/ui/unexpected_after_array_element.rs:4:18
|
4 | json!([ true => ]);

View File

@@ -1,4 +1,4 @@
error: no rules expected the token `=>`
error: no rules expected `=>`
--> tests/ui/unexpected_after_map_entry.rs:4:23
|
4 | json!({ "k": true => });

View File

@@ -1,4 +1,4 @@
error: no rules expected the token `:`
error: no rules expected `:`
--> tests/ui/unexpected_colon.rs:4:13
|
4 | json!({ : true });

View File

@@ -1,4 +1,4 @@
error: no rules expected the token `,`
error: no rules expected `,`
--> tests/ui/unexpected_comma.rs:4:17
|
4 | json!({ "a" , "b": true });