aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid LeGare <legare@google.com>2022-03-02 16:21:22 +0000
committerDavid LeGare <legare@google.com>2022-03-02 16:21:22 +0000
commit2f2c465ed15d06f9bac021f14c63506cfe700ae9 (patch)
tree58f7f050cf3633807c295fb927d3752b7b5a1a0d /src
parent88d364f35e6339938bed10e0272e4cbd0aa70f3f (diff)
downloadserde_json-2f2c465ed15d06f9bac021f14c63506cfe700ae9.tar.gz
Update serde_json to 1.0.79
Test: cd external/rust/crates && atest --host -c Change-Id: Ic547cf00640b27bac6afe4f77c3c546d472c3d6e
Diffstat (limited to 'src')
-rw-r--r--src/de.rs54
-rw-r--r--src/error.rs9
-rw-r--r--src/io/core.rs4
-rw-r--r--src/lexical/algorithm.rs2
-rw-r--r--src/lexical/bhcomp.rs2
-rw-r--r--src/lexical/bignum.rs2
-rw-r--r--src/lexical/float.rs2
-rw-r--r--src/lexical/math.rs11
-rw-r--r--src/lexical/num.rs2
-rw-r--r--src/lexical/rounding.rs2
-rw-r--r--src/lexical/shift.rs2
-rw-r--r--src/lib.rs76
-rw-r--r--src/map.rs44
-rw-r--r--src/number.rs44
-rw-r--r--src/raw.rs21
-rw-r--r--src/read.rs133
-rw-r--r--src/ser.rs17
-rw-r--r--src/value/de.rs10
-rw-r--r--src/value/from.rs6
-rw-r--r--src/value/index.rs9
-rw-r--r--src/value/mod.rs8
-rw-r--r--src/value/partial_eq.rs2
-rw-r--r--src/value/ser.rs13
23 files changed, 301 insertions, 174 deletions
diff --git a/src/de.rs b/src/de.rs
index a2f34b9..ffd0d48 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -3,10 +3,16 @@
use crate::error::{Error, ErrorCode, Result};
#[cfg(feature = "float_roundtrip")]
use crate::lexical;
-use crate::lib::str::FromStr;
-use crate::lib::*;
use crate::number::Number;
use crate::read::{self, Fused, Reference};
+use alloc::string::String;
+use alloc::vec::Vec;
+#[cfg(feature = "float_roundtrip")]
+use core::iter;
+use core::iter::FusedIterator;
+use core::marker::PhantomData;
+use core::result;
+use core::str::FromStr;
use serde::de::{self, Expected, Unexpected};
use serde::{forward_to_deserialize_any, serde_if_integer128};
@@ -87,7 +93,9 @@ impl<'a> Deserializer<read::StrRead<'a>> {
macro_rules! overflow {
($a:ident * 10 + $b:ident, $c:expr) => {
- $a >= $c / 10 && ($a > $c / 10 || $b > $c % 10)
+ match $c {
+ c => $a >= c / 10 && ($a > c / 10 || $b > c % 10),
+ }
};
}
@@ -856,6 +864,15 @@ impl<'de, R: Read<'de>> Deserializer<R> {
buf.push('-');
}
self.scan_integer(&mut buf)?;
+ if positive {
+ if let Ok(unsigned) = buf.parse() {
+ return Ok(ParserNumber::U64(unsigned));
+ }
+ } else {
+ if let Ok(signed) = buf.parse() {
+ return Ok(ParserNumber::I64(signed));
+ }
+ }
Ok(ParserNumber::String(buf))
}
@@ -1560,7 +1577,8 @@ impl<'de, 'a, R: Read<'de>> de::Deserializer<'de> for &'a mut Deserializer<R> {
///
/// # Examples
///
- /// You can use this to parse JSON strings containing invalid UTF-8 bytes.
+ /// You can use this to parse JSON strings containing invalid UTF-8 bytes,
+ /// or unpaired surrogates.
///
/// ```
/// use serde_bytes::ByteBuf;
@@ -1580,20 +1598,18 @@ impl<'de, 'a, R: Read<'de>> de::Deserializer<'de> for &'a mut Deserializer<R> {
/// ```
///
/// Backslash escape sequences like `\n` are still interpreted and required
- /// to be valid, and `\u` escape sequences are required to represent valid
- /// Unicode code points.
+ /// to be valid. `\u` escape sequences are required to represent a valid
+ /// Unicode code point or lone surrogate.
///
/// ```
/// use serde_bytes::ByteBuf;
///
- /// fn look_at_bytes() {
- /// let json_data = b"\"invalid unicode surrogate: \\uD801\"";
- /// let parsed: Result<ByteBuf, _> = serde_json::from_slice(json_data);
- ///
- /// assert!(parsed.is_err());
- ///
- /// let expected_msg = "unexpected end of hex escape at line 1 column 35";
- /// assert_eq!(expected_msg, parsed.unwrap_err().to_string());
+ /// fn look_at_bytes() -> Result<(), serde_json::Error> {
+ /// let json_data = b"\"lone surrogate: \\uD801\"";
+ /// let bytes: ByteBuf = serde_json::from_slice(json_data)?;
+ /// let expected = b"lone surrogate: \xED\xA0\x81";
+ /// assert_eq!(expected, bytes.as_slice());
+ /// Ok(())
/// }
/// #
/// # look_at_bytes();
@@ -2168,10 +2184,18 @@ where
}
#[inline]
- fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
+ fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
+ #[cfg(feature = "raw_value")]
+ {
+ if name == crate::raw::TOKEN {
+ return self.de.deserialize_raw_value(visitor);
+ }
+ }
+
+ let _ = name;
visitor.visit_newtype_struct(self)
}
diff --git a/src/error.rs b/src/error.rs
index 4219d32..6390c43 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,9 +1,14 @@
//! When serializing or deserializing JSON goes wrong.
use crate::io;
-use crate::lib::str::FromStr;
-use crate::lib::*;
+use alloc::boxed::Box;
+use alloc::string::{String, ToString};
+use core::fmt::{self, Debug, Display};
+use core::result;
+use core::str::FromStr;
use serde::{de, ser};
+#[cfg(feature = "std")]
+use std::error;
/// This type represents all possible errors that can occur when serializing or
/// deserializing JSON data.
diff --git a/src/io/core.rs b/src/io/core.rs
index 97354eb..465ab8b 100644
--- a/src/io/core.rs
+++ b/src/io/core.rs
@@ -1,7 +1,9 @@
//! Reimplements core logic and types from `std::io` in an `alloc`-friendly
//! fashion.
-use crate::lib::*;
+use alloc::vec::Vec;
+use core::fmt::{self, Display};
+use core::result;
pub enum ErrorKind {
Other,
diff --git a/src/lexical/algorithm.rs b/src/lexical/algorithm.rs
index d01e5b9..a2cbf18 100644
--- a/src/lexical/algorithm.rs
+++ b/src/lexical/algorithm.rs
@@ -133,7 +133,7 @@ where
let shift = fp.normalize();
errors <<= shift;
- u64::error_is_accurate::<F>(errors, &fp)
+ u64::error_is_accurate::<F>(errors, fp)
}
}
diff --git a/src/lexical/bhcomp.rs b/src/lexical/bhcomp.rs
index 6d76c59..1f2a7bb 100644
--- a/src/lexical/bhcomp.rs
+++ b/src/lexical/bhcomp.rs
@@ -12,7 +12,7 @@ use super::float::*;
use super::math::*;
use super::num::*;
use super::rounding::*;
-use crate::lib::{cmp, mem};
+use core::{cmp, mem};
// MANTISSA
diff --git a/src/lexical/bignum.rs b/src/lexical/bignum.rs
index dee4e68..f9551f5 100644
--- a/src/lexical/bignum.rs
+++ b/src/lexical/bignum.rs
@@ -3,7 +3,7 @@
//! Big integer type definition.
use super::math::*;
-use crate::lib::Vec;
+use alloc::vec::Vec;
/// Storage for a big integer type.
#[derive(Clone, PartialEq, Eq)]
diff --git a/src/lexical/float.rs b/src/lexical/float.rs
index e320ead..2d434a2 100644
--- a/src/lexical/float.rs
+++ b/src/lexical/float.rs
@@ -108,7 +108,7 @@ impl ExtendedFloat {
F: Float,
Algorithm: FnOnce(&mut ExtendedFloat, i32),
{
- round_to_native::<F, _>(self, algorithm)
+ round_to_native::<F, _>(self, algorithm);
}
// FROM
diff --git a/src/lexical/math.rs b/src/lexical/math.rs
index 4890c0f..37cc1d2 100644
--- a/src/lexical/math.rs
+++ b/src/lexical/math.rs
@@ -9,7 +9,8 @@
use super::large_powers;
use super::num::*;
use super::small_powers::*;
-use crate::lib::{cmp, iter, mem, Vec};
+use alloc::vec::Vec;
+use core::{cmp, iter, mem};
// ALIASES
// -------
@@ -593,7 +594,7 @@ mod large {
// Iteratively add elements from y to x.
let mut carry = false;
- for (xi, yi) in (&mut x[xstart..]).iter_mut().zip(y.iter()) {
+ for (xi, yi) in x[xstart..].iter_mut().zip(y.iter()) {
// Only one op of the two can overflow, since we added at max
// Limb::max_value() + Limb::max_value(). Add the previous carry,
// and store the current carry for the next.
@@ -613,7 +614,7 @@ mod large {
/// AddAssign bigint to bigint.
#[inline]
pub fn iadd(x: &mut Vec<Limb>, y: &[Limb]) {
- iadd_impl(x, y, 0)
+ iadd_impl(x, y, 0);
}
/// Add bigint to bigint.
@@ -859,13 +860,13 @@ pub(crate) trait Math: Clone + Sized + Default {
/// Multiply by a power of 2.
#[inline]
fn imul_pow2(&mut self, n: u32) {
- self.ishl(n as usize)
+ self.ishl(n as usize);
}
/// Multiply by a power of 5.
#[inline]
fn imul_pow5(&mut self, n: u32) {
- small::imul_pow5(self.data_mut(), n)
+ small::imul_pow5(self.data_mut(), n);
}
/// MulAssign by a power of 10.
diff --git a/src/lexical/num.rs b/src/lexical/num.rs
index 27c78ed..e47e003 100644
--- a/src/lexical/num.rs
+++ b/src/lexical/num.rs
@@ -2,7 +2,7 @@
//! Utilities for Rust numbers.
-use crate::lib::ops;
+use core::ops;
/// Precalculated values of radix**i for i in range [0, arr.len()-1].
/// Each value can be **exactly** represented as that type.
diff --git a/src/lexical/rounding.rs b/src/lexical/rounding.rs
index d2704c9..6ec1292 100644
--- a/src/lexical/rounding.rs
+++ b/src/lexical/rounding.rs
@@ -5,7 +5,7 @@
use super::float::ExtendedFloat;
use super::num::*;
use super::shift::*;
-use crate::lib::mem;
+use core::mem;
// MASKS
diff --git a/src/lexical/shift.rs b/src/lexical/shift.rs
index b0bd469..a0bae01 100644
--- a/src/lexical/shift.rs
+++ b/src/lexical/shift.rs
@@ -3,7 +3,7 @@
//! Bit-shift helpers.
use super::float::ExtendedFloat;
-use crate::lib::mem;
+use core::mem;
// Shift extended-precision float right `shift` bytes.
#[inline]
diff --git a/src/lib.rs b/src/lib.rs
index 319ce71..63846e7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -300,10 +300,10 @@
//! [macro]: https://docs.serde.rs/serde_json/macro.json.html
//! [`serde-json-core`]: https://github.com/rust-embedded-community/serde-json-core
-#![doc(html_root_url = "https://docs.rs/serde_json/1.0.68")]
-#![deny(clippy::all, clippy::pedantic)]
+#![doc(html_root_url = "https://docs.rs/serde_json/1.0.79")]
// Ignored clippy lints
#![allow(
+ clippy::collapsible_else_if,
clippy::comparison_chain,
clippy::deprecated_cfg_attr,
clippy::doc_markdown,
@@ -313,6 +313,10 @@
clippy::match_like_matches_macro,
clippy::match_single_binding,
clippy::needless_doctest_main,
+ clippy::needless_late_init,
+ // clippy bug: https://github.com/rust-lang/rust-clippy/issues/8366
+ clippy::ptr_arg,
+ clippy::return_self_not_must_use,
clippy::transmute_ptr_to_ptr,
clippy::unnecessary_wraps,
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
@@ -320,6 +324,8 @@
)]
// Ignored clippy_pedantic lints
#![allow(
+ // buggy
+ clippy::iter_not_returning_iterator, // https://github.com/rust-lang/rust-clippy/issues/8285
// Deserializer::from_str, into_iter
clippy::should_implement_trait,
// integer and float ser/de requires these sorts of casts
@@ -359,65 +365,8 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_cfg))]
-////////////////////////////////////////////////////////////////////////////////
-
-#[cfg(not(feature = "std"))]
extern crate alloc;
-/// A facade around all the types we need from the `std`, `core`, and `alloc`
-/// crates. This avoids elaborate import wrangling having to happen in every
-/// module.
-mod lib {
- mod core {
- #[cfg(not(feature = "std"))]
- pub use core::*;
- #[cfg(feature = "std")]
- pub use std::*;
- }
-
- pub use self::core::cell::{Cell, RefCell};
- pub use self::core::clone::{self, Clone};
- pub use self::core::convert::{self, From, Into};
- pub use self::core::default::{self, Default};
- pub use self::core::fmt::{self, Debug, Display};
- pub use self::core::hash::{self, Hash};
- pub use self::core::iter::FusedIterator;
- pub use self::core::marker::{self, PhantomData};
- pub use self::core::ops::{Bound, RangeBounds};
- pub use self::core::result::{self, Result};
- pub use self::core::{borrow, char, cmp, iter, mem, num, ops, slice, str};
-
- #[cfg(not(feature = "std"))]
- pub use alloc::borrow::{Cow, ToOwned};
- #[cfg(feature = "std")]
- pub use std::borrow::{Cow, ToOwned};
-
- #[cfg(not(feature = "std"))]
- pub use alloc::string::{String, ToString};
- #[cfg(feature = "std")]
- pub use std::string::{String, ToString};
-
- #[cfg(not(feature = "std"))]
- pub use alloc::vec::{self, Vec};
- #[cfg(feature = "std")]
- pub use std::vec::{self, Vec};
-
- #[cfg(not(feature = "std"))]
- pub use alloc::boxed::Box;
- #[cfg(feature = "std")]
- pub use std::boxed::Box;
-
- #[cfg(not(feature = "std"))]
- pub use alloc::collections::{btree_map, BTreeMap};
- #[cfg(feature = "std")]
- pub use std::collections::{btree_map, BTreeMap};
-
- #[cfg(feature = "std")]
- pub use std::error;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
#[cfg(feature = "std")]
#[doc(inline)]
pub use crate::de::from_reader;
@@ -436,15 +385,12 @@ pub use crate::value::{from_value, to_value, Map, Number, Value};
// We only use our own error type; no need for From conversions provided by the
// standard library's try! macro. This reduces lines of LLVM IR by 4%.
macro_rules! tri {
- ($e:expr) => {
+ ($e:expr $(,)?) => {
match $e {
- crate::lib::Result::Ok(val) => val,
- crate::lib::Result::Err(err) => return crate::lib::Result::Err(err),
+ core::result::Result::Ok(val) => val,
+ core::result::Result::Err(err) => return core::result::Result::Err(err),
}
};
- ($e:expr,) => {
- tri!($e)
- };
}
#[macro_use]
diff --git a/src/map.rs b/src/map.rs
index 716f128..146eb6a 100644
--- a/src/map.rs
+++ b/src/map.rs
@@ -6,12 +6,19 @@
//! [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html
//! [`IndexMap`]: https://docs.rs/indexmap/*/indexmap/map/struct.IndexMap.html
-use crate::lib::borrow::Borrow;
-use crate::lib::iter::FromIterator;
-use crate::lib::*;
use crate::value::Value;
+use alloc::string::String;
+use core::borrow::Borrow;
+use core::fmt::{self, Debug};
+use core::hash::Hash;
+use core::iter::{FromIterator, FusedIterator};
+#[cfg(feature = "preserve_order")]
+use core::mem;
+use core::ops;
use serde::de;
+#[cfg(not(feature = "preserve_order"))]
+use alloc::collections::{btree_map, BTreeMap};
#[cfg(feature = "preserve_order")]
use indexmap::{self, IndexMap};
@@ -94,6 +101,20 @@ impl Map<String, Value> {
self.map.get_mut(key)
}
+ /// Returns the key-value pair matching the given key.
+ ///
+ /// The key may be any borrowed form of the map's key type, but the ordering
+ /// on the borrowed form *must* match the ordering on the key type.
+ #[inline]
+ #[cfg(any(feature = "preserve_order", not(no_btreemap_get_key_value)))]
+ pub fn get_key_value<Q>(&self, key: &Q) -> Option<(&String, &Value)>
+ where
+ String: Borrow<Q>,
+ Q: ?Sized + Ord + Eq + Hash,
+ {
+ self.map.get_key_value(key)
+ }
+
/// Inserts a key-value pair into the map.
///
/// If the map did not have this key present, `None` is returned.
@@ -151,6 +172,8 @@ impl Map<String, Value> {
no_btreemap_get_key_value,
))]
{
+ use core::ops::{Bound, RangeBounds};
+
struct Key<'a, Q: ?Sized>(&'a Q);
impl<'a, Q: ?Sized> RangeBounds<Q> for Key<'a, Q> {
@@ -188,7 +211,7 @@ impl Map<String, Value> {
S: Into<String>,
{
#[cfg(not(feature = "preserve_order"))]
- use crate::lib::btree_map::Entry as EntryImpl;
+ use alloc::collections::btree_map::Entry as EntryImpl;
#[cfg(feature = "preserve_order")]
use indexmap::map::Entry as EntryImpl;
@@ -249,6 +272,19 @@ impl Map<String, Value> {
iter: self.map.values_mut(),
}
}
+
+ /// Retains only the elements specified by the predicate.
+ ///
+ /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)`
+ /// returns `false`.
+ #[cfg(not(no_btreemap_retain))]
+ #[inline]
+ pub fn retain<F>(&mut self, f: F)
+ where
+ F: FnMut(&String, &mut Value) -> bool,
+ {
+ self.map.retain(f);
+ }
}
#[allow(clippy::derivable_impls)] // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7655
diff --git a/src/number.rs b/src/number.rs
index c147618..b965271 100644
--- a/src/number.rs
+++ b/src/number.rs
@@ -1,6 +1,8 @@
use crate::de::ParserNumber;
use crate::error::Error;
-use crate::lib::*;
+use core::fmt::{self, Debug, Display};
+#[cfg(not(feature = "arbitrary_precision"))]
+use core::hash::{Hash, Hasher};
use serde::de::{self, Unexpected, Visitor};
use serde::{
forward_to_deserialize_any, serde_if_integer128, Deserialize, Deserializer, Serialize,
@@ -16,13 +18,13 @@ use serde::de::{IntoDeserializer, MapAccess};
pub(crate) const TOKEN: &str = "$serde_json::private::Number";
/// Represents a JSON number, whether integer or floating point.
-#[derive(Clone, Eq, PartialEq)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Number {
n: N,
}
#[cfg(not(feature = "arbitrary_precision"))]
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone)]
enum N {
PosInt(u64),
/// Always less than zero.
@@ -31,10 +33,42 @@ enum N {
Float(f64),
}
+#[cfg(not(feature = "arbitrary_precision"))]
+impl PartialEq for N {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (N::PosInt(a), N::PosInt(b)) => a == b,
+ (N::NegInt(a), N::NegInt(b)) => a == b,
+ (N::Float(a), N::Float(b)) => a == b,
+ _ => false,
+ }
+ }
+}
+
// Implementing Eq is fine since any float values are always finite.
#[cfg(not(feature = "arbitrary_precision"))]
impl Eq for N {}
+#[cfg(not(feature = "arbitrary_precision"))]
+impl Hash for N {
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ match *self {
+ N::PosInt(i) => i.hash(h),
+ N::NegInt(i) => i.hash(h),
+ N::Float(f) => {
+ if f == 0.0f64 {
+ // There are 2 zero representations, +0 and -0, which
+ // compare equal but have different bits. We use the +0 hash
+ // for both so that hash(+0) == hash(-0).
+ 0.0f64.to_bits().hash(h);
+ } else {
+ f.to_bits().hash(h);
+ }
+ }
+ }
+ }
+}
+
#[cfg(feature = "arbitrary_precision")]
type N = String;
@@ -130,7 +164,7 @@ impl Number {
{
for c in self.n.chars() {
if c == '.' || c == 'e' || c == 'E' {
- return self.n.parse::<f64>().ok().map_or(false, |f| f.is_finite());
+ return self.n.parse::<f64>().ok().map_or(false, f64::is_finite);
}
}
false
@@ -254,7 +288,7 @@ impl Number {
}
}
-impl fmt::Display for Number {
+impl Display for Number {
#[cfg(not(feature = "arbitrary_precision"))]
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self.n {
diff --git a/src/raw.rs b/src/raw.rs
index b8d04ee..c8377ac 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -1,5 +1,9 @@
use crate::error::Error;
-use crate::lib::*;
+use alloc::borrow::ToOwned;
+use alloc::boxed::Box;
+use alloc::string::String;
+use core::fmt::{self, Debug, Display};
+use core::mem;
use serde::de::value::BorrowedStrDeserializer;
use serde::de::{
self, Deserialize, DeserializeSeed, Deserializer, IntoDeserializer, MapAccess, Unexpected,
@@ -122,6 +126,10 @@ impl RawValue {
fn from_owned(json: Box<str>) -> Box<Self> {
unsafe { mem::transmute::<Box<str>, Box<RawValue>>(json) }
}
+
+ fn into_owned(raw_value: Box<Self>) -> Box<str> {
+ unsafe { mem::transmute::<Box<RawValue>, Box<str>>(raw_value) }
+ }
}
impl Clone for Box<RawValue> {
@@ -216,6 +224,12 @@ impl RawValue {
}
}
+impl From<Box<RawValue>> for Box<str> {
+ fn from(raw_value: Box<RawValue>) -> Self {
+ RawValue::into_owned(raw_value)
+ }
+}
+
/// Convert a `T` into a boxed `RawValue`.
///
/// # Example
@@ -271,7 +285,7 @@ impl RawValue {
#[cfg_attr(docsrs, doc(cfg(feature = "raw_value")))]
pub fn to_raw_value<T>(value: &T) -> Result<Box<RawValue>, Error>
where
- T: Serialize,
+ T: ?Sized + Serialize,
{
let json_string = crate::to_string(value)?;
Ok(RawValue::from_owned(json_string.into_boxed_str()))
@@ -435,9 +449,10 @@ impl<'de> Visitor<'de> for BoxedFromString {
where
E: de::Error,
{
- self.visit_string(s.to_owned())
+ Ok(RawValue::from_owned(s.to_owned().into_boxed_str()))
}
+ #[cfg(any(feature = "std", feature = "alloc"))]
fn visit_string<E>(self, s: String) -> Result<Self::Value, E>
where
E: de::Error,
diff --git a/src/read.rs b/src/read.rs
index 8ed3d7d..1319d89 100644
--- a/src/read.rs
+++ b/src/read.rs
@@ -1,6 +1,9 @@
use crate::error::{Error, ErrorCode, Result};
-use crate::lib::ops::Deref;
-use crate::lib::*;
+use alloc::vec::Vec;
+use core::char;
+use core::cmp;
+use core::ops::Deref;
+use core::str;
#[cfg(feature = "std")]
use crate::io;
@@ -225,7 +228,7 @@ where
return result(self, scratch);
}
b'\\' => {
- tri!(parse_escape(self, scratch));
+ tri!(parse_escape(self, validate, scratch));
}
_ => {
if validate {
@@ -465,7 +468,7 @@ impl<'a> SliceRead<'a> {
b'\\' => {
scratch.extend_from_slice(&self.slice[start..self.index]);
self.index += 1;
- tri!(parse_escape(self, scratch));
+ tri!(parse_escape(self, validate, scratch));
start = self.index;
}
_ => {
@@ -654,8 +657,9 @@ impl<'a> Read<'a> for StrRead<'a> {
fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference<'a, 's, str>> {
self.delegate.parse_str_bytes(scratch, true, |_, bytes| {
- // The input is assumed to be valid UTF-8 and the \u-escapes are
- // checked along the way, so don't need to check here.
+ // The deserialization input came in as &str with a UTF-8 guarantee,
+ // and the \u-escapes are checked along the way, so don't need to
+ // check here.
Ok(unsafe { str::from_utf8_unchecked(bytes) })
})
}
@@ -677,7 +681,7 @@ impl<'a> Read<'a> for StrRead<'a> {
#[cfg(feature = "raw_value")]
fn begin_raw_buffering(&mut self) {
- self.delegate.begin_raw_buffering()
+ self.delegate.begin_raw_buffering();
}
#[cfg(feature = "raw_value")]
@@ -753,7 +757,7 @@ where
#[cfg(feature = "raw_value")]
fn begin_raw_buffering(&mut self) {
- R::begin_raw_buffering(self)
+ R::begin_raw_buffering(self);
}
#[cfg(feature = "raw_value")]
@@ -816,6 +820,16 @@ where
}
}
+fn peek_or_eof<'de, R>(read: &mut R) -> Result<u8>
+where
+ R: ?Sized + Read<'de>,
+{
+ match tri!(read.peek()) {
+ Some(b) => Ok(b),
+ None => error(read, ErrorCode::EofWhileParsingString),
+ }
+}
+
fn error<'de, R, T>(read: &R, reason: ErrorCode) -> Result<T>
where
R: ?Sized + Read<'de>,
@@ -830,7 +844,11 @@ fn as_str<'de, 's, R: Read<'de>>(read: &R, slice: &'s [u8]) -> Result<&'s str> {
/// Parses a JSON escape sequence and appends it into the scratch space. Assumes
/// the previous byte read was a backslash.
-fn parse_escape<'de, R: Read<'de>>(read: &mut R, scratch: &mut Vec<u8>) -> Result<()> {
+fn parse_escape<'de, R: Read<'de>>(
+ read: &mut R,
+ validate: bool,
+ scratch: &mut Vec<u8>,
+) -> Result<()> {
let ch = tri!(next_or_eof(read));
match ch {
@@ -843,19 +861,56 @@ fn parse_escape<'de, R: Read<'de>>(read: &mut R, scratch: &mut Vec<u8>) -> Resul
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,
+ ]);
+ }
+
let c = match tri!(read.decode_hex_escape()) {
- 0xDC00..=0xDFFF => {
- return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape);
+ n @ 0xDC00..=0xDFFF => {
+ return if validate {
+ error(read, ErrorCode::LoneLeadingSurrogateInHexEscape)
+ } else {
+ encode_surrogate(scratch, n);
+ Ok(())
+ };
}
- // Non-BMP characters are encoded as a sequence of
- // two hex escapes, representing UTF-16 surrogates.
+ // 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 => {
- if tri!(next_or_eof(read)) != b'\\' {
- return error(read, ErrorCode::UnexpectedEndOfHexEscape);
+ if tri!(peek_or_eof(read)) == b'\\' {
+ read.discard();
+ } else {
+ return if validate {
+ read.discard();
+ error(read, ErrorCode::UnexpectedEndOfHexEscape)
+ } else {
+ encode_surrogate(scratch, n1);
+ Ok(())
+ };
}
- if tri!(next_or_eof(read)) != b'u' {
- return error(read, ErrorCode::UnexpectedEndOfHexEscape);
+
+ if tri!(peek_or_eof(read)) == b'u' {
+ read.discard();
+ } else {
+ return if validate {
+ 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.
+ parse_escape(read, validate, scratch)
+ };
}
let n2 = tri!(read.decode_hex_escape());
@@ -874,12 +929,9 @@ fn parse_escape<'de, R: Read<'de>>(read: &mut R, scratch: &mut Vec<u8>) -> Resul
}
}
- n => match char::from_u32(n as u32) {
- Some(c) => c,
- None => {
- return error(read, ErrorCode::InvalidUnicodeCodePoint);
- }
- },
+ // Every u16 outside of the surrogate ranges above is guaranteed
+ // to be a legal char.
+ n => char::from_u32(n as u32).unwrap(),
};
scratch.extend_from_slice(c.encode_utf8(&mut [0_u8; 4]).as_bytes());
@@ -903,36 +955,13 @@ where
match ch {
b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't' => {}
b'u' => {
- let n = match tri!(read.decode_hex_escape()) {
- 0xDC00..=0xDFFF => {
- return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape);
- }
+ // At this point we don't care if the codepoint is valid. We just
+ // want to consume it. We don't actually know what is valid or not
+ // at this point, because that depends on if this string will
+ // ultimately be parsed into a string or a byte buffer in the "real"
+ // parse.
- // Non-BMP characters are encoded as a sequence of
- // two hex escapes, representing UTF-16 surrogates.
- n1 @ 0xD800..=0xDBFF => {
- if tri!(next_or_eof(read)) != b'\\' {
- return error(read, ErrorCode::UnexpectedEndOfHexEscape);
- }
- if tri!(next_or_eof(read)) != b'u' {
- return error(read, ErrorCode::UnexpectedEndOfHexEscape);
- }
-
- let n2 = tri!(read.decode_hex_escape());
-
- if n2 < 0xDC00 || n2 > 0xDFFF {
- return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape);
- }
-
- (((n1 - 0xD800) as u32) << 10 | (n2 - 0xDC00) as u32) + 0x1_0000
- }
-
- n => n as u32,
- };
-
- if char::from_u32(n).is_none() {
- return error(read, ErrorCode::InvalidUnicodeCodePoint);
- }
+ tri!(read.decode_hex_escape());
}
_ => {
return error(read, ErrorCode::InvalidEscape);
diff --git a/src/ser.rs b/src/ser.rs
index 54b0bf2..db77cd8 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -2,8 +2,10 @@
use crate::error::{Error, ErrorCode, Result};
use crate::io;
-use crate::lib::num::FpCategory;
-use crate::lib::*;
+use alloc::string::{String, ToString};
+use alloc::vec::Vec;
+use core::fmt::{self, Display};
+use core::num::FpCategory;
use serde::ser::{self, Impossible, Serialize};
use serde::serde_if_integer128;
@@ -756,7 +758,7 @@ where
#[cfg(feature = "arbitrary_precision")]
Compound::Number { ref mut ser, .. } => {
if key == crate::number::TOKEN {
- tri!(value.serialize(NumberStrEmitter(&mut *ser)));
+ tri!(value.serialize(NumberStrEmitter(ser)));
Ok(())
} else {
Err(invalid_number())
@@ -765,7 +767,7 @@ where
#[cfg(feature = "raw_value")]
Compound::RawValue { ref mut ser, .. } => {
if key == crate::raw::TOKEN {
- tri!(value.serialize(RawValueStrEmitter(&mut *ser)));
+ tri!(value.serialize(RawValueStrEmitter(ser)));
Ok(())
} else {
Err(invalid_raw_value())
@@ -1546,6 +1548,13 @@ impl<'a, W: io::Write, F: Formatter> ser::Serializer for RawValueStrEmitter<'a,
) -> Result<Self::SerializeStructVariant> {
Err(ser::Error::custom("expected RawValue"))
}
+
+ fn collect_str<T>(self, value: &T) -> Result<Self::Ok>
+ where
+ T: ?Sized + Display,
+ {
+ self.serialize_str(&value.to_string())
+ }
}
/// Represents a character escape code in a type-safe manner.
diff --git a/src/value/de.rs b/src/value/de.rs
index 24ca826..75e49df 100644
--- a/src/value/de.rs
+++ b/src/value/de.rs
@@ -1,9 +1,15 @@
use crate::error::Error;
-use crate::lib::str::FromStr;
-use crate::lib::*;
use crate::map::Map;
use crate::number::Number;
use crate::value::Value;
+use alloc::borrow::{Cow, ToOwned};
+use alloc::string::String;
+#[cfg(feature = "raw_value")]
+use alloc::string::ToString;
+use alloc::vec::{self, Vec};
+use core::fmt;
+use core::slice;
+use core::str::FromStr;
use serde::de::{
self, Deserialize, DeserializeSeed, EnumAccess, Expected, IntoDeserializer, MapAccess,
SeqAccess, Unexpected, VariantAccess, Visitor,
diff --git a/src/value/from.rs b/src/value/from.rs
index 59e09fd..7b37ef6 100644
--- a/src/value/from.rs
+++ b/src/value/from.rs
@@ -1,8 +1,10 @@
use super::Value;
-use crate::lib::iter::FromIterator;
-use crate::lib::*;
use crate::map::Map;
use crate::number::Number;
+use alloc::borrow::Cow;
+use alloc::string::{String, ToString};
+use alloc::vec::Vec;
+use core::iter::FromIterator;
#[cfg(feature = "arbitrary_precision")]
use serde::serde_if_integer128;
diff --git a/src/value/index.rs b/src/value/index.rs
index d759a1d..0d90a5d 100644
--- a/src/value/index.rs
+++ b/src/value/index.rs
@@ -1,6 +1,9 @@
use super::Value;
-use crate::lib::*;
use crate::map::Map;
+use alloc::borrow::ToOwned;
+use alloc::string::String;
+use core::fmt::{self, Display};
+use core::ops;
/// A type that can be used to index into a `serde_json::Value`.
///
@@ -133,14 +136,14 @@ mod private {
pub trait Sealed {}
impl Sealed for usize {}
impl Sealed for str {}
- impl Sealed for super::String {}
+ impl Sealed for alloc::string::String {}
impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {}
}
/// Used in panic messages.
struct Type<'a>(&'a Value);
-impl<'a> fmt::Display for Type<'a> {
+impl<'a> Display for Type<'a> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self.0 {
Value::Null => formatter.write_str("null"),
diff --git a/src/value/mod.rs b/src/value/mod.rs
index a28da66..3f00c95 100644
--- a/src/value/mod.rs
+++ b/src/value/mod.rs
@@ -92,7 +92,11 @@
use crate::error::Error;
use crate::io;
-use crate::lib::*;
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::fmt::{self, Debug, Display};
+use core::mem;
+use core::str;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
@@ -191,7 +195,7 @@ impl Debug for Value {
}
}
-impl fmt::Display for Value {
+impl Display for Value {
/// Display a JSON value as a string.
///
/// ```
diff --git a/src/value/partial_eq.rs b/src/value/partial_eq.rs
index 354ea5a..b4ef84c 100644
--- a/src/value/partial_eq.rs
+++ b/src/value/partial_eq.rs
@@ -1,5 +1,5 @@
use super::Value;
-use crate::lib::*;
+use alloc::string::String;
fn eq_i64(value: &Value, other: i64) -> bool {
value.as_i64().map_or(false, |i| i == other)
diff --git a/src/value/ser.rs b/src/value/ser.rs
index 03cb12b..179380a 100644
--- a/src/value/ser.rs
+++ b/src/value/ser.rs
@@ -1,8 +1,12 @@
use crate::error::{Error, ErrorCode, Result};
-use crate::lib::*;
use crate::map::Map;
use crate::number::Number;
use crate::value::{to_value, Value};
+use alloc::borrow::ToOwned;
+use alloc::string::{String, ToString};
+use alloc::vec::Vec;
+use core::fmt::Display;
+use core::result;
use serde::ser::{Impossible, Serialize};
#[cfg(feature = "arbitrary_precision")]
@@ -1016,4 +1020,11 @@ impl serde::ser::Serializer for RawValueEmitter {
) -> Result<Self::SerializeStructVariant> {
Err(invalid_raw_value())
}
+
+ fn collect_str<T>(self, value: &T) -> Result<Self::Ok>
+ where
+ T: ?Sized + Display,
+ {
+ self.serialize_str(&value.to_string())
+ }
}