mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-24 02:58:00 +00:00
Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ffed19243d | |||
| bb7f94df84 | |||
| ff0f467e25 | |||
| d1975f3661 | |||
| b91713e824 | |||
| 6ea446fb4b | |||
| 85c6904a93 | |||
| 2fd5212204 | |||
| 7d1bc1f0fc | |||
| cdc2fa1b9f | |||
| ac4001e590 | |||
| fbcb2230bb | |||
| 86c88bea12 | |||
| 82d0fe00fd | |||
| e61261e002 | |||
| 9fd56cd41c | |||
| f6e7366b46 | |||
| 1f9f72bc48 | |||
| e24dbc418d | |||
| 18e5b03fd1 | |||
| 5aa163f27e | |||
| 3728d3c67a | |||
| 3f48ed36cc | |||
| b6a2d07f26 | |||
| 84ad76b2e5 | |||
| e6b6602a42 | |||
| 999b94d6ae | |||
| fa6712d2bf | |||
| 012ea8eb84 | |||
| 9add5812e2 | |||
| 5fd52100b6 | |||
| 6670a309ca | |||
| b7bad3a165 | |||
| 4e002ece07 | |||
| eaccae2c46 | |||
| 990a502c39 | |||
| 661206d885 | |||
| 51d4563ed1 | |||
| 7db0982e58 | |||
| ed04824f10 | |||
| 88ee470a1c | |||
| a5ecbdb4f4 | |||
| bd588db067 | |||
| 8f09aeacdd | |||
| 0b5c56b0db | |||
| 85de92e6f7 | |||
| c858a1fa77 | |||
| d02eb22557 | |||
| 034fe25d5b | |||
| 0a230e8598 | |||
| b20214d4a0 | |||
| 34f4b68f77 | |||
| 60e08f9545 | |||
| ba46f45dc5 | |||
| 44b9567e21 | |||
| b276849ce1 | |||
| 398fba9b1e | |||
| cd6697b0e4 | |||
| c162d51866 | |||
| 78a9dbc57e | |||
| 391d3ababf | |||
| 99d9151ce9 | |||
| 5cbc8439ea | |||
| 97c350a95e | |||
| 920a77ad61 | |||
| 7a7a182ab6 | |||
| 9e1f573f88 | |||
| 094f63b86a | |||
| 42fa79455e | |||
| 104ad9a7dd | |||
| 23c14e5f33 | |||
| e80571751d | |||
| 0737474640 | |||
| 34de1e00c8 | |||
| f6eb34a830 | |||
| db3074a40f | |||
| 2e821eab4b |
@@ -158,6 +158,7 @@ jobs:
|
||||
# https://github.com/rust-lang/rust-clippy/issues/5356
|
||||
- run: cd serde && cargo clippy --features rc,unstable -- -D clippy::all -A clippy::redundant_field_names
|
||||
- run: cd serde_derive && cargo clippy -- -D clippy::all
|
||||
- run: cd serde_derive_internals && cargo clippy -- -D clippy::all
|
||||
- run: cd serde_test && cargo clippy -- -D clippy::all -A clippy::redundant_field_names
|
||||
- run: cd test_suite && cargo clippy --tests --features unstable -- -D clippy::all -A clippy::redundant_field_names
|
||||
- run: cd test_suite/no_std && cargo clippy -- -D clippy::all -A clippy::redundant_field_names
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "1.0.119" # remember to update html_root_url and serde_derive dependency
|
||||
version = "1.0.122" # remember to update html_root_url and serde_derive dependency
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
@@ -14,7 +14,7 @@ include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APAC
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
serde_derive = { version = "=1.0.119", optional = true, path = "../serde_derive" }
|
||||
serde_derive = { version = "=1.0.122", optional = true, path = "../serde_derive" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_derive = { version = "1.0", path = "../serde_derive" }
|
||||
|
||||
@@ -130,12 +130,28 @@ impl<'de> Visitor<'de> for IgnoredAny {
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
#[inline]
|
||||
fn visit_i128<E>(self, x: i128) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_u64<E>(self, x: u64) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
#[inline]
|
||||
fn visit_u128<E>(self, x: u128) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_f64<E>(self, x: f64) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
|
||||
+53
-72
@@ -1260,24 +1260,7 @@ macro_rules! parse_ip_impl {
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
struct IpAddrVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for IpAddrVisitor {
|
||||
type Value = $ty;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str($expecting)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
s.parse().map_err(Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(IpAddrVisitor)
|
||||
deserializer.deserialize_str(FromStrVisitor::new($expecting))
|
||||
} else {
|
||||
<[u8; $size]>::deserialize(deserializer).map(<$ty>::from)
|
||||
}
|
||||
@@ -1405,24 +1388,7 @@ impl<'de> Deserialize<'de> for net::IpAddr {
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
struct IpAddrVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for IpAddrVisitor {
|
||||
type Value = net::IpAddr;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("IP address")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
s.parse().map_err(Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(IpAddrVisitor)
|
||||
deserializer.deserialize_str(FromStrVisitor::new("IP address"))
|
||||
} else {
|
||||
use lib::net::IpAddr;
|
||||
deserialize_enum! {
|
||||
@@ -1449,24 +1415,7 @@ macro_rules! parse_socket_impl {
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
struct SocketAddrVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for SocketAddrVisitor {
|
||||
type Value = $ty;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str($expecting)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
s.parse().map_err(Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(SocketAddrVisitor)
|
||||
deserializer.deserialize_str(FromStrVisitor::new($expecting))
|
||||
} else {
|
||||
<(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port))
|
||||
}
|
||||
@@ -1482,24 +1431,7 @@ impl<'de> Deserialize<'de> for net::SocketAddr {
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
struct SocketAddrVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for SocketAddrVisitor {
|
||||
type Value = net::SocketAddr;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("socket address")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
s.parse().map_err(Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(SocketAddrVisitor)
|
||||
deserializer.deserialize_str(FromStrVisitor::new("socket address"))
|
||||
} else {
|
||||
use lib::net::SocketAddr;
|
||||
deserialize_enum! {
|
||||
@@ -1917,6 +1849,17 @@ impl<'de> Deserialize<'de> for Duration {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_overflow<E>(secs: u64, nanos: u32) -> Result<(), E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
static NANOS_PER_SEC: u32 = 1_000_000_000;
|
||||
match secs.checked_add((nanos / NANOS_PER_SEC) as u64) {
|
||||
Some(_) => Ok(()),
|
||||
None => Err(E::custom("overflow deserializing Duration")),
|
||||
}
|
||||
}
|
||||
|
||||
struct DurationVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for DurationVisitor {
|
||||
@@ -1942,6 +1885,7 @@ impl<'de> Deserialize<'de> for Duration {
|
||||
return Err(Error::invalid_length(1, &self));
|
||||
}
|
||||
};
|
||||
try!(check_overflow(secs, nanos));
|
||||
Ok(Duration::new(secs, nanos))
|
||||
}
|
||||
|
||||
@@ -1975,6 +1919,7 @@ impl<'de> Deserialize<'de> for Duration {
|
||||
Some(nanos) => nanos,
|
||||
None => return Err(<A::Error as Error>::missing_field("nanos")),
|
||||
};
|
||||
try!(check_overflow(secs, nanos));
|
||||
Ok(Duration::new(secs, nanos))
|
||||
}
|
||||
}
|
||||
@@ -2603,3 +2548,39 @@ atomic_impl! {
|
||||
atomic_impl! {
|
||||
AtomicI64 AtomicU64
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
struct FromStrVisitor<T> {
|
||||
expecting: &'static str,
|
||||
ty: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T> FromStrVisitor<T> {
|
||||
fn new(expecting: &'static str) -> Self {
|
||||
FromStrVisitor {
|
||||
expecting: expecting,
|
||||
ty: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de, T> Visitor<'de> for FromStrVisitor<T>
|
||||
where
|
||||
T: str::FromStr,
|
||||
T::Err: fmt::Display,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(self.expecting)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
s.parse().map_err(Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -393,7 +393,7 @@ pub enum Unexpected<'a> {
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for Unexpected<'a> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::Unexpected::*;
|
||||
match *self {
|
||||
Bool(b) => write!(formatter, "boolean `{}`", b),
|
||||
|
||||
+169
-31
@@ -25,7 +25,7 @@ use lib::*;
|
||||
|
||||
use self::private::{First, Second};
|
||||
use __private::de::size_hint;
|
||||
use de::{self, Expected, IntoDeserializer, SeqAccess};
|
||||
use de::{self, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
|
||||
use ser;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -48,7 +48,7 @@ macro_rules! impl_copy_clone {
|
||||
|
||||
/// A minimal representation of all possible errors that can occur using the
|
||||
/// `IntoDeserializer` trait.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Error {
|
||||
err: ErrorImpl,
|
||||
}
|
||||
@@ -93,16 +93,25 @@ impl ser::Error for Error {
|
||||
|
||||
impl Display for Error {
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(&self.err)
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("Serde deserialization error")
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Error {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut debug = formatter.debug_tuple("Error");
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
debug.field(&self.err);
|
||||
debug.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
@@ -126,7 +135,6 @@ where
|
||||
}
|
||||
|
||||
/// A deserializer holding a `()`.
|
||||
#[derive(Debug)]
|
||||
pub struct UnitDeserializer<E> {
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
@@ -160,6 +168,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Debug for UnitDeserializer<E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.debug_struct("UnitDeserializer").finish()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer that cannot be instantiated.
|
||||
@@ -208,7 +222,6 @@ macro_rules! primitive_deserializer {
|
||||
($ty:ty, $doc:tt, $name:ident, $method:ident $($cast:tt)*) => {
|
||||
#[doc = "A deserializer holding"]
|
||||
#[doc = $doc]
|
||||
#[derive(Debug)]
|
||||
pub struct $name<E> {
|
||||
value: $ty,
|
||||
marker: PhantomData<E>
|
||||
@@ -249,6 +262,15 @@ macro_rules! primitive_deserializer {
|
||||
visitor.$method(self.value $($cast)*)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Debug for $name<E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct(stringify!($name))
|
||||
.field("value", &self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +294,6 @@ serde_if_integer128! {
|
||||
}
|
||||
|
||||
/// A deserializer holding a `u32`.
|
||||
#[derive(Debug)]
|
||||
pub struct U32Deserializer<E> {
|
||||
value: u32,
|
||||
marker: PhantomData<E>,
|
||||
@@ -343,10 +364,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Debug for U32Deserializer<E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("U32Deserializer")
|
||||
.field("value", &self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer holding a `&str`.
|
||||
#[derive(Debug)]
|
||||
pub struct StrDeserializer<'a, E> {
|
||||
value: &'a str,
|
||||
marker: PhantomData<E>,
|
||||
@@ -417,11 +446,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> Debug for StrDeserializer<'a, E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("StrDeserializer")
|
||||
.field("value", &self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer holding a `&str` with a lifetime tied to another
|
||||
/// deserializer.
|
||||
#[derive(Debug)]
|
||||
pub struct BorrowedStrDeserializer<'de, E> {
|
||||
value: &'de str,
|
||||
marker: PhantomData<E>,
|
||||
@@ -488,11 +525,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> Debug for BorrowedStrDeserializer<'de, E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("BorrowedStrDeserializer")
|
||||
.field("value", &self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer holding a `String`.
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[derive(Debug)]
|
||||
pub struct StringDeserializer<E> {
|
||||
value: String,
|
||||
marker: PhantomData<E>,
|
||||
@@ -574,11 +619,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<E> Debug for StringDeserializer<E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("StringDeserializer")
|
||||
.field("value", &self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer holding a `Cow<str>`.
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[derive(Debug)]
|
||||
pub struct CowStrDeserializer<'a, E> {
|
||||
value: Cow<'a, str>,
|
||||
marker: PhantomData<E>,
|
||||
@@ -663,29 +717,48 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'a, E> Debug for CowStrDeserializer<'a, E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("CowStrDeserializer")
|
||||
.field("value", &self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer holding a `&[u8]` with a lifetime tied to another
|
||||
/// deserializer.
|
||||
#[derive(Debug)]
|
||||
pub struct BorrowedBytesDeserializer<'de, E> {
|
||||
value: &'de [u8],
|
||||
/// A deserializer holding a `&[u8]`. Always calls [`Visitor::visit_bytes`].
|
||||
pub struct BytesDeserializer<'a, E> {
|
||||
value: &'a [u8],
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl_copy_clone!(BorrowedBytesDeserializer<'de>);
|
||||
|
||||
impl<'de, E> BorrowedBytesDeserializer<'de, E> {
|
||||
/// Create a new borrowed deserializer from the given byte slice.
|
||||
pub fn new(value: &'de [u8]) -> BorrowedBytesDeserializer<'de, E> {
|
||||
BorrowedBytesDeserializer {
|
||||
impl<'a, E> BytesDeserializer<'a, E> {
|
||||
/// Create a new deserializer from the given bytes.
|
||||
pub fn new(value: &'a [u8]) -> Self {
|
||||
BytesDeserializer {
|
||||
value: value,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> de::Deserializer<'de> for BorrowedBytesDeserializer<'de, E>
|
||||
impl_copy_clone!(BytesDeserializer<'a>);
|
||||
|
||||
impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a [u8]
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = BytesDeserializer<'a, E>;
|
||||
|
||||
fn into_deserializer(self) -> BytesDeserializer<'a, E> {
|
||||
BytesDeserializer::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
@@ -693,7 +766,55 @@ where
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
visitor.visit_bytes(self.value)
|
||||
}
|
||||
|
||||
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 enum identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> Debug for BytesDeserializer<'a, E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("BytesDeserializer")
|
||||
.field("value", &self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A deserializer holding a `&[u8]` with a lifetime tied to another
|
||||
/// deserializer. Always calls [`Visitor::visit_borrowed_bytes`].
|
||||
pub struct BorrowedBytesDeserializer<'de, E> {
|
||||
value: &'de [u8],
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<'de, E> BorrowedBytesDeserializer<'de, E> {
|
||||
/// Create a new borrowed deserializer from the given borrowed bytes.
|
||||
pub fn new(value: &'de [u8]) -> Self {
|
||||
BorrowedBytesDeserializer {
|
||||
value: value,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_copy_clone!(BorrowedBytesDeserializer<'de>);
|
||||
|
||||
impl<'de, E> Deserializer<'de> for BorrowedBytesDeserializer<'de, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
visitor.visit_borrowed_bytes(self.value)
|
||||
}
|
||||
@@ -701,14 +822,23 @@ where
|
||||
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 ignored_any enum
|
||||
tuple_struct map struct enum identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> Debug for BorrowedBytesDeserializer<'de, E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("BorrowedBytesDeserializer")
|
||||
.field("value", &self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer that iterates over a sequence.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct SeqDeserializer<I, E> {
|
||||
iter: iter::Fuse<I>,
|
||||
count: usize,
|
||||
@@ -813,6 +943,19 @@ impl Expected for ExpectedInSeq {
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, E> Debug for SeqDeserializer<I, E>
|
||||
where
|
||||
I: Debug,
|
||||
{
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("SeqDeserializer")
|
||||
.field("iter", &self.iter)
|
||||
.field("count", &self.count)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
@@ -1108,7 +1251,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot #[derive(Debug)] because of the bound `Second<I::Item>: Debug`.
|
||||
impl<'de, I, E> Debug for MapDeserializer<'de, I, E>
|
||||
where
|
||||
I: Iterator + Debug,
|
||||
@@ -1121,8 +1263,6 @@ where
|
||||
.field("iter", &self.iter)
|
||||
.field("value", &self.value)
|
||||
.field("count", &self.count)
|
||||
.field("lifetime", &self.lifetime)
|
||||
.field("error", &self.error)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -1331,7 +1471,6 @@ mod private {
|
||||
|
||||
use de::{self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UnitOnly<E> {
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
@@ -1390,7 +1529,6 @@ mod private {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MapAsEnum<A> {
|
||||
map: A,
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/// bother with this macro and may assume support for 128-bit integers.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::__private::ser::Error;
|
||||
/// # use serde::__private::doc::Error;
|
||||
/// #
|
||||
/// # struct MySerializer;
|
||||
/// #
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Serde types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.119")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.122")]
|
||||
// Support using Serde without the standard library!
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
// Unstable functionality only if the user asks for it. For tracking and
|
||||
|
||||
+63
-36
@@ -1,5 +1,6 @@
|
||||
use lib::*;
|
||||
|
||||
use de::value::{BorrowedBytesDeserializer, BytesDeserializer};
|
||||
use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
@@ -824,15 +825,17 @@ mod content {
|
||||
/// Not public API.
|
||||
pub struct TaggedContentVisitor<'de, T> {
|
||||
tag_name: &'static str,
|
||||
expecting: &'static str,
|
||||
value: PhantomData<TaggedContent<'de, T>>,
|
||||
}
|
||||
|
||||
impl<'de, T> TaggedContentVisitor<'de, T> {
|
||||
/// Visitor for the content of an internally tagged enum with the given
|
||||
/// tag name.
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
pub fn new(name: &'static str, expecting: &'static str) -> Self {
|
||||
TaggedContentVisitor {
|
||||
tag_name: name,
|
||||
expecting: expecting,
|
||||
value: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -861,7 +864,7 @@ mod content {
|
||||
type Value = TaggedContent<'de, T>;
|
||||
|
||||
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.write_str("internally tagged enum")
|
||||
fmt.write_str(self.expecting)
|
||||
}
|
||||
|
||||
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
|
||||
@@ -2542,11 +2545,13 @@ pub trait IdentifierDeserializer<'de, E: Error> {
|
||||
fn from(self) -> Self::Deserializer;
|
||||
}
|
||||
|
||||
impl<'de, E> IdentifierDeserializer<'de, E> for u32
|
||||
pub struct Borrowed<'de, T: 'de + ?Sized>(pub &'de T);
|
||||
|
||||
impl<'de, E> IdentifierDeserializer<'de, E> for u64
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
type Deserializer = <u32 as IntoDeserializer<'de, E>>::Deserializer;
|
||||
type Deserializer = <u64 as IntoDeserializer<'de, E>>::Deserializer;
|
||||
|
||||
fn from(self) -> Self::Deserializer {
|
||||
self.into_deserializer()
|
||||
@@ -2558,20 +2563,6 @@ pub struct StrDeserializer<'a, E> {
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<'a, E> IdentifierDeserializer<'a, E> for &'a str
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
type Deserializer = StrDeserializer<'a, E>;
|
||||
|
||||
fn from(self) -> Self::Deserializer {
|
||||
StrDeserializer {
|
||||
value: self,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, E> Deserializer<'de> for StrDeserializer<'a, E>
|
||||
where
|
||||
E: Error,
|
||||
@@ -2592,26 +2583,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BytesDeserializer<'a, E> {
|
||||
value: &'a [u8],
|
||||
pub struct BorrowedStrDeserializer<'de, E> {
|
||||
value: &'de str,
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8]
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
type Deserializer = BytesDeserializer<'a, E>;
|
||||
|
||||
fn from(self) -> Self::Deserializer {
|
||||
BytesDeserializer {
|
||||
value: self,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
|
||||
impl<'de, E> Deserializer<'de> for BorrowedStrDeserializer<'de, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
@@ -2621,7 +2598,7 @@ where
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
visitor.visit_bytes(self.value)
|
||||
visitor.visit_borrowed_str(self.value)
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
@@ -2631,6 +2608,56 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> IdentifierDeserializer<'a, E> for &'a str
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
type Deserializer = StrDeserializer<'a, E>;
|
||||
|
||||
fn from(self) -> Self::Deserializer {
|
||||
StrDeserializer {
|
||||
value: self,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> IdentifierDeserializer<'de, E> for Borrowed<'de, str>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
type Deserializer = BorrowedStrDeserializer<'de, E>;
|
||||
|
||||
fn from(self) -> Self::Deserializer {
|
||||
BorrowedStrDeserializer {
|
||||
value: self.0,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8]
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
type Deserializer = BytesDeserializer<'a, E>;
|
||||
|
||||
fn from(self) -> Self::Deserializer {
|
||||
BytesDeserializer::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> IdentifierDeserializer<'de, E> for Borrowed<'de, [u8]>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
type Deserializer = BorrowedBytesDeserializer<'de, E>;
|
||||
|
||||
fn from(self) -> Self::Deserializer {
|
||||
BorrowedBytesDeserializer::new(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// A DeserializeSeed helper for implementing deserialize_in_place Visitors.
|
||||
///
|
||||
/// Wraps a mutable reference and calls deserialize_in_place on it.
|
||||
|
||||
@@ -1,3 +1,35 @@
|
||||
// Used only by Serde doc tests. Not public API.
|
||||
|
||||
use lib::*;
|
||||
|
||||
use ser;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug)]
|
||||
pub struct Error;
|
||||
|
||||
impl ser::Error for Error {
|
||||
fn custom<T>(_: T) -> Self
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __private_serialize {
|
||||
@@ -10,19 +42,6 @@ macro_rules! __private_serialize {
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __private_deserialize {
|
||||
() => {
|
||||
trait Deserialize<'de>: Sized {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: $crate::Deserializer<'de>;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Used only by Serde doc tests. Not public API.
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! __serialize_unimplemented {
|
||||
@@ -1,8 +1,9 @@
|
||||
mod macros;
|
||||
|
||||
pub mod de;
|
||||
pub mod ser;
|
||||
|
||||
// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed.
|
||||
pub mod doc;
|
||||
|
||||
pub use lib::clone::Clone;
|
||||
pub use lib::convert::{From, Into};
|
||||
pub use lib::default::Default;
|
||||
|
||||
@@ -335,33 +335,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Used only by Serde doc tests. Not public API.
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug)]
|
||||
pub struct Error;
|
||||
|
||||
impl ser::Error for Error {
|
||||
fn custom<T>(_: T) -> Self
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
mod content {
|
||||
use lib::*;
|
||||
@@ -452,7 +425,6 @@ mod content {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Content {
|
||||
Bool(bool),
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ use ser::{
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::ser::{Serializer, Impossible};
|
||||
/// # use serde::__private::ser::Error;
|
||||
/// # use serde::__private::doc::Error;
|
||||
/// #
|
||||
/// # struct MySerializer;
|
||||
/// #
|
||||
|
||||
@@ -711,7 +711,7 @@ pub trait Serializer: Sized {
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::ser::{Serializer, SerializeSeq};
|
||||
/// # use serde::__private::ser::Error;
|
||||
/// # use serde::__private::doc::Error;
|
||||
/// #
|
||||
/// # struct MySerializer;
|
||||
/// #
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "1.0.119" # remember to update html_root_url
|
||||
version = "1.0.122" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
||||
@@ -22,7 +22,7 @@ proc-macro = true
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = { version = "1.0.58", features = ["visit"] }
|
||||
syn = "1.0.60"
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0", path = "../serde" }
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::collections::HashSet;
|
||||
|
||||
use syn;
|
||||
use syn::punctuated::{Pair, Punctuated};
|
||||
use syn::visit::{self, Visit};
|
||||
|
||||
use internals::ast::{Container, Data};
|
||||
use internals::{attr, ungroup};
|
||||
@@ -112,7 +111,8 @@ pub fn with_bound(
|
||||
// parameters.
|
||||
associated_type_usage: Vec<&'ast syn::TypePath>,
|
||||
}
|
||||
impl<'ast> Visit<'ast> for FindTyParams<'ast> {
|
||||
|
||||
impl<'ast> FindTyParams<'ast> {
|
||||
fn visit_field(&mut self, field: &'ast syn::Field) {
|
||||
if let syn::Type::Path(ty) = ungroup(&field.ty) {
|
||||
if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() {
|
||||
@@ -138,7 +138,98 @@ pub fn with_bound(
|
||||
self.relevant_type_params.insert(id.clone());
|
||||
}
|
||||
}
|
||||
visit::visit_path(self, path);
|
||||
for segment in &path.segments {
|
||||
self.visit_path_segment(segment);
|
||||
}
|
||||
}
|
||||
|
||||
// Everything below is simply traversing the syntax tree.
|
||||
|
||||
fn visit_type(&mut self, ty: &'ast syn::Type) {
|
||||
match ty {
|
||||
syn::Type::Array(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::BareFn(ty) => {
|
||||
for arg in &ty.inputs {
|
||||
self.visit_type(&arg.ty);
|
||||
}
|
||||
self.visit_return_type(&ty.output);
|
||||
}
|
||||
syn::Type::Group(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::ImplTrait(ty) => {
|
||||
for bound in &ty.bounds {
|
||||
self.visit_type_param_bound(bound);
|
||||
}
|
||||
}
|
||||
syn::Type::Macro(ty) => self.visit_macro(&ty.mac),
|
||||
syn::Type::Paren(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::Path(ty) => {
|
||||
if let Some(qself) = &ty.qself {
|
||||
self.visit_type(&qself.ty);
|
||||
}
|
||||
self.visit_path(&ty.path);
|
||||
}
|
||||
syn::Type::Ptr(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::Reference(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::Slice(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::TraitObject(ty) => {
|
||||
for bound in &ty.bounds {
|
||||
self.visit_type_param_bound(bound);
|
||||
}
|
||||
}
|
||||
syn::Type::Tuple(ty) => {
|
||||
for elem in &ty.elems {
|
||||
self.visit_type(elem);
|
||||
}
|
||||
}
|
||||
|
||||
syn::Type::Infer(_) | syn::Type::Never(_) | syn::Type::Verbatim(_) => {}
|
||||
|
||||
#[cfg(test)]
|
||||
syn::Type::__TestExhaustive(_) => unimplemented!(),
|
||||
#[cfg(not(test))]
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_path_segment(&mut self, segment: &'ast syn::PathSegment) {
|
||||
self.visit_path_arguments(&segment.arguments);
|
||||
}
|
||||
|
||||
fn visit_path_arguments(&mut self, arguments: &'ast syn::PathArguments) {
|
||||
match arguments {
|
||||
syn::PathArguments::None => {}
|
||||
syn::PathArguments::AngleBracketed(arguments) => {
|
||||
for arg in &arguments.args {
|
||||
match arg {
|
||||
syn::GenericArgument::Type(arg) => self.visit_type(arg),
|
||||
syn::GenericArgument::Binding(arg) => self.visit_type(&arg.ty),
|
||||
syn::GenericArgument::Lifetime(_)
|
||||
| syn::GenericArgument::Constraint(_)
|
||||
| syn::GenericArgument::Const(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
syn::PathArguments::Parenthesized(arguments) => {
|
||||
for argument in &arguments.inputs {
|
||||
self.visit_type(argument);
|
||||
}
|
||||
self.visit_return_type(&arguments.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_return_type(&mut self, return_type: &'ast syn::ReturnType) {
|
||||
match return_type {
|
||||
syn::ReturnType::Default => {}
|
||||
syn::ReturnType::Type(_, output) => self.visit_type(output),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) {
|
||||
match bound {
|
||||
syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
|
||||
syn::TypeParamBound::Lifetime(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Type parameter should not be considered used by a macro path.
|
||||
|
||||
+113
-61
@@ -402,6 +402,7 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
|
||||
let expecting = format!("unit struct {}", params.type_name());
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
quote_block! {
|
||||
struct __Visitor;
|
||||
@@ -459,6 +460,7 @@ fn deserialize_tuple(
|
||||
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
|
||||
None => format!("tuple struct {}", params.type_name()),
|
||||
};
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let nfields = fields.len();
|
||||
|
||||
@@ -545,6 +547,7 @@ fn deserialize_tuple_in_place(
|
||||
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
|
||||
None => format!("tuple struct {}", params.type_name()),
|
||||
};
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let nfields = fields.len();
|
||||
|
||||
@@ -633,6 +636,7 @@ fn deserialize_seq(
|
||||
} else {
|
||||
format!("{} with {} elements", expecting, deserialized_count)
|
||||
};
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let mut index_in_seq = 0_usize;
|
||||
let let_values = vars.clone().zip(fields).map(|(var, field)| {
|
||||
@@ -735,6 +739,7 @@ fn deserialize_seq_in_place(
|
||||
} else {
|
||||
format!("{} with {} elements", expecting, deserialized_count)
|
||||
};
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let mut index_in_seq = 0usize;
|
||||
let write_values = fields.iter().map(|field| {
|
||||
@@ -910,6 +915,7 @@ fn deserialize_struct(
|
||||
Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident),
|
||||
None => format!("struct {}", params.type_name()),
|
||||
};
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let visit_seq = Stmts(deserialize_seq(
|
||||
&type_path, params, fields, true, cattrs, &expecting,
|
||||
@@ -1051,6 +1057,7 @@ fn deserialize_struct_in_place(
|
||||
Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident),
|
||||
None => format!("struct {}", params.type_name()),
|
||||
};
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting));
|
||||
|
||||
@@ -1203,6 +1210,7 @@ fn deserialize_externally_tagged_enum(
|
||||
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
let expecting = format!("enum {}", params.type_name());
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs);
|
||||
|
||||
@@ -1312,6 +1320,9 @@ fn deserialize_internally_tagged_enum(
|
||||
}
|
||||
});
|
||||
|
||||
let expecting = format!("internally tagged enum {}", params.type_name());
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
quote_block! {
|
||||
#variant_visitor
|
||||
|
||||
@@ -1319,7 +1330,7 @@ fn deserialize_internally_tagged_enum(
|
||||
|
||||
let __tagged = try!(_serde::Deserializer::deserialize_any(
|
||||
__deserializer,
|
||||
_serde::__private::de::TaggedContentVisitor::<__Field>::new(#tag)));
|
||||
_serde::__private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting)));
|
||||
|
||||
match __tagged.tag {
|
||||
#(#variant_arms)*
|
||||
@@ -1362,6 +1373,7 @@ fn deserialize_adjacently_tagged_enum(
|
||||
.collect();
|
||||
|
||||
let expecting = format!("adjacently tagged enum {}", params.type_name());
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
let deny_unknown_fields = cattrs.deny_unknown_fields();
|
||||
|
||||
@@ -1653,6 +1665,7 @@ fn deserialize_untagged_enum(
|
||||
"data did not match any variant of untagged enum {}",
|
||||
params.type_name()
|
||||
);
|
||||
let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg);
|
||||
|
||||
quote_block! {
|
||||
let __content = try!(<_serde::__private::de::Content as _serde::Deserialize>::deserialize(__deserializer));
|
||||
@@ -1909,7 +1922,9 @@ fn deserialize_generated_identifier(
|
||||
fields,
|
||||
is_variant,
|
||||
fallthrough,
|
||||
None,
|
||||
!is_variant && cattrs.has_flatten(),
|
||||
None,
|
||||
));
|
||||
|
||||
let lifetime = if !is_variant && cattrs.has_flatten() {
|
||||
@@ -1945,6 +1960,8 @@ fn deserialize_generated_identifier(
|
||||
}
|
||||
}
|
||||
|
||||
// Generates `Deserialize::deserialize` body for an enum with
|
||||
// `serde(field_identifier)` or `serde(variant_identifier)` attribute.
|
||||
fn deserialize_custom_identifier(
|
||||
params: &Parameters,
|
||||
variants: &[Variant],
|
||||
@@ -1959,26 +1976,38 @@ fn deserialize_custom_identifier(
|
||||
let this = ¶ms.this;
|
||||
let this = quote!(#this);
|
||||
|
||||
let (ordinary, fallthrough) = if let Some(last) = variants.last() {
|
||||
let (ordinary, fallthrough, fallthrough_borrowed) = if let Some(last) = variants.last() {
|
||||
let last_ident = &last.ident;
|
||||
if last.attrs.other() {
|
||||
// Process `serde(other)` attribute. It would always be found on the
|
||||
// last variant (checked in `check_identifier`), so all preceding
|
||||
// are ordinary variants.
|
||||
let ordinary = &variants[..variants.len() - 1];
|
||||
let fallthrough = quote!(_serde::__private::Ok(#this::#last_ident));
|
||||
(ordinary, Some(fallthrough))
|
||||
(ordinary, Some(fallthrough), None)
|
||||
} else if let Style::Newtype = last.style {
|
||||
let ordinary = &variants[..variants.len() - 1];
|
||||
let deserializer = quote!(_serde::__private::de::IdentifierDeserializer::from(__value));
|
||||
let fallthrough = quote! {
|
||||
_serde::__private::Result::map(
|
||||
_serde::Deserialize::deserialize(#deserializer),
|
||||
#this::#last_ident)
|
||||
let fallthrough = |value| {
|
||||
quote! {
|
||||
_serde::__private::Result::map(
|
||||
_serde::Deserialize::deserialize(
|
||||
_serde::__private::de::IdentifierDeserializer::from(#value)
|
||||
),
|
||||
#this::#last_ident)
|
||||
}
|
||||
};
|
||||
(ordinary, Some(fallthrough))
|
||||
(
|
||||
ordinary,
|
||||
Some(fallthrough(quote!(__value))),
|
||||
Some(fallthrough(quote!(_serde::__private::de::Borrowed(
|
||||
__value
|
||||
)))),
|
||||
)
|
||||
} else {
|
||||
(variants, None)
|
||||
(variants, None, None)
|
||||
}
|
||||
} else {
|
||||
(variants, None)
|
||||
(variants, None, None)
|
||||
};
|
||||
|
||||
let names_idents: Vec<_> = ordinary
|
||||
@@ -2016,7 +2045,9 @@ fn deserialize_custom_identifier(
|
||||
&names_idents,
|
||||
is_variant,
|
||||
fallthrough,
|
||||
fallthrough_borrowed,
|
||||
false,
|
||||
cattrs.expecting(),
|
||||
));
|
||||
|
||||
quote_block! {
|
||||
@@ -2046,21 +2077,20 @@ fn deserialize_identifier(
|
||||
fields: &[(String, Ident, Vec<String>)],
|
||||
is_variant: bool,
|
||||
fallthrough: Option<TokenStream>,
|
||||
fallthrough_borrowed: Option<TokenStream>,
|
||||
collect_other_fields: bool,
|
||||
expecting: Option<&str>,
|
||||
) -> Fragment {
|
||||
let mut flat_fields = Vec::new();
|
||||
for (_, ident, aliases) in fields {
|
||||
flat_fields.extend(aliases.iter().map(|alias| (alias, ident)))
|
||||
}
|
||||
|
||||
let field_strs = flat_fields.iter().map(|(name, _)| name);
|
||||
let field_borrowed_strs = flat_fields.iter().map(|(name, _)| name);
|
||||
let field_bytes = flat_fields
|
||||
let field_strs: &Vec<_> = &flat_fields.iter().map(|(name, _)| name).collect();
|
||||
let field_bytes: &Vec<_> = &flat_fields
|
||||
.iter()
|
||||
.map(|(name, _)| Literal::byte_string(name.as_bytes()));
|
||||
let field_borrowed_bytes = flat_fields
|
||||
.iter()
|
||||
.map(|(name, _)| Literal::byte_string(name.as_bytes()));
|
||||
.map(|(name, _)| Literal::byte_string(name.as_bytes()))
|
||||
.collect();
|
||||
|
||||
let constructors: &Vec<_> = &flat_fields
|
||||
.iter()
|
||||
@@ -2071,11 +2101,11 @@ fn deserialize_identifier(
|
||||
.map(|(_, ident, _)| quote!(#this::#ident))
|
||||
.collect();
|
||||
|
||||
let expecting = if is_variant {
|
||||
let expecting = expecting.unwrap_or(if is_variant {
|
||||
"variant identifier"
|
||||
} else {
|
||||
"field identifier"
|
||||
};
|
||||
});
|
||||
|
||||
let index_expecting = if is_variant { "variant" } else { "field" };
|
||||
|
||||
@@ -2111,20 +2141,36 @@ fn deserialize_identifier(
|
||||
(None, None, None, None)
|
||||
};
|
||||
|
||||
let fallthrough_arm = if let Some(fallthrough) = fallthrough {
|
||||
let fallthrough_arm_tokens;
|
||||
let fallthrough_arm = if let Some(fallthrough) = &fallthrough {
|
||||
fallthrough
|
||||
} else if is_variant {
|
||||
quote! {
|
||||
fallthrough_arm_tokens = quote! {
|
||||
_serde::__private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS))
|
||||
}
|
||||
};
|
||||
&fallthrough_arm_tokens
|
||||
} else {
|
||||
quote! {
|
||||
fallthrough_arm_tokens = quote! {
|
||||
_serde::__private::Err(_serde::de::Error::unknown_field(__value, FIELDS))
|
||||
}
|
||||
};
|
||||
&fallthrough_arm_tokens
|
||||
};
|
||||
|
||||
let u64_fallthrough_arm_tokens;
|
||||
let u64_fallthrough_arm = if let Some(fallthrough) = &fallthrough {
|
||||
fallthrough
|
||||
} else {
|
||||
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
|
||||
u64_fallthrough_arm_tokens = quote! {
|
||||
_serde::__private::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&#fallthrough_msg,
|
||||
))
|
||||
};
|
||||
&u64_fallthrough_arm_tokens
|
||||
};
|
||||
|
||||
let variant_indices = 0_u64..;
|
||||
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
|
||||
let visit_other = if collect_other_fields {
|
||||
quote! {
|
||||
fn visit_bool<__E>(self, __value: bool) -> _serde::__private::Result<Self::Value, __E>
|
||||
@@ -2217,37 +2263,6 @@ fn deserialize_identifier(
|
||||
{
|
||||
_serde::__private::Ok(__Field::__other(_serde::__private::de::Content::Unit))
|
||||
}
|
||||
|
||||
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
#(
|
||||
#field_borrowed_strs => _serde::__private::Ok(#constructors),
|
||||
)*
|
||||
_ => {
|
||||
#value_as_borrowed_str_content
|
||||
#fallthrough_arm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::__private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
#(
|
||||
#field_borrowed_bytes => _serde::__private::Ok(#constructors),
|
||||
)*
|
||||
_ => {
|
||||
#bytes_to_str
|
||||
#value_as_borrowed_bytes_content
|
||||
#fallthrough_arm
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
@@ -2259,15 +2274,50 @@ fn deserialize_identifier(
|
||||
#(
|
||||
#variant_indices => _serde::__private::Ok(#main_constructors),
|
||||
)*
|
||||
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&#fallthrough_msg,
|
||||
))
|
||||
_ => #u64_fallthrough_arm,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields {
|
||||
let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(&fallthrough_arm);
|
||||
Some(quote! {
|
||||
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
#(
|
||||
#field_strs => _serde::__private::Ok(#constructors),
|
||||
)*
|
||||
_ => {
|
||||
#value_as_borrowed_str_content
|
||||
#fallthrough_borrowed_arm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::__private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
#(
|
||||
#field_bytes => _serde::__private::Ok(#constructors),
|
||||
)*
|
||||
_ => {
|
||||
#bytes_to_str
|
||||
#value_as_borrowed_bytes_content
|
||||
#fallthrough_borrowed_arm
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result {
|
||||
_serde::__private::Formatter::write_str(__formatter, #expecting)
|
||||
@@ -2305,6 +2355,8 @@ fn deserialize_identifier(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#visit_borrowed
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ use proc_macro2::{Group, Span, TokenStream, TokenTree};
|
||||
use quote::ToTokens;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeSet;
|
||||
use std::str::FromStr;
|
||||
use syn;
|
||||
use syn::parse::{self, Parse, ParseStream};
|
||||
use syn::punctuated::Punctuated;
|
||||
@@ -223,6 +222,8 @@ pub struct Container {
|
||||
has_flatten: bool,
|
||||
serde_path: Option<syn::Path>,
|
||||
is_packed: bool,
|
||||
/// Error message generated when type can't be deserialized
|
||||
expecting: Option<String>,
|
||||
}
|
||||
|
||||
/// Styles of representing an enum.
|
||||
@@ -305,6 +306,7 @@ impl Container {
|
||||
let mut field_identifier = BoolAttr::none(cx, FIELD_IDENTIFIER);
|
||||
let mut variant_identifier = BoolAttr::none(cx, VARIANT_IDENTIFIER);
|
||||
let mut serde_path = Attr::none(cx, CRATE);
|
||||
let mut expecting = Attr::none(cx, EXPECTING);
|
||||
|
||||
for meta_item in item
|
||||
.attrs
|
||||
@@ -337,13 +339,7 @@ impl Container {
|
||||
rename_all_ser_rule.set(&m.path, rename_rule);
|
||||
rename_all_de_rule.set(&m.path, rename_rule);
|
||||
}
|
||||
Err(()) => cx.error_spanned_by(
|
||||
s,
|
||||
format!(
|
||||
"unknown rename rule for #[serde(rename_all = {:?})]",
|
||||
s.value(),
|
||||
),
|
||||
),
|
||||
Err(err) => cx.error_spanned_by(s, err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -354,25 +350,13 @@ impl Container {
|
||||
if let Some(ser) = ser {
|
||||
match RenameRule::from_str(&ser.value()) {
|
||||
Ok(rename_rule) => rename_all_ser_rule.set(&m.path, rename_rule),
|
||||
Err(()) => cx.error_spanned_by(
|
||||
ser,
|
||||
format!(
|
||||
"unknown rename rule for #[serde(rename_all = {:?})]",
|
||||
ser.value(),
|
||||
),
|
||||
),
|
||||
Err(err) => cx.error_spanned_by(ser, err),
|
||||
}
|
||||
}
|
||||
if let Some(de) = de {
|
||||
match RenameRule::from_str(&de.value()) {
|
||||
Ok(rename_rule) => rename_all_de_rule.set(&m.path, rename_rule),
|
||||
Err(()) => cx.error_spanned_by(
|
||||
de,
|
||||
format!(
|
||||
"unknown rename rule for #[serde(rename_all = {:?})]",
|
||||
de.value(),
|
||||
),
|
||||
),
|
||||
Err(err) => cx.error_spanned_by(de, err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -575,6 +559,13 @@ impl Container {
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(expecting = "a message")]`
|
||||
Meta(NameValue(m)) if m.path == EXPECTING => {
|
||||
if let Ok(s) = get_lit_str(cx, EXPECTING, &m.lit) {
|
||||
expecting.set(&m.path, s.value());
|
||||
}
|
||||
}
|
||||
|
||||
Meta(meta_item) => {
|
||||
let path = meta_item
|
||||
.path()
|
||||
@@ -627,6 +618,7 @@ impl Container {
|
||||
has_flatten: false,
|
||||
serde_path: serde_path.get(),
|
||||
is_packed,
|
||||
expecting: expecting.get(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,6 +694,12 @@ impl Container {
|
||||
self.custom_serde_path()
|
||||
.map_or_else(|| Cow::Owned(parse_quote!(_serde)), Cow::Borrowed)
|
||||
}
|
||||
|
||||
/// Error message generated when type can't be deserialized.
|
||||
/// If `None`, default message will be used
|
||||
pub fn expecting(&self) -> Option<&str> {
|
||||
self.expecting.as_ref().map(String::as_ref)
|
||||
}
|
||||
}
|
||||
|
||||
fn decide_tag(
|
||||
@@ -914,13 +912,7 @@ impl Variant {
|
||||
rename_all_ser_rule.set(&m.path, rename_rule);
|
||||
rename_all_de_rule.set(&m.path, rename_rule);
|
||||
}
|
||||
Err(()) => cx.error_spanned_by(
|
||||
s,
|
||||
format!(
|
||||
"unknown rename rule for #[serde(rename_all = {:?})]",
|
||||
s.value()
|
||||
),
|
||||
),
|
||||
Err(err) => cx.error_spanned_by(s, err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -931,25 +923,13 @@ impl Variant {
|
||||
if let Some(ser) = ser {
|
||||
match RenameRule::from_str(&ser.value()) {
|
||||
Ok(rename_rule) => rename_all_ser_rule.set(&m.path, rename_rule),
|
||||
Err(()) => cx.error_spanned_by(
|
||||
ser,
|
||||
format!(
|
||||
"unknown rename rule for #[serde(rename_all = {:?})]",
|
||||
ser.value(),
|
||||
),
|
||||
),
|
||||
Err(err) => cx.error_spanned_by(ser, err),
|
||||
}
|
||||
}
|
||||
if let Some(de) = de {
|
||||
match RenameRule::from_str(&de.value()) {
|
||||
Ok(rename_rule) => rename_all_de_rule.set(&m.path, rename_rule),
|
||||
Err(()) => cx.error_spanned_by(
|
||||
de,
|
||||
format!(
|
||||
"unknown rename rule for #[serde(rename_all = {:?})]",
|
||||
de.value(),
|
||||
),
|
||||
),
|
||||
Err(err) => cx.error_spanned_by(de, err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#[allow(deprecated, unused_imports)]
|
||||
use std::ascii::AsciiExt;
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
|
||||
use self::RenameRule::*;
|
||||
|
||||
@@ -17,7 +17,7 @@ pub enum RenameRule {
|
||||
/// Rename direct children to "lowercase" style.
|
||||
LowerCase,
|
||||
/// Rename direct children to "UPPERCASE" style.
|
||||
UPPERCASE,
|
||||
UpperCase,
|
||||
/// Rename direct children to "PascalCase" style, as typically used for
|
||||
/// enum variants.
|
||||
PascalCase,
|
||||
@@ -35,13 +35,35 @@ pub enum RenameRule {
|
||||
ScreamingKebabCase,
|
||||
}
|
||||
|
||||
static RENAME_RULES: &[(&str, RenameRule)] = &[
|
||||
("lowercase", LowerCase),
|
||||
("UPPERCASE", UpperCase),
|
||||
("PascalCase", PascalCase),
|
||||
("camelCase", CamelCase),
|
||||
("snake_case", SnakeCase),
|
||||
("SCREAMING_SNAKE_CASE", ScreamingSnakeCase),
|
||||
("kebab-case", KebabCase),
|
||||
("SCREAMING-KEBAB-CASE", ScreamingKebabCase),
|
||||
];
|
||||
|
||||
impl RenameRule {
|
||||
pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError> {
|
||||
for (name, rule) in RENAME_RULES {
|
||||
if rename_all_str == *name {
|
||||
return Ok(*rule);
|
||||
}
|
||||
}
|
||||
Err(ParseError {
|
||||
unknown: rename_all_str,
|
||||
})
|
||||
}
|
||||
|
||||
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
|
||||
pub fn apply_to_variant(&self, variant: &str) -> String {
|
||||
match *self {
|
||||
None | PascalCase => variant.to_owned(),
|
||||
LowerCase => variant.to_ascii_lowercase(),
|
||||
UPPERCASE => variant.to_ascii_uppercase(),
|
||||
UpperCase => variant.to_ascii_uppercase(),
|
||||
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
|
||||
SnakeCase => {
|
||||
let mut snake = String::new();
|
||||
@@ -65,7 +87,7 @@ impl RenameRule {
|
||||
pub fn apply_to_field(&self, field: &str) -> String {
|
||||
match *self {
|
||||
None | LowerCase | SnakeCase => field.to_owned(),
|
||||
UPPERCASE => field.to_ascii_uppercase(),
|
||||
UpperCase => field.to_ascii_uppercase(),
|
||||
PascalCase => {
|
||||
let mut pascal = String::new();
|
||||
let mut capitalize = true;
|
||||
@@ -92,21 +114,22 @@ impl RenameRule {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for RenameRule {
|
||||
type Err = ();
|
||||
pub struct ParseError<'a> {
|
||||
unknown: &'a str,
|
||||
}
|
||||
|
||||
fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> {
|
||||
match rename_all_str {
|
||||
"lowercase" => Ok(LowerCase),
|
||||
"UPPERCASE" => Ok(UPPERCASE),
|
||||
"PascalCase" => Ok(PascalCase),
|
||||
"camelCase" => Ok(CamelCase),
|
||||
"snake_case" => Ok(SnakeCase),
|
||||
"SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
|
||||
"kebab-case" => Ok(KebabCase),
|
||||
"SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase),
|
||||
_ => Err(()),
|
||||
impl<'a> Display for ParseError<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("unknown rename rule `rename_all = ")?;
|
||||
Debug::fmt(self.unknown, f)?;
|
||||
f.write_str("`, expected one of ")?;
|
||||
for (i, (name, _rule)) in RENAME_RULES.iter().enumerate() {
|
||||
if i > 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
Debug::fmt(name, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +154,7 @@ fn rename_variants() {
|
||||
] {
|
||||
assert_eq!(None.apply_to_variant(original), original);
|
||||
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
||||
assert_eq!(UPPERCASE.apply_to_variant(original), upper);
|
||||
assert_eq!(UpperCase.apply_to_variant(original), upper);
|
||||
assert_eq!(PascalCase.apply_to_variant(original), original);
|
||||
assert_eq!(CamelCase.apply_to_variant(original), camel);
|
||||
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
||||
@@ -163,7 +186,7 @@ fn rename_fields() {
|
||||
("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
||||
] {
|
||||
assert_eq!(None.apply_to_field(original), original);
|
||||
assert_eq!(UPPERCASE.apply_to_field(original), upper);
|
||||
assert_eq!(UpperCase.apply_to_field(original), upper);
|
||||
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
||||
assert_eq!(CamelCase.apply_to_field(original), camel);
|
||||
assert_eq!(SnakeCase.apply_to_field(original), original);
|
||||
|
||||
@@ -35,6 +35,7 @@ pub const TRY_FROM: Symbol = Symbol("try_from");
|
||||
pub const UNTAGGED: Symbol = Symbol("untagged");
|
||||
pub const VARIANT_IDENTIFIER: Symbol = Symbol("variant_identifier");
|
||||
pub const WITH: Symbol = Symbol("with");
|
||||
pub const EXPECTING: Symbol = Symbol("expecting");
|
||||
|
||||
impl PartialEq<Symbol> for Ident {
|
||||
fn eq(&self, word: &Symbol) -> bool {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
//!
|
||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.119")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.122")]
|
||||
#![allow(unknown_lints, bare_trait_objects)]
|
||||
#![deny(clippy::all, clippy::pedantic)]
|
||||
// Ignored clippy lints
|
||||
@@ -48,6 +48,7 @@
|
||||
clippy::struct_excessive_bools,
|
||||
clippy::too_many_lines,
|
||||
clippy::unseparated_literal_suffix,
|
||||
clippy::unused_self,
|
||||
clippy::use_self,
|
||||
clippy::wildcard_imports
|
||||
)]
|
||||
|
||||
@@ -16,7 +16,7 @@ path = "lib.rs"
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = { version = "1.0.33", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
|
||||
syn = { version = "1.0.60", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.25.0")]
|
||||
#![allow(unknown_lints, bare_trait_objects)]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(
|
||||
cognitive_complexity,
|
||||
redundant_field_names,
|
||||
result_unit_err,
|
||||
trivially_copy_pass_by_ref,
|
||||
wildcard_in_or_patterns,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||
unnested_or_patterns,
|
||||
)
|
||||
#![deny(clippy::all, clippy::pedantic)]
|
||||
// Ignored clippy lints
|
||||
#![allow(
|
||||
clippy::cognitive_complexity,
|
||||
clippy::redundant_field_names,
|
||||
clippy::result_unit_err,
|
||||
clippy::should_implement_trait,
|
||||
clippy::trivially_copy_pass_by_ref,
|
||||
clippy::wildcard_in_or_patterns,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||
clippy::unnested_or_patterns,
|
||||
)]
|
||||
// Ignored clippy_pedantic lints
|
||||
#![allow(
|
||||
clippy::doc_markdown,
|
||||
clippy::enum_glob_use,
|
||||
clippy::items_after_statements,
|
||||
clippy::match_same_arms,
|
||||
clippy::missing_errors_doc,
|
||||
clippy::must_use_candidate,
|
||||
clippy::struct_excessive_bools,
|
||||
clippy::too_many_lines,
|
||||
clippy::wildcard_imports
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_test"
|
||||
version = "1.0.119" # remember to update html_root_url
|
||||
version = "1.0.122" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Token De/Serializer for testing De/Serialize implementations"
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
|
||||
// The rustc-cfg strings below are *not* public API. Please let us know by
|
||||
// opening a GitHub issue if your build environment requires some way to enable
|
||||
// these cfgs other than by executing our build script.
|
||||
fn main() {
|
||||
let minor = match rustc_minor_version() {
|
||||
Some(minor) => minor,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// #[track_caller] stabilized in Rust 1.46:
|
||||
// https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html#track_caller
|
||||
if minor >= 46 {
|
||||
println!("cargo:rustc-cfg=track_caller");
|
||||
}
|
||||
}
|
||||
|
||||
fn rustc_minor_version() -> Option<u32> {
|
||||
let rustc = env::var_os("RUSTC")?;
|
||||
let output = Command::new(rustc).arg("--version").output().ok()?;
|
||||
let version = str::from_utf8(&output.stdout).ok()?;
|
||||
let mut pieces = version.split('.');
|
||||
if pieces.next() != Some("rustc 1") {
|
||||
return None;
|
||||
}
|
||||
pieces.next()?.parse().ok()
|
||||
}
|
||||
@@ -28,6 +28,7 @@ use std::fmt::Debug;
|
||||
/// Token::StructEnd,
|
||||
/// ]);
|
||||
/// ```
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
||||
where
|
||||
T: Serialize + Deserialize<'de> + PartialEq + Debug,
|
||||
@@ -58,6 +59,7 @@ where
|
||||
/// Token::StructEnd,
|
||||
/// ]);
|
||||
/// ```
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
|
||||
where
|
||||
T: Serialize,
|
||||
@@ -110,6 +112,7 @@ where
|
||||
/// assert_ser_tokens_error(&example, expected, error);
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: &str)
|
||||
where
|
||||
T: Serialize,
|
||||
@@ -147,6 +150,7 @@ where
|
||||
/// Token::StructEnd,
|
||||
/// ]);
|
||||
/// ```
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
||||
where
|
||||
T: Deserialize<'de> + PartialEq + Debug,
|
||||
@@ -199,6 +203,7 @@ where
|
||||
/// "unknown field `x`, expected `a` or `b`",
|
||||
/// );
|
||||
/// ```
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str)
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
|
||||
@@ -777,6 +777,17 @@ macro_rules! impl_deserializer {
|
||||
{
|
||||
self.0.next_value_seed($wrapper(seed))
|
||||
}
|
||||
fn next_entry_seed<K, V>(
|
||||
&mut self,
|
||||
kseed: K,
|
||||
vseed: V,
|
||||
) -> Result<Option<(K::Value, V::Value)>, D::Error>
|
||||
where
|
||||
K: DeserializeSeed<'de>,
|
||||
V: DeserializeSeed<'de>,
|
||||
{
|
||||
self.0.next_entry_seed($wrapper(kseed), $wrapper(vseed))
|
||||
}
|
||||
fn size_hint(&self) -> Option<usize> {
|
||||
self.0.size_hint()
|
||||
}
|
||||
|
||||
+29
-3
@@ -168,14 +168,42 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
self.next_token();
|
||||
visitor.visit_str(variant)
|
||||
}
|
||||
(Token::BorrowedStr(variant), Token::Unit) => {
|
||||
self.next_token();
|
||||
visitor.visit_borrowed_str(variant)
|
||||
}
|
||||
(Token::String(variant), Token::Unit) => {
|
||||
self.next_token();
|
||||
visitor.visit_string(variant.to_string())
|
||||
}
|
||||
(Token::Bytes(variant), Token::Unit) => {
|
||||
self.next_token();
|
||||
visitor.visit_bytes(variant)
|
||||
}
|
||||
(Token::BorrowedBytes(variant), Token::Unit) => {
|
||||
self.next_token();
|
||||
visitor.visit_borrowed_bytes(variant)
|
||||
}
|
||||
(Token::ByteBuf(variant), Token::Unit) => {
|
||||
self.next_token();
|
||||
visitor.visit_byte_buf(variant.to_vec())
|
||||
}
|
||||
(Token::U8(variant), Token::Unit) => {
|
||||
self.next_token();
|
||||
visitor.visit_u8(variant)
|
||||
}
|
||||
(Token::U16(variant), Token::Unit) => {
|
||||
self.next_token();
|
||||
visitor.visit_u16(variant)
|
||||
}
|
||||
(Token::U32(variant), Token::Unit) => {
|
||||
self.next_token();
|
||||
visitor.visit_u32(variant)
|
||||
}
|
||||
(Token::U64(variant), Token::Unit) => {
|
||||
self.next_token();
|
||||
visitor.visit_u64(variant)
|
||||
}
|
||||
(variant, Token::Unit) => unexpected!(variant),
|
||||
(variant, _) => {
|
||||
visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any))
|
||||
@@ -250,9 +278,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
{
|
||||
visitor.visit_enum(DeserializerEnumVisitor { de: self })
|
||||
}
|
||||
_ => {
|
||||
unexpected!(self.next_token());
|
||||
}
|
||||
_ => self.deserialize_any(visitor),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.119")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.122")]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||
// Ignored clippy lints
|
||||
@@ -158,6 +158,7 @@
|
||||
module_name_repetitions,
|
||||
must_use_candidate,
|
||||
redundant_field_names,
|
||||
too_many_lines,
|
||||
use_debug,
|
||||
use_self
|
||||
)
|
||||
|
||||
+13
-13
@@ -32,18 +32,18 @@ impl<'a> Serializer<'a> {
|
||||
}
|
||||
|
||||
macro_rules! assert_next_token {
|
||||
($ser:expr, $expected:ident) => {
|
||||
assert_next_token!($ser, stringify!($expected), Token::$expected, true);
|
||||
($ser:expr, $actual:ident) => {
|
||||
assert_next_token!($ser, stringify!($actual), Token::$actual, true);
|
||||
};
|
||||
($ser:expr, $expected:ident($v:expr)) => {
|
||||
($ser:expr, $actual:ident($v:expr)) => {
|
||||
assert_next_token!(
|
||||
$ser,
|
||||
format_args!(concat!(stringify!($expected), "({:?})"), $v),
|
||||
Token::$expected(v),
|
||||
format_args!(concat!(stringify!($actual), "({:?})"), $v),
|
||||
Token::$actual(v),
|
||||
v == $v
|
||||
);
|
||||
};
|
||||
($ser:expr, $expected:ident { $($k:ident),* }) => {
|
||||
($ser:expr, $actual:ident { $($k:ident),* }) => {
|
||||
let compare = ($($k,)*);
|
||||
let field_format = || {
|
||||
use std::fmt::Write;
|
||||
@@ -55,21 +55,21 @@ macro_rules! assert_next_token {
|
||||
};
|
||||
assert_next_token!(
|
||||
$ser,
|
||||
format_args!(concat!(stringify!($expected), " {{ {}}}"), field_format()),
|
||||
Token::$expected { $($k),* },
|
||||
format_args!(concat!(stringify!($actual), " {{ {}}}"), field_format()),
|
||||
Token::$actual { $($k),* },
|
||||
($($k,)*) == compare
|
||||
);
|
||||
};
|
||||
($ser:expr, $expected:expr, $pat:pat, $guard:expr) => {
|
||||
($ser:expr, $actual:expr, $pat:pat, $guard:expr) => {
|
||||
match $ser.next_token() {
|
||||
Some($pat) if $guard => {}
|
||||
Some(other) => {
|
||||
Some(expected) => {
|
||||
panic!("expected Token::{} but serialized as {}",
|
||||
$expected, other);
|
||||
expected, $actual);
|
||||
}
|
||||
None => {
|
||||
panic!("expected Token::{} after end of serialized tokens",
|
||||
$expected);
|
||||
panic!("expected end of tokens, but {} was serialized",
|
||||
$actual);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -573,12 +573,7 @@ const _: () = {
|
||||
1u64 => _serde::__private::Ok(__Field::__field1),
|
||||
2u64 => _serde::__private::Ok(__Field::__field2),
|
||||
3u64 => _serde::__private::Ok(__Field::__field3),
|
||||
_ => _serde::__private::Err(
|
||||
_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 4",
|
||||
),
|
||||
),
|
||||
_ => _serde::__private::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(
|
||||
@@ -1081,12 +1076,7 @@ const _: () = {
|
||||
1u64 => _serde::__private::Ok(__Field::__field1),
|
||||
2u64 => _serde::__private::Ok(__Field::__field2),
|
||||
3u64 => _serde::__private::Ok(__Field::__field3),
|
||||
_ => _serde::__private::Err(
|
||||
_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 4",
|
||||
),
|
||||
),
|
||||
_ => _serde::__private::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(
|
||||
|
||||
@@ -77,10 +77,7 @@ const _: () = {
|
||||
{
|
||||
match __value {
|
||||
0u64 => _serde::__private::Ok(__Field::__field0),
|
||||
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 1",
|
||||
)),
|
||||
_ => _serde::__private::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(
|
||||
@@ -260,10 +257,7 @@ const _: () = {
|
||||
{
|
||||
match __value {
|
||||
0u64 => _serde::__private::Ok(__Field::__field0),
|
||||
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 1",
|
||||
)),
|
||||
_ => _serde::__private::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(
|
||||
|
||||
@@ -357,12 +357,7 @@ const _: () = {
|
||||
match __value {
|
||||
0u64 => _serde::__private::Ok(__Field::__field0),
|
||||
1u64 => _serde::__private::Ok(__Field::__field1),
|
||||
_ => _serde::__private::Err(
|
||||
_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 2",
|
||||
),
|
||||
),
|
||||
_ => _serde::__private::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(
|
||||
|
||||
@@ -73,10 +73,7 @@ const _: () = {
|
||||
{
|
||||
match __value {
|
||||
0u64 => _serde::__private::Ok(__Field::__field0),
|
||||
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 1",
|
||||
)),
|
||||
_ => _serde::__private::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(
|
||||
@@ -256,10 +253,7 @@ const _: () = {
|
||||
{
|
||||
match __value {
|
||||
0u64 => _serde::__private::Ok(__Field::__field0),
|
||||
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 1",
|
||||
)),
|
||||
_ => _serde::__private::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(
|
||||
|
||||
@@ -244,12 +244,7 @@ const _: () = {
|
||||
{
|
||||
match __value {
|
||||
0u64 => _serde::__private::Ok(__Field::__field0),
|
||||
_ => _serde::__private::Err(
|
||||
_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 1",
|
||||
),
|
||||
),
|
||||
_ => _serde::__private::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(
|
||||
@@ -433,12 +428,7 @@ const _: () = {
|
||||
{
|
||||
match __value {
|
||||
0u64 => _serde::__private::Ok(__Field::__field0),
|
||||
_ => _serde::__private::Err(
|
||||
_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 1",
|
||||
),
|
||||
),
|
||||
_ => _serde::__private::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(
|
||||
|
||||
@@ -100,10 +100,7 @@ const _: () = {
|
||||
0u64 => _serde::__private::Ok(__Field::__field0),
|
||||
1u64 => _serde::__private::Ok(__Field::__field1),
|
||||
2u64 => _serde::__private::Ok(__Field::__field2),
|
||||
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 3",
|
||||
)),
|
||||
_ => _serde::__private::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(
|
||||
@@ -387,10 +384,7 @@ const _: () = {
|
||||
0u64 => _serde::__private::Ok(__Field::__field0),
|
||||
1u64 => _serde::__private::Ok(__Field::__field1),
|
||||
2u64 => _serde::__private::Ok(__Field::__field2),
|
||||
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&"field index 0 <= i < 3",
|
||||
)),
|
||||
_ => _serde::__private::Ok(__Field::__ignore),
|
||||
}
|
||||
}
|
||||
fn visit_str<__E>(
|
||||
|
||||
@@ -2637,3 +2637,171 @@ fn test_flatten_any_after_flatten_struct() {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expecting_message() {
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[serde(expecting = "something strange...")]
|
||||
struct Unit;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(expecting = "something strange...")]
|
||||
struct Newtype(bool);
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(expecting = "something strange...")]
|
||||
struct Tuple(u32, bool);
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(expecting = "something strange...")]
|
||||
struct Struct {
|
||||
question: String,
|
||||
answer: u32,
|
||||
}
|
||||
|
||||
assert_de_tokens_error::<Unit>(
|
||||
&[Token::Str("Unit")],
|
||||
r#"invalid type: string "Unit", expected something strange..."#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<Newtype>(
|
||||
&[Token::Str("Newtype")],
|
||||
r#"invalid type: string "Newtype", expected something strange..."#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<Tuple>(
|
||||
&[Token::Str("Tuple")],
|
||||
r#"invalid type: string "Tuple", expected something strange..."#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<Struct>(
|
||||
&[Token::Str("Struct")],
|
||||
r#"invalid type: string "Struct", expected something strange..."#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expecting_message_externally_tagged_enum() {
|
||||
#[derive(Deserialize)]
|
||||
#[serde(expecting = "something strange...")]
|
||||
enum Enum {
|
||||
ExternallyTagged,
|
||||
}
|
||||
|
||||
assert_de_tokens_error::<Enum>(
|
||||
&[Token::Str("ExternallyTagged")],
|
||||
r#"invalid type: string "ExternallyTagged", expected something strange..."#,
|
||||
);
|
||||
|
||||
// Check that #[serde(expecting = "...")] doesn't affect variant identifier error message
|
||||
assert_de_tokens_error::<Enum>(
|
||||
&[Token::Enum { name: "Enum" }, Token::Unit],
|
||||
r#"invalid type: unit value, expected variant identifier"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expecting_message_internally_tagged_enum() {
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "tag")]
|
||||
#[serde(expecting = "something strange...")]
|
||||
enum Enum {
|
||||
InternallyTagged,
|
||||
}
|
||||
|
||||
assert_de_tokens_error::<Enum>(
|
||||
&[Token::Str("InternallyTagged")],
|
||||
r#"invalid type: string "InternallyTagged", expected something strange..."#,
|
||||
);
|
||||
|
||||
// Check that #[serde(expecting = "...")] doesn't affect variant identifier error message
|
||||
assert_de_tokens_error::<Enum>(
|
||||
&[Token::Map { len: None }, Token::Str("tag"), Token::Unit],
|
||||
r#"invalid type: unit value, expected variant identifier"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expecting_message_adjacently_tagged_enum() {
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "tag", content = "content")]
|
||||
#[serde(expecting = "something strange...")]
|
||||
enum Enum {
|
||||
AdjacentlyTagged,
|
||||
}
|
||||
|
||||
assert_de_tokens_error::<Enum>(
|
||||
&[Token::Str("AdjacentlyTagged")],
|
||||
r#"invalid type: string "AdjacentlyTagged", expected something strange..."#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<Enum>(
|
||||
&[Token::Map { len: None }, Token::Unit],
|
||||
r#"invalid type: unit value, expected "tag", "content", or other ignored fields"#,
|
||||
);
|
||||
|
||||
// Check that #[serde(expecting = "...")] doesn't affect variant identifier error message
|
||||
assert_de_tokens_error::<Enum>(
|
||||
&[Token::Map { len: None }, Token::Str("tag"), Token::Unit],
|
||||
r#"invalid type: unit value, expected variant identifier"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expecting_message_untagged_tagged_enum() {
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[serde(expecting = "something strange...")]
|
||||
enum Enum {
|
||||
Untagged,
|
||||
}
|
||||
|
||||
assert_de_tokens_error::<Enum>(&[Token::Str("Untagged")], r#"something strange..."#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expecting_message_identifier_enum() {
|
||||
#[derive(Deserialize)]
|
||||
#[serde(field_identifier)]
|
||||
#[serde(expecting = "something strange...")]
|
||||
enum FieldEnum {
|
||||
Field,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(variant_identifier)]
|
||||
#[serde(expecting = "something strange...")]
|
||||
enum VariantEnum {
|
||||
Variant,
|
||||
}
|
||||
|
||||
assert_de_tokens_error::<FieldEnum>(
|
||||
&[Token::Unit],
|
||||
r#"invalid type: unit value, expected something strange..."#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<FieldEnum>(
|
||||
&[
|
||||
Token::Enum { name: "FieldEnum" },
|
||||
Token::Str("Unknown"),
|
||||
Token::None,
|
||||
],
|
||||
r#"invalid type: map, expected something strange..."#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<VariantEnum>(
|
||||
&[Token::Unit],
|
||||
r#"invalid type: unit value, expected something strange..."#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<VariantEnum>(
|
||||
&[
|
||||
Token::Enum {
|
||||
name: "VariantEnum",
|
||||
},
|
||||
Token::Str("Unknown"),
|
||||
Token::None,
|
||||
],
|
||||
r#"invalid type: map, expected something strange..."#,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,6 +90,30 @@ fn test_struct() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_field_identifier() {
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
#[serde(field_identifier)]
|
||||
enum FieldStr<'a> {
|
||||
#[serde(borrow)]
|
||||
Str(&'a str),
|
||||
}
|
||||
|
||||
assert_de_tokens(&FieldStr::Str("value"), &[Token::BorrowedStr("value")]);
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
#[serde(field_identifier)]
|
||||
enum FieldBytes<'a> {
|
||||
#[serde(borrow)]
|
||||
Bytes(&'a [u8]),
|
||||
}
|
||||
|
||||
assert_de_tokens(
|
||||
&FieldBytes::Bytes(b"value"),
|
||||
&[Token::BorrowedBytes(b"value")],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cow() {
|
||||
#[derive(Deserialize)]
|
||||
|
||||
@@ -622,6 +622,24 @@ declare_tests! {
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::U8(0),
|
||||
Token::I32(1),
|
||||
|
||||
Token::U8(1),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::U16(0),
|
||||
Token::I32(1),
|
||||
|
||||
Token::U16(1),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::U32(0),
|
||||
@@ -631,6 +649,34 @@ declare_tests! {
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::U64(0),
|
||||
Token::I32(1),
|
||||
|
||||
Token::U64(1),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
// Mixed key types
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::U8(0),
|
||||
Token::I32(1),
|
||||
|
||||
Token::U64(1),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::U8(0),
|
||||
Token::I32(1),
|
||||
|
||||
Token::Str("b"),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Struct { name: "Struct", len: 2 },
|
||||
Token::Str("a"),
|
||||
@@ -647,6 +693,46 @@ declare_tests! {
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_struct_borrowed_keys {
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::BorrowedStr("a"),
|
||||
Token::I32(1),
|
||||
|
||||
Token::BorrowedStr("b"),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Struct { name: "Struct", len: 2 },
|
||||
Token::BorrowedStr("a"),
|
||||
Token::I32(1),
|
||||
|
||||
Token::BorrowedStr("b"),
|
||||
Token::I32(2),
|
||||
Token::StructEnd,
|
||||
],
|
||||
}
|
||||
test_struct_owned_keys {
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::String("a"),
|
||||
Token::I32(1),
|
||||
|
||||
Token::String("b"),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Struct { name: "Struct", len: 2 },
|
||||
Token::String("a"),
|
||||
Token::I32(1),
|
||||
|
||||
Token::String("b"),
|
||||
Token::I32(2),
|
||||
Token::StructEnd,
|
||||
],
|
||||
}
|
||||
test_struct_with_skip {
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
@@ -663,6 +749,21 @@ declare_tests! {
|
||||
Token::I32(4),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::U8(0),
|
||||
Token::I32(1),
|
||||
|
||||
Token::U16(1),
|
||||
Token::I32(2),
|
||||
|
||||
Token::U32(2),
|
||||
Token::I32(3),
|
||||
|
||||
Token::U64(3),
|
||||
Token::I32(4),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Struct { name: "Struct", len: 2 },
|
||||
Token::Str("a"),
|
||||
@@ -780,6 +881,26 @@ declare_tests! {
|
||||
Token::Str("Unit"),
|
||||
Token::Unit,
|
||||
],
|
||||
EnumOther::Unit => &[
|
||||
Token::Enum { name: "EnumOther" },
|
||||
Token::U8(0),
|
||||
Token::Unit,
|
||||
],
|
||||
EnumOther::Unit => &[
|
||||
Token::Enum { name: "EnumOther" },
|
||||
Token::U16(0),
|
||||
Token::Unit,
|
||||
],
|
||||
EnumOther::Unit => &[
|
||||
Token::Enum { name: "EnumOther" },
|
||||
Token::U32(0),
|
||||
Token::Unit,
|
||||
],
|
||||
EnumOther::Unit => &[
|
||||
Token::Enum { name: "EnumOther" },
|
||||
Token::U64(0),
|
||||
Token::Unit,
|
||||
],
|
||||
}
|
||||
test_enum_other {
|
||||
EnumOther::Other => &[
|
||||
@@ -787,6 +908,26 @@ declare_tests! {
|
||||
Token::Str("Foo"),
|
||||
Token::Unit,
|
||||
],
|
||||
EnumOther::Other => &[
|
||||
Token::Enum { name: "EnumOther" },
|
||||
Token::U8(42),
|
||||
Token::Unit,
|
||||
],
|
||||
EnumOther::Other => &[
|
||||
Token::Enum { name: "EnumOther" },
|
||||
Token::U16(42),
|
||||
Token::Unit,
|
||||
],
|
||||
EnumOther::Other => &[
|
||||
Token::Enum { name: "EnumOther" },
|
||||
Token::U32(42),
|
||||
Token::Unit,
|
||||
],
|
||||
EnumOther::Other => &[
|
||||
Token::Enum { name: "EnumOther" },
|
||||
Token::U64(42),
|
||||
Token::Unit,
|
||||
],
|
||||
}
|
||||
test_box {
|
||||
Box::new(0i32) => &[Token::I32(0)],
|
||||
@@ -1452,4 +1593,25 @@ declare_error_tests! {
|
||||
],
|
||||
"invalid value: integer `65536`, expected u16",
|
||||
}
|
||||
test_duration_overflow_seq<Duration> {
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::U64(u64::max_value()),
|
||||
Token::U32(1_000_000_000),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
"overflow deserializing Duration",
|
||||
}
|
||||
test_duration_overflow_struct<Duration> {
|
||||
&[
|
||||
Token::Struct { name: "Duration", len: 2 },
|
||||
Token::Str("secs"),
|
||||
Token::U64(u64::max_value()),
|
||||
|
||||
Token::Str("nanos"),
|
||||
Token::U32(1_000_000_000),
|
||||
Token::StructEnd,
|
||||
],
|
||||
"overflow deserializing Duration",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//! Tests for `#[serde(field_identifier)]` and `#[serde(variant_identifier)]`
|
||||
use serde::Deserialize;
|
||||
use serde_test::{assert_de_tokens, Token};
|
||||
|
||||
@@ -27,6 +28,10 @@ fn test_field_identifier() {
|
||||
Bbb,
|
||||
}
|
||||
|
||||
assert_de_tokens(&F::Aaa, &[Token::U8(0)]);
|
||||
assert_de_tokens(&F::Aaa, &[Token::U16(0)]);
|
||||
assert_de_tokens(&F::Aaa, &[Token::U32(0)]);
|
||||
assert_de_tokens(&F::Aaa, &[Token::U64(0)]);
|
||||
assert_de_tokens(&F::Aaa, &[Token::Str("aaa")]);
|
||||
assert_de_tokens(&F::Aaa, &[Token::Bytes(b"aaa")]);
|
||||
}
|
||||
@@ -42,6 +47,10 @@ fn test_unit_fallthrough() {
|
||||
Other,
|
||||
}
|
||||
|
||||
assert_de_tokens(&F::Other, &[Token::U8(42)]);
|
||||
assert_de_tokens(&F::Other, &[Token::U16(42)]);
|
||||
assert_de_tokens(&F::Other, &[Token::U32(42)]);
|
||||
assert_de_tokens(&F::Other, &[Token::U64(42)]);
|
||||
assert_de_tokens(&F::Other, &[Token::Str("x")]);
|
||||
}
|
||||
|
||||
@@ -68,5 +77,9 @@ fn test_newtype_fallthrough_generic() {
|
||||
Other(T),
|
||||
}
|
||||
|
||||
assert_de_tokens(&F::Other(42u8), &[Token::U8(42)]);
|
||||
assert_de_tokens(&F::Other(42u16), &[Token::U16(42)]);
|
||||
assert_de_tokens(&F::Other(42u32), &[Token::U32(42)]);
|
||||
assert_de_tokens(&F::Other(42u64), &[Token::U64(42)]);
|
||||
assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
error: unknown rename rule for #[serde(rename_all = "abc")]
|
||||
error: unknown rename rule `rename_all = "abc"`, expected one of "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE"
|
||||
--> $DIR/container_unknown_rename_rule.rs:4:22
|
||||
|
|
||||
4 | #[serde(rename_all = "abc")]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
error: unknown rename rule for #[serde(rename_all = "abc")]
|
||||
error: unknown rename rule `rename_all = "abc"`, expected one of "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE"
|
||||
--> $DIR/variant_unknown_rename_rule.rs:5:26
|
||||
|
|
||||
5 | #[serde(rename_all = "abc")]
|
||||
|
||||
Reference in New Issue
Block a user