mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-18 06:11:02 +00:00
Compare commits
73 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 89c4b02bf3 | |||
| eeb8e44cda | |||
| 785c2d9605 | |||
| d549f048e1 | |||
| 4c0dd63011 | |||
| 26fb134165 | |||
| 07e614b52b | |||
| b1f899fbe8 | |||
| b4f860e627 | |||
| d940fe1b49 | |||
| f2899a9e06 | |||
| 3aca38d2d3 | |||
| 30752ac4ff | |||
| b84e6ca4f5 | |||
| 87a2fb0f1a | |||
| 9eaf7b9824 | |||
| 7bde100237 | |||
| da7fc795ee | |||
| 4c5fec1363 | |||
| 6588b0ad37 | |||
| 0093f74cfe | |||
| 171c6da57a | |||
| 2dddc7796d | |||
| 8514f4119a | |||
| 98fb7d94aa | |||
| 31ca16d9bc | |||
| 9f72ce695e | |||
| c383e4f953 | |||
| a94d8750fb | |||
| b0d651be40 | |||
| d5a9c11b5c | |||
| 6bfe1c435a | |||
| a02da49b87 | |||
| 29dc6c3367 | |||
| a7f0bab078 | |||
| 3dc6829303 | |||
| 42e63ff942 | |||
| df07751e6f | |||
| 5445f1741b | |||
| 9d0f811221 | |||
| 36b9a859c4 | |||
| 59628d1712 | |||
| bee7470715 | |||
| 5a359e10f4 | |||
| 5e37ade519 | |||
| 1a9ffdbd0c | |||
| 2adb0e99b0 | |||
| 71ed1f2f12 | |||
| 47954502af | |||
| 4987fd15f7 | |||
| 8bfe0d0ac0 | |||
| 7c0e6bd18f | |||
| 41b9c33c2b | |||
| 28a775db22 | |||
| e999600f8f | |||
| d3492d8d36 | |||
| 48de0c51b0 | |||
| 93bda5f1dc | |||
| 2d75ef6b30 | |||
| f97160f715 | |||
| eb59c776ca | |||
| 9128201c78 | |||
| 2cbfd37072 | |||
| 0939214c51 | |||
| 8c60f5aea7 | |||
| da0ed4021d | |||
| 99f905403b | |||
| aa0654332d | |||
| af376c22c3 | |||
| 477eb7b70e | |||
| 026e91a68c | |||
| bfbedac919 | |||
| 4036ff88ed |
@@ -21,6 +21,11 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@nightly
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
- run: cd test_suite && cargo test --features unstable
|
- run: cd test_suite && cargo test --features unstable
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: Cargo.lock
|
||||||
|
path: Cargo.lock
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
name: Test suite (windows)
|
name: Test suite (windows)
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.207"
|
version = "1.0.210"
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
categories = ["encoding", "no-std", "no-std::no-alloc"]
|
categories = ["encoding", "no-std", "no-std::no-alloc"]
|
||||||
@@ -37,7 +37,7 @@ rustdoc-args = ["--generate-link-to-definition"]
|
|||||||
# is compatible with exactly one serde release because the generated code
|
# is compatible with exactly one serde release because the generated code
|
||||||
# involves nonpublic APIs which are not bound by semver.
|
# involves nonpublic APIs which are not bound by semver.
|
||||||
[target.'cfg(any())'.dependencies]
|
[target.'cfg(any())'.dependencies]
|
||||||
serde_derive = { version = "=1.0.207", path = "../serde_derive" }
|
serde_derive = { version = "=1.0.210", path = "../serde_derive" }
|
||||||
|
|
||||||
|
|
||||||
### FEATURES #################################################################
|
### FEATURES #################################################################
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ fn main() {
|
|||||||
|
|
||||||
if minor >= 77 {
|
if minor >= 77 {
|
||||||
println!("cargo:rustc-check-cfg=cfg(no_core_cstr)");
|
println!("cargo:rustc-check-cfg=cfg(no_core_cstr)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(no_core_error)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(no_core_net)");
|
||||||
println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)");
|
println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)");
|
||||||
println!("cargo:rustc-check-cfg=cfg(no_core_try_from)");
|
println!("cargo:rustc-check-cfg=cfg(no_core_try_from)");
|
||||||
println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)");
|
println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)");
|
||||||
@@ -86,11 +88,23 @@ fn main() {
|
|||||||
println!("cargo:rustc-cfg=no_core_num_saturating");
|
println!("cargo:rustc-cfg=no_core_num_saturating");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Support for core::net stabilized in Rust 1.77.
|
||||||
|
// https://blog.rust-lang.org/2024/03/21/Rust-1.77.0.html
|
||||||
|
if minor < 77 {
|
||||||
|
println!("cargo:rustc-cfg=no_core_net");
|
||||||
|
}
|
||||||
|
|
||||||
// Support for the `#[diagnostic]` tool attribute namespace
|
// Support for the `#[diagnostic]` tool attribute namespace
|
||||||
// https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html#diagnostic-attributes
|
// https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html#diagnostic-attributes
|
||||||
if minor < 78 {
|
if minor < 78 {
|
||||||
println!("cargo:rustc-cfg=no_diagnostic_namespace");
|
println!("cargo:rustc-cfg=no_diagnostic_namespace");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The Error trait became available in core in 1.81.
|
||||||
|
// https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror
|
||||||
|
if minor < 81 {
|
||||||
|
println!("cargo:rustc-cfg=no_core_error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rustc_minor_version() -> Option<u32> {
|
fn rustc_minor_version() -> Option<u32> {
|
||||||
|
|||||||
+16
-30
@@ -1583,12 +1583,9 @@ map_impl! {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
macro_rules! parse_ip_impl {
|
macro_rules! parse_ip_impl {
|
||||||
(
|
($ty:ty, $expecting:expr, $size:tt) => {
|
||||||
$(#[$attr:meta])*
|
|
||||||
$ty:ty, $expecting:expr, $size:tt
|
|
||||||
) => {
|
|
||||||
$(#[$attr])*
|
|
||||||
impl<'de> Deserialize<'de> for $ty {
|
impl<'de> Deserialize<'de> for $ty {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
@@ -1604,7 +1601,7 @@ macro_rules! parse_ip_impl {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
macro_rules! variant_identifier {
|
macro_rules! variant_identifier {
|
||||||
(
|
(
|
||||||
$name_kind:ident ($($variant:ident; $bytes:expr; $index:expr),*)
|
$name_kind:ident ($($variant:ident; $bytes:expr; $index:expr),*)
|
||||||
@@ -1679,7 +1676,7 @@ macro_rules! variant_identifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
macro_rules! deserialize_enum {
|
macro_rules! deserialize_enum {
|
||||||
(
|
(
|
||||||
$name:ident $name_kind:ident ($($variant:ident; $bytes:expr; $index:expr),*)
|
$name:ident $name_kind:ident ($($variant:ident; $bytes:expr; $index:expr),*)
|
||||||
@@ -1716,8 +1713,7 @@ macro_rules! deserialize_enum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
impl<'de> Deserialize<'de> for net::IpAddr {
|
impl<'de> Deserialize<'de> for net::IpAddr {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
@@ -1736,25 +1732,18 @@ impl<'de> Deserialize<'de> for net::IpAddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_ip_impl! {
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[cfg(feature = "std")]
|
parse_ip_impl!(net::Ipv4Addr, "IPv4 address", 4);
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
net::Ipv4Addr, "IPv4 address", 4
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_ip_impl! {
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[cfg(feature = "std")]
|
parse_ip_impl!(net::Ipv6Addr, "IPv6 address", 16);
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
net::Ipv6Addr, "IPv6 address", 16
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
macro_rules! parse_socket_impl {
|
macro_rules! parse_socket_impl {
|
||||||
(
|
(
|
||||||
$(#[$attr:meta])*
|
|
||||||
$ty:ty, $expecting:tt,
|
$ty:ty, $expecting:tt,
|
||||||
$new:expr,
|
$new:expr,
|
||||||
) => {
|
) => {
|
||||||
$(#[$attr])*
|
|
||||||
impl<'de> Deserialize<'de> for $ty {
|
impl<'de> Deserialize<'de> for $ty {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
@@ -1770,8 +1759,7 @@ macro_rules! parse_socket_impl {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
impl<'de> Deserialize<'de> for net::SocketAddr {
|
impl<'de> Deserialize<'de> for net::SocketAddr {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
@@ -1790,16 +1778,14 @@ impl<'de> Deserialize<'de> for net::SocketAddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
parse_socket_impl! {
|
parse_socket_impl! {
|
||||||
#[cfg(feature = "std")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
net::SocketAddrV4, "IPv4 socket address",
|
net::SocketAddrV4, "IPv4 socket address",
|
||||||
|(ip, port)| net::SocketAddrV4::new(ip, port),
|
|(ip, port)| net::SocketAddrV4::new(ip, port),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
parse_socket_impl! {
|
parse_socket_impl! {
|
||||||
#[cfg(feature = "std")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
net::SocketAddrV6, "IPv6 socket address",
|
net::SocketAddrV6, "IPv6 socket address",
|
||||||
|(ip, port)| net::SocketAddrV6::new(ip, port, 0, 0),
|
|(ip, port)| net::SocketAddrV6::new(ip, port, 0, 0),
|
||||||
}
|
}
|
||||||
@@ -3160,13 +3146,13 @@ atomic_impl! {
|
|||||||
AtomicU64 "64"
|
AtomicU64 "64"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
struct FromStrVisitor<T> {
|
struct FromStrVisitor<T> {
|
||||||
expecting: &'static str,
|
expecting: &'static str,
|
||||||
ty: PhantomData<T>,
|
ty: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
impl<T> FromStrVisitor<T> {
|
impl<T> FromStrVisitor<T> {
|
||||||
fn new(expecting: &'static str) -> Self {
|
fn new(expecting: &'static str) -> Self {
|
||||||
FromStrVisitor {
|
FromStrVisitor {
|
||||||
@@ -3176,7 +3162,7 @@ impl<T> FromStrVisitor<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
impl<'de, T> Visitor<'de> for FromStrVisitor<T>
|
impl<'de, T> Visitor<'de> for FromStrVisitor<T>
|
||||||
where
|
where
|
||||||
T: str::FromStr,
|
T: str::FromStr,
|
||||||
|
|||||||
+4
-5
@@ -118,17 +118,16 @@ use crate::lib::*;
|
|||||||
|
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
|
||||||
mod format;
|
|
||||||
mod ignored_any;
|
mod ignored_any;
|
||||||
mod impls;
|
mod impls;
|
||||||
pub(crate) mod size_hint;
|
pub(crate) mod size_hint;
|
||||||
|
|
||||||
pub use self::ignored_any::IgnoredAny;
|
pub use self::ignored_any::IgnoredAny;
|
||||||
|
|
||||||
#[cfg(not(any(feature = "std", feature = "unstable")))]
|
#[cfg(all(not(feature = "std"), no_core_error))]
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::std_error::Error as StdError;
|
pub use crate::std_error::Error as StdError;
|
||||||
#[cfg(all(feature = "unstable", not(feature = "std")))]
|
#[cfg(not(any(feature = "std", no_core_error)))]
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use core::error::Error as StdError;
|
pub use core::error::Error as StdError;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@@ -1374,7 +1373,7 @@ pub trait Visitor<'de>: Sized {
|
|||||||
E: Error,
|
E: Error,
|
||||||
{
|
{
|
||||||
let mut buf = [0u8; 58];
|
let mut buf = [0u8; 58];
|
||||||
let mut writer = format::Buf::new(&mut buf);
|
let mut writer = crate::format::Buf::new(&mut buf);
|
||||||
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v)).unwrap();
|
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v)).unwrap();
|
||||||
Err(Error::invalid_type(
|
Err(Error::invalid_type(
|
||||||
Unexpected::Other(writer.as_str()),
|
Unexpected::Other(writer.as_str()),
|
||||||
@@ -1436,7 +1435,7 @@ pub trait Visitor<'de>: Sized {
|
|||||||
E: Error,
|
E: Error,
|
||||||
{
|
{
|
||||||
let mut buf = [0u8; 57];
|
let mut buf = [0u8; 57];
|
||||||
let mut writer = format::Buf::new(&mut buf);
|
let mut writer = crate::format::Buf::new(&mut buf);
|
||||||
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as u128", v)).unwrap();
|
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as u128", v)).unwrap();
|
||||||
Err(Error::invalid_type(
|
Err(Error::invalid_type(
|
||||||
Unexpected::Other(writer.as_str()),
|
Unexpected::Other(writer.as_str()),
|
||||||
|
|||||||
+10
-3
@@ -95,7 +95,7 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Serde types in rustdoc of other crates get linked to here.
|
// Serde types in rustdoc of other crates get linked to here.
|
||||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.207")]
|
#![doc(html_root_url = "https://docs.rs/serde/1.0.210")]
|
||||||
// Support using Serde without the standard library!
|
// Support using Serde without the standard library!
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
// Show which crate feature enables conditionally compiled APIs in documentation.
|
// Show which crate feature enables conditionally compiled APIs in documentation.
|
||||||
@@ -238,8 +238,13 @@ mod lib {
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::ffi::CString;
|
pub use std::ffi::CString;
|
||||||
|
|
||||||
|
#[cfg(all(not(no_core_net), not(feature = "std")))]
|
||||||
|
pub use self::core::net;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::{error, net};
|
pub use std::net;
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub use std::error;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::collections::{HashMap, HashSet};
|
pub use std::collections::{HashMap, HashSet};
|
||||||
@@ -305,6 +310,8 @@ mod integer128;
|
|||||||
pub mod de;
|
pub mod de;
|
||||||
pub mod ser;
|
pub mod ser;
|
||||||
|
|
||||||
|
mod format;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::de::{Deserialize, Deserializer};
|
pub use crate::de::{Deserialize, Deserializer};
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
@@ -318,7 +325,7 @@ pub mod __private;
|
|||||||
#[path = "de/seed.rs"]
|
#[path = "de/seed.rs"]
|
||||||
mod seed;
|
mod seed;
|
||||||
|
|
||||||
#[cfg(not(any(feature = "std", feature = "unstable")))]
|
#[cfg(all(not(feature = "std"), no_core_error))]
|
||||||
mod std_error;
|
mod std_error;
|
||||||
|
|
||||||
// Re-export #[derive(Serialize, Deserialize)].
|
// Re-export #[derive(Serialize, Deserialize)].
|
||||||
|
|||||||
+58
-162
@@ -904,7 +904,9 @@ mod content {
|
|||||||
|
|
||||||
/// Not public API.
|
/// Not public API.
|
||||||
pub struct TagOrContentFieldVisitor {
|
pub struct TagOrContentFieldVisitor {
|
||||||
|
/// Name of the tag field of the adjacently tagged enum
|
||||||
pub tag: &'static str,
|
pub tag: &'static str,
|
||||||
|
/// Name of the content field of the adjacently tagged enum
|
||||||
pub content: &'static str,
|
pub content: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -979,7 +981,9 @@ mod content {
|
|||||||
|
|
||||||
/// Not public API.
|
/// Not public API.
|
||||||
pub struct TagContentOtherFieldVisitor {
|
pub struct TagContentOtherFieldVisitor {
|
||||||
|
/// Name of the tag field of the adjacently tagged enum
|
||||||
pub tag: &'static str,
|
pub tag: &'static str,
|
||||||
|
/// Name of the content field of the adjacently tagged enum
|
||||||
pub content: &'static str,
|
pub content: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1894,10 +1898,19 @@ mod content {
|
|||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
|
// Covered by tests/test_enum_untagged.rs
|
||||||
|
// with_optional_field::*
|
||||||
match *self.content {
|
match *self.content {
|
||||||
Content::None => visitor.visit_none(),
|
Content::None => visitor.visit_none(),
|
||||||
Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)),
|
Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)),
|
||||||
Content::Unit => visitor.visit_unit(),
|
Content::Unit => visitor.visit_unit(),
|
||||||
|
// This case is to support data formats which do not encode an
|
||||||
|
// indication whether a value is optional. An example of such a
|
||||||
|
// format is JSON, and a counterexample is RON. When requesting
|
||||||
|
// `deserialize_any` in JSON, the data format never performs
|
||||||
|
// `Visitor::visit_some` but we still must be able to
|
||||||
|
// deserialize the resulting Content into data structures with
|
||||||
|
// optional fields.
|
||||||
_ => visitor.visit_some(self),
|
_ => visitor.visit_some(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1927,10 +1940,21 @@ mod content {
|
|||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
|
// Covered by tests/test_enum_untagged.rs
|
||||||
|
// newtype_struct
|
||||||
match *self.content {
|
match *self.content {
|
||||||
Content::Newtype(ref v) => {
|
Content::Newtype(ref v) => {
|
||||||
visitor.visit_newtype_struct(ContentRefDeserializer::new(v))
|
visitor.visit_newtype_struct(ContentRefDeserializer::new(v))
|
||||||
}
|
}
|
||||||
|
// This case is to support data formats that encode newtype
|
||||||
|
// structs and their underlying data the same, with no
|
||||||
|
// indication whether a newtype wrapper was present. For example
|
||||||
|
// JSON does this, while RON does not. In RON a newtype's name
|
||||||
|
// is included in the serialized representation and it knows to
|
||||||
|
// call `Visitor::visit_newtype_struct` from `deserialize_any`.
|
||||||
|
// JSON's `deserialize_any` never calls `visit_newtype_struct`
|
||||||
|
// but in this code we still must be able to deserialize the
|
||||||
|
// resulting Content into newtypes.
|
||||||
_ => visitor.visit_newtype_struct(self),
|
_ => visitor.visit_newtype_struct(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2135,6 +2159,10 @@ mod content {
|
|||||||
fn unit_variant(self) -> Result<(), E> {
|
fn unit_variant(self) -> Result<(), E> {
|
||||||
match self.value {
|
match self.value {
|
||||||
Some(value) => de::Deserialize::deserialize(ContentRefDeserializer::new(value)),
|
Some(value) => de::Deserialize::deserialize(ContentRefDeserializer::new(value)),
|
||||||
|
// Covered by tests/test_annotations.rs
|
||||||
|
// test_partially_untagged_adjacently_tagged_enum
|
||||||
|
// Covered by tests/test_enum_untagged.rs
|
||||||
|
// newtype_enum::unit
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2144,6 +2172,11 @@ mod content {
|
|||||||
T: de::DeserializeSeed<'de>,
|
T: de::DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
match self.value {
|
match self.value {
|
||||||
|
// Covered by tests/test_annotations.rs
|
||||||
|
// test_partially_untagged_enum_desugared
|
||||||
|
// test_partially_untagged_enum_generic
|
||||||
|
// Covered by tests/test_enum_untagged.rs
|
||||||
|
// newtype_enum::newtype
|
||||||
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
|
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
|
||||||
None => Err(de::Error::invalid_type(
|
None => Err(de::Error::invalid_type(
|
||||||
de::Unexpected::UnitVariant,
|
de::Unexpected::UnitVariant,
|
||||||
@@ -2157,9 +2190,13 @@ mod content {
|
|||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
match self.value {
|
match self.value {
|
||||||
Some(Content::Seq(v)) => {
|
// Covered by tests/test_annotations.rs
|
||||||
de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor)
|
// test_partially_untagged_enum
|
||||||
}
|
// test_partially_untagged_enum_desugared
|
||||||
|
// Covered by tests/test_enum_untagged.rs
|
||||||
|
// newtype_enum::tuple0
|
||||||
|
// newtype_enum::tuple2
|
||||||
|
Some(Content::Seq(v)) => visit_content_seq_ref(v, visitor),
|
||||||
Some(other) => Err(de::Error::invalid_type(
|
Some(other) => Err(de::Error::invalid_type(
|
||||||
other.unexpected(),
|
other.unexpected(),
|
||||||
&"tuple variant",
|
&"tuple variant",
|
||||||
@@ -2180,12 +2217,13 @@ mod content {
|
|||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
match self.value {
|
match self.value {
|
||||||
Some(Content::Map(v)) => {
|
// Covered by tests/test_enum_untagged.rs
|
||||||
de::Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor)
|
// newtype_enum::struct_from_map
|
||||||
}
|
Some(Content::Map(v)) => visit_content_map_ref(v, visitor),
|
||||||
Some(Content::Seq(v)) => {
|
// Covered by tests/test_enum_untagged.rs
|
||||||
de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor)
|
// newtype_enum::struct_from_seq
|
||||||
}
|
// newtype_enum::empty_struct_from_seq
|
||||||
|
Some(Content::Seq(v)) => visit_content_seq_ref(v, visitor),
|
||||||
Some(other) => Err(de::Error::invalid_type(
|
Some(other) => Err(de::Error::invalid_type(
|
||||||
other.unexpected(),
|
other.unexpected(),
|
||||||
&"struct variant",
|
&"struct variant",
|
||||||
@@ -2198,158 +2236,6 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SeqRefDeserializer<'a, 'de: 'a, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
iter: <&'a [Content<'de>] as IntoIterator>::IntoIter,
|
|
||||||
err: PhantomData<E>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'de, E> SeqRefDeserializer<'a, 'de, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
fn new(slice: &'a [Content<'de>]) -> Self {
|
|
||||||
SeqRefDeserializer {
|
|
||||||
iter: slice.iter(),
|
|
||||||
err: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, 'a, E> de::Deserializer<'de> for SeqRefDeserializer<'a, 'de, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
type Error = E;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
|
|
||||||
where
|
|
||||||
V: de::Visitor<'de>,
|
|
||||||
{
|
|
||||||
let len = self.iter.len();
|
|
||||||
if len == 0 {
|
|
||||||
visitor.visit_unit()
|
|
||||||
} else {
|
|
||||||
let ret = tri!(visitor.visit_seq(&mut self));
|
|
||||||
let remaining = self.iter.len();
|
|
||||||
if remaining == 0 {
|
|
||||||
Ok(ret)
|
|
||||||
} else {
|
|
||||||
Err(de::Error::invalid_length(len, &"fewer elements in array"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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<'de, 'a, E> de::SeqAccess<'de> for SeqRefDeserializer<'a, 'de, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
type Error = E;
|
|
||||||
|
|
||||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
|
||||||
where
|
|
||||||
T: de::DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
match self.iter.next() {
|
|
||||||
Some(value) => seed
|
|
||||||
.deserialize(ContentRefDeserializer::new(value))
|
|
||||||
.map(Some),
|
|
||||||
None => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> Option<usize> {
|
|
||||||
size_hint::from_bounds(&self.iter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MapRefDeserializer<'a, 'de: 'a, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
iter: <&'a [(Content<'de>, Content<'de>)] as IntoIterator>::IntoIter,
|
|
||||||
value: Option<&'a Content<'de>>,
|
|
||||||
err: PhantomData<E>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'de, E> MapRefDeserializer<'a, 'de, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
fn new(map: &'a [(Content<'de>, Content<'de>)]) -> Self {
|
|
||||||
MapRefDeserializer {
|
|
||||||
iter: map.iter(),
|
|
||||||
value: None,
|
|
||||||
err: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, 'a, E> de::MapAccess<'de> for MapRefDeserializer<'a, 'de, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
type Error = E;
|
|
||||||
|
|
||||||
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
|
||||||
where
|
|
||||||
T: de::DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
match self.iter.next() {
|
|
||||||
Some((key, value)) => {
|
|
||||||
self.value = Some(value);
|
|
||||||
seed.deserialize(ContentRefDeserializer::new(key)).map(Some)
|
|
||||||
}
|
|
||||||
None => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
|
|
||||||
where
|
|
||||||
T: de::DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
match self.value.take() {
|
|
||||||
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
|
|
||||||
None => Err(de::Error::custom("value is missing")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> Option<usize> {
|
|
||||||
size_hint::from_bounds(&self.iter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, 'a, E> de::Deserializer<'de> for MapRefDeserializer<'a, 'de, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
type Error = E;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
|
||||||
where
|
|
||||||
V: de::Visitor<'de>,
|
|
||||||
{
|
|
||||||
visitor.visit_map(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
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<'de, E> de::IntoDeserializer<'de, E> for ContentDeserializer<'de, E>
|
impl<'de, E> de::IntoDeserializer<'de, E> for ContentDeserializer<'de, E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
@@ -2710,6 +2596,17 @@ where
|
|||||||
visitor.visit_unit()
|
visitor.visit_unit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_unit_struct<V>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
visitor.visit_unit()
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@@ -2734,7 +2631,6 @@ where
|
|||||||
deserialize_string()
|
deserialize_string()
|
||||||
deserialize_bytes()
|
deserialize_bytes()
|
||||||
deserialize_byte_buf()
|
deserialize_byte_buf()
|
||||||
deserialize_unit_struct(&'static str)
|
|
||||||
deserialize_seq()
|
deserialize_seq()
|
||||||
deserialize_tuple(usize)
|
deserialize_tuple(usize)
|
||||||
deserialize_tuple_struct(&'static str, usize)
|
deserialize_tuple_struct(&'static str, usize)
|
||||||
|
|||||||
@@ -51,8 +51,6 @@ enum Unsupported {
|
|||||||
String,
|
String,
|
||||||
ByteArray,
|
ByteArray,
|
||||||
Optional,
|
Optional,
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
|
||||||
UnitStruct,
|
|
||||||
Sequence,
|
Sequence,
|
||||||
Tuple,
|
Tuple,
|
||||||
TupleStruct,
|
TupleStruct,
|
||||||
@@ -69,8 +67,6 @@ impl Display for Unsupported {
|
|||||||
Unsupported::String => formatter.write_str("a string"),
|
Unsupported::String => formatter.write_str("a string"),
|
||||||
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
||||||
Unsupported::Optional => formatter.write_str("an optional"),
|
Unsupported::Optional => formatter.write_str("an optional"),
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
|
||||||
Unsupported::UnitStruct => formatter.write_str("unit struct"),
|
|
||||||
Unsupported::Sequence => formatter.write_str("a sequence"),
|
Unsupported::Sequence => formatter.write_str("a sequence"),
|
||||||
Unsupported::Tuple => formatter.write_str("a tuple"),
|
Unsupported::Tuple => formatter.write_str("a tuple"),
|
||||||
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
||||||
@@ -1092,7 +1088,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(Self::bad_type(Unsupported::UnitStruct))
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit_variant(
|
fn serialize_unit_variant(
|
||||||
|
|||||||
+13
-29
@@ -773,28 +773,17 @@ impl Serialize for SystemTime {
|
|||||||
/// statically known to never have more than a constant `MAX_LEN` bytes.
|
/// statically known to never have more than a constant `MAX_LEN` bytes.
|
||||||
///
|
///
|
||||||
/// Panics if the `Display` impl tries to write more than `MAX_LEN` bytes.
|
/// Panics if the `Display` impl tries to write more than `MAX_LEN` bytes.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
macro_rules! serialize_display_bounded_length {
|
macro_rules! serialize_display_bounded_length {
|
||||||
($value:expr, $max:expr, $serializer:expr) => {{
|
($value:expr, $max:expr, $serializer:expr) => {{
|
||||||
let mut buffer = [0u8; $max];
|
let mut buffer = [0u8; $max];
|
||||||
let remaining_len = {
|
let mut writer = crate::format::Buf::new(&mut buffer);
|
||||||
let mut remaining = &mut buffer[..];
|
write!(&mut writer, "{}", $value).unwrap();
|
||||||
write!(remaining, "{}", $value).unwrap();
|
$serializer.serialize_str(writer.as_str())
|
||||||
remaining.len()
|
|
||||||
};
|
|
||||||
let written_len = buffer.len() - remaining_len;
|
|
||||||
let written = &buffer[..written_len];
|
|
||||||
|
|
||||||
// write! only provides fmt::Formatter to Display implementations, which
|
|
||||||
// has methods write_str and write_char but no method to write arbitrary
|
|
||||||
// bytes. Therefore `written` must be valid UTF-8.
|
|
||||||
let written_str = str::from_utf8(written).expect("must be valid UTF-8");
|
|
||||||
$serializer.serialize_str(written_str)
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
impl Serialize for net::IpAddr {
|
impl Serialize for net::IpAddr {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -818,7 +807,7 @@ impl Serialize for net::IpAddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
const DEC_DIGITS_LUT: &[u8] = b"\
|
const DEC_DIGITS_LUT: &[u8] = b"\
|
||||||
0001020304050607080910111213141516171819\
|
0001020304050607080910111213141516171819\
|
||||||
2021222324252627282930313233343536373839\
|
2021222324252627282930313233343536373839\
|
||||||
@@ -826,7 +815,7 @@ const DEC_DIGITS_LUT: &[u8] = b"\
|
|||||||
6061626364656667686970717273747576777879\
|
6061626364656667686970717273747576777879\
|
||||||
8081828384858687888990919293949596979899";
|
8081828384858687888990919293949596979899";
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
|
fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
|
||||||
if n >= 100 {
|
if n >= 100 {
|
||||||
@@ -847,7 +836,7 @@ fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_format_u8() {
|
fn test_format_u8() {
|
||||||
let mut i = 0u8;
|
let mut i = 0u8;
|
||||||
@@ -864,8 +853,7 @@ fn test_format_u8() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
impl Serialize for net::Ipv4Addr {
|
impl Serialize for net::Ipv4Addr {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -889,8 +877,7 @@ impl Serialize for net::Ipv4Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
impl Serialize for net::Ipv6Addr {
|
impl Serialize for net::Ipv6Addr {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -906,8 +893,7 @@ impl Serialize for net::Ipv6Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
impl Serialize for net::SocketAddr {
|
impl Serialize for net::SocketAddr {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -931,8 +917,7 @@ impl Serialize for net::SocketAddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
impl Serialize for net::SocketAddrV4 {
|
impl Serialize for net::SocketAddrV4 {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -948,8 +933,7 @@ impl Serialize for net::SocketAddrV4 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
impl Serialize for net::SocketAddrV6 {
|
impl Serialize for net::SocketAddrV6 {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -115,10 +115,10 @@ mod impossible;
|
|||||||
|
|
||||||
pub use self::impossible::Impossible;
|
pub use self::impossible::Impossible;
|
||||||
|
|
||||||
#[cfg(not(any(feature = "std", feature = "unstable")))]
|
#[cfg(all(not(feature = "std"), no_core_error))]
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::std_error::Error as StdError;
|
pub use crate::std_error::Error as StdError;
|
||||||
#[cfg(all(feature = "unstable", not(feature = "std")))]
|
#[cfg(not(any(feature = "std", no_core_error)))]
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use core::error::Error as StdError;
|
pub use core::error::Error as StdError;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.207"
|
version = "1.0.210"
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
categories = ["no-std", "no-std::no-alloc"]
|
categories = ["no-std", "no-std::no-alloc"]
|
||||||
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
//!
|
//!
|
||||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.207")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.210")]
|
||||||
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
|
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
|
||||||
// Ignored clippy lints
|
// Ignored clippy lints
|
||||||
#![allow(
|
#![allow(
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,799 @@
|
|||||||
|
#![deny(trivial_numeric_casts)]
|
||||||
|
#![allow(
|
||||||
|
clippy::derive_partial_eq_without_eq,
|
||||||
|
clippy::enum_variant_names,
|
||||||
|
clippy::redundant_field_names,
|
||||||
|
clippy::too_many_lines
|
||||||
|
)]
|
||||||
|
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(tag = "t", content = "c")]
|
||||||
|
enum AdjacentlyTagged<T> {
|
||||||
|
Unit,
|
||||||
|
Newtype(T),
|
||||||
|
Tuple(u8, u8),
|
||||||
|
Struct { f: u8 },
|
||||||
|
}
|
||||||
|
|
||||||
|
mod unit {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_str_tag_only() {
|
||||||
|
// Map: tag only
|
||||||
|
assert_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: tag only and incorrect hint for number of elements
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_int_tag_only() {
|
||||||
|
// Map: tag (as number) only
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::U16(0),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_bytes_tag_only() {
|
||||||
|
// Map: tag only
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Bytes(b"t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: tag only
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::BorrowedBytes(b"t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_str_tag_content() {
|
||||||
|
// Map: tag + content
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
// Map: content + tag
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: tag + content + excess fields (f, g, h)
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::Str("g"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("h"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_int_tag_content() {
|
||||||
|
// Map: tag (as number) + content (as number)
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::U8(0),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::U8(1),
|
||||||
|
Token::Unit,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: content (as number) + tag (as number)
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::U64(1),
|
||||||
|
Token::Unit,
|
||||||
|
Token::U64(0),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_bytes_tag_content() {
|
||||||
|
// Map: tag + content
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::BorrowedBytes(b"t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::BorrowedBytes(b"c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: content + tag
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Bytes(b"c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Bytes(b"t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq_tag_content() {
|
||||||
|
// Seq: tag and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: Some(2) },
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::Unit,
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Seq: tag (as string) and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: None },
|
||||||
|
Token::Str("Unit"), // tag
|
||||||
|
Token::Unit, // content
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Seq: tag (as borrowed string) and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: None },
|
||||||
|
Token::BorrowedStr("Unit"), // tag
|
||||||
|
Token::Unit, // content
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod newtype {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_tag_only() {
|
||||||
|
// optional newtype with no content field
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Newtype::<Option<u8>>(None),
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_tag_content() {
|
||||||
|
let value = AdjacentlyTagged::Newtype::<u8>(1);
|
||||||
|
|
||||||
|
// Map: tag + content
|
||||||
|
assert_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: content + tag
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq() {
|
||||||
|
let value = AdjacentlyTagged::Newtype::<u8>(1);
|
||||||
|
|
||||||
|
// Seq: tag and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: Some(2) },
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::U8(1),
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Seq: tag (as string) and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: None },
|
||||||
|
Token::Str("Newtype"), // tag
|
||||||
|
Token::U8(1), // content
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Seq: tag (as borrowed string) and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: None },
|
||||||
|
Token::BorrowedStr("Newtype"), // tag
|
||||||
|
Token::U8(1), // content
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_with_newtype() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct NewtypeStruct(u32);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Newtype(NewtypeStruct(5)),
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::NewtypeStruct {
|
||||||
|
name: "NewtypeStruct",
|
||||||
|
},
|
||||||
|
Token::U32(5),
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod tuple {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map() {
|
||||||
|
let value = AdjacentlyTagged::Tuple::<u8>(1, 1);
|
||||||
|
|
||||||
|
// Map: tag + content
|
||||||
|
assert_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Tuple",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Tuple { len: 2 },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::TupleEnd,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: content + tag
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Tuple { len: 2 },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::TupleEnd,
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Tuple",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq() {
|
||||||
|
let value = AdjacentlyTagged::Tuple::<u8>(1, 1);
|
||||||
|
|
||||||
|
// Seq: tag + content
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: Some(2) },
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Tuple",
|
||||||
|
},
|
||||||
|
Token::Tuple { len: 2 },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::TupleEnd,
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod struct_ {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map() {
|
||||||
|
let value = AdjacentlyTagged::Struct::<u8> { f: 1 };
|
||||||
|
|
||||||
|
// Map: tag + content
|
||||||
|
assert_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Struct",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Struct {
|
||||||
|
name: "Struct",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructEnd,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: content + tag
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Struct {
|
||||||
|
name: "Struct",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructEnd,
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Struct",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq() {
|
||||||
|
let value = AdjacentlyTagged::Struct::<u8> { f: 1 };
|
||||||
|
|
||||||
|
// Seq: tag + content
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: Some(2) },
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Struct",
|
||||||
|
},
|
||||||
|
Token::Struct {
|
||||||
|
name: "Struct",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructEnd,
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn struct_with_flatten() {
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
#[serde(tag = "t", content = "c")]
|
||||||
|
enum Data {
|
||||||
|
A {
|
||||||
|
a: i32,
|
||||||
|
#[serde(flatten)]
|
||||||
|
flat: Flat,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct Flat {
|
||||||
|
b: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = Data::A {
|
||||||
|
a: 0,
|
||||||
|
flat: Flat { b: 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&data,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Data",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "Data",
|
||||||
|
variant: "A",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(0),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::I32(0),
|
||||||
|
Token::MapEnd,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn expecting_message() {
|
||||||
|
#[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],
|
||||||
|
"invalid type: unit value, expected variant of enum Enum",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn partially_untagged() {
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
#[serde(tag = "t", content = "c")]
|
||||||
|
enum Data {
|
||||||
|
A(u32),
|
||||||
|
B,
|
||||||
|
#[serde(untagged)]
|
||||||
|
Var(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = Data::A(7);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&data,
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::Str("A"),
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::U32(7),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let data = Data::Var(42);
|
||||||
|
|
||||||
|
assert_de_tokens(&data, &[Token::U32(42)]);
|
||||||
|
|
||||||
|
// TODO test error output
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deny_unknown_fields() {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(tag = "t", content = "c", deny_unknown_fields)]
|
||||||
|
enum AdjacentlyTagged {
|
||||||
|
Unit,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("h"),
|
||||||
|
],
|
||||||
|
r#"invalid value: string "h", expected "t" or "c""#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("h"),
|
||||||
|
],
|
||||||
|
r#"invalid value: string "h", expected "t" or "c""#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("h"),
|
||||||
|
],
|
||||||
|
r#"invalid value: string "h", expected "t" or "c""#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::U64(0), // tag field
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::U64(3),
|
||||||
|
],
|
||||||
|
r#"invalid value: integer `3`, expected "t" or "c""#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Bytes(b"c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Bytes(b"h"),
|
||||||
|
],
|
||||||
|
r#"invalid value: byte array, expected "t" or "c""#,
|
||||||
|
);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,583 @@
|
|||||||
|
#![deny(trivial_numeric_casts)]
|
||||||
|
#![allow(
|
||||||
|
clippy::derive_partial_eq_without_eq,
|
||||||
|
clippy::enum_variant_names,
|
||||||
|
clippy::redundant_field_names,
|
||||||
|
clippy::too_many_lines
|
||||||
|
)]
|
||||||
|
|
||||||
|
mod bytes;
|
||||||
|
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn complex() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Untagged {
|
||||||
|
A { a: u8 },
|
||||||
|
B { b: u8 },
|
||||||
|
C,
|
||||||
|
D(u8),
|
||||||
|
E(String),
|
||||||
|
F(u8, u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Untagged::A { a: 1 },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Untagged::B { b: 2 },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::U8(2),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Serializes to unit, deserializes from either depending on format's
|
||||||
|
// preference.
|
||||||
|
assert_tokens(&Untagged::C, &[Token::Unit]);
|
||||||
|
assert_de_tokens(&Untagged::C, &[Token::None]);
|
||||||
|
|
||||||
|
assert_tokens(&Untagged::D(4), &[Token::U8(4)]);
|
||||||
|
assert_tokens(&Untagged::E("e".to_owned()), &[Token::Str("e")]);
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Untagged::F(1, 2),
|
||||||
|
&[
|
||||||
|
Token::Tuple { len: 2 },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(2),
|
||||||
|
Token::TupleEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<Untagged>(
|
||||||
|
&[Token::Tuple { len: 1 }, Token::U8(1), Token::TupleEnd],
|
||||||
|
"data did not match any variant of untagged enum Untagged",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<Untagged>(
|
||||||
|
&[
|
||||||
|
Token::Tuple { len: 3 },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(2),
|
||||||
|
Token::U8(3),
|
||||||
|
Token::TupleEnd,
|
||||||
|
],
|
||||||
|
"data did not match any variant of untagged enum Untagged",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_unit_and_empty_map() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct Unit;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Message {
|
||||||
|
Unit(Unit),
|
||||||
|
Map(BTreeMap<String, String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Message::Map(BTreeMap::new()),
|
||||||
|
&[Token::Map { len: Some(0) }, Token::MapEnd],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::ContentRefDeserializer::deserialize_newtype_struct
|
||||||
|
#[test]
|
||||||
|
fn newtype_struct() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct NewtypeStruct(u32);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum E {
|
||||||
|
Newtype(NewtypeStruct),
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = E::Newtype(NewtypeStruct(5));
|
||||||
|
|
||||||
|
// Content::Newtype case
|
||||||
|
assert_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::NewtypeStruct {
|
||||||
|
name: "NewtypeStruct",
|
||||||
|
},
|
||||||
|
Token::U32(5),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// _ case
|
||||||
|
assert_de_tokens(&value, &[Token::U32(5)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod newtype_enum {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Outer {
|
||||||
|
Inner(Inner),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
enum Inner {
|
||||||
|
Unit,
|
||||||
|
Newtype(u8),
|
||||||
|
Tuple0(),
|
||||||
|
Tuple2(u8, u8),
|
||||||
|
Struct { f: u8 },
|
||||||
|
EmptyStruct {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::unit_variant
|
||||||
|
#[test]
|
||||||
|
fn unit() {
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Inner(Inner::Unit),
|
||||||
|
&[Token::UnitVariant {
|
||||||
|
name: "Inner",
|
||||||
|
variant: "Unit",
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::newtype_variant_seed
|
||||||
|
#[test]
|
||||||
|
fn newtype() {
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Inner(Inner::Newtype(1)),
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant {
|
||||||
|
name: "Inner",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::U8(1),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::tuple_variant
|
||||||
|
#[test]
|
||||||
|
fn tuple0() {
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Inner(Inner::Tuple0()),
|
||||||
|
&[
|
||||||
|
Token::TupleVariant {
|
||||||
|
name: "Inner",
|
||||||
|
variant: "Tuple0",
|
||||||
|
len: 0,
|
||||||
|
},
|
||||||
|
Token::TupleVariantEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::tuple_variant
|
||||||
|
#[test]
|
||||||
|
fn tuple2() {
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Inner(Inner::Tuple2(1, 1)),
|
||||||
|
&[
|
||||||
|
Token::TupleVariant {
|
||||||
|
name: "Inner",
|
||||||
|
variant: "Tuple2",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::TupleVariantEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||||
|
// Content::Map case
|
||||||
|
#[test]
|
||||||
|
fn struct_from_map() {
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Inner(Inner::Struct { f: 1 }),
|
||||||
|
&[
|
||||||
|
Token::StructVariant {
|
||||||
|
name: "Inner",
|
||||||
|
variant: "Struct",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructVariantEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||||
|
// Content::Seq case
|
||||||
|
#[test]
|
||||||
|
fn struct_from_seq() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&Outer::Inner(Inner::Struct { f: 1 }),
|
||||||
|
&[
|
||||||
|
Token::Map { len: Some(1) },
|
||||||
|
// tag
|
||||||
|
Token::Str("Struct"),
|
||||||
|
// content
|
||||||
|
Token::Seq { len: Some(1) },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::SeqEnd,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||||
|
// Content::Map case
|
||||||
|
// Special case - empty map
|
||||||
|
#[test]
|
||||||
|
fn empty_struct_from_map() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&Outer::Inner(Inner::EmptyStruct {}),
|
||||||
|
&[
|
||||||
|
Token::Map { len: Some(1) },
|
||||||
|
// tag
|
||||||
|
Token::Str("EmptyStruct"),
|
||||||
|
// content
|
||||||
|
Token::Map { len: Some(0) },
|
||||||
|
Token::MapEnd,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||||
|
// Content::Seq case
|
||||||
|
// Special case - empty seq
|
||||||
|
#[test]
|
||||||
|
fn empty_struct_from_seq() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&Outer::Inner(Inner::EmptyStruct {}),
|
||||||
|
&[
|
||||||
|
Token::Map { len: Some(1) },
|
||||||
|
// tag
|
||||||
|
Token::Str("EmptyStruct"),
|
||||||
|
// content
|
||||||
|
Token::Seq { len: Some(0) },
|
||||||
|
Token::SeqEnd,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::ContentRefDeserializer::deserialize_option
|
||||||
|
mod with_optional_field {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Enum {
|
||||||
|
Struct { optional: Option<u32> },
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn some() {
|
||||||
|
assert_tokens(
|
||||||
|
&Enum::Struct { optional: Some(42) },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Enum",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("optional"),
|
||||||
|
Token::Some,
|
||||||
|
Token::U32(42),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn some_without_marker() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&Enum::Struct { optional: Some(42) },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Enum",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("optional"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn none() {
|
||||||
|
assert_tokens(
|
||||||
|
&Enum::Struct { optional: None },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Enum",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("optional"),
|
||||||
|
Token::None,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unit() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&Enum::Struct { optional: None },
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("optional"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_and_bytes() {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Untagged {
|
||||||
|
String {
|
||||||
|
string: String,
|
||||||
|
},
|
||||||
|
Bytes {
|
||||||
|
#[serde(with = "bytes")]
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::String {
|
||||||
|
string: "\0".to_owned(),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("string"),
|
||||||
|
Token::Str("\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::String {
|
||||||
|
string: "\0".to_owned(),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("string"),
|
||||||
|
Token::String("\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::String {
|
||||||
|
string: "\0".to_owned(),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("string"),
|
||||||
|
Token::Bytes(b"\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::String {
|
||||||
|
string: "\0".to_owned(),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("string"),
|
||||||
|
Token::ByteBuf(b"\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::Bytes { bytes: vec![0] },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("bytes"),
|
||||||
|
Token::Str("\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::Bytes { bytes: vec![0] },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("bytes"),
|
||||||
|
Token::String("\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::Bytes { bytes: vec![0] },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("bytes"),
|
||||||
|
Token::Bytes(b"\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::Bytes { bytes: vec![0] },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("bytes"),
|
||||||
|
Token::ByteBuf(b"\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::Bytes { bytes: vec![0] },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("bytes"),
|
||||||
|
Token::Seq { len: Some(1) },
|
||||||
|
Token::U8(0),
|
||||||
|
Token::SeqEnd,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn contains_flatten() {
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Data {
|
||||||
|
A {
|
||||||
|
a: i32,
|
||||||
|
#[serde(flatten)]
|
||||||
|
flat: Flat,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct Flat {
|
||||||
|
b: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = Data::A {
|
||||||
|
a: 0,
|
||||||
|
flat: Flat { b: 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&data,
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(0),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::I32(0),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn contains_flatten_with_integer_key() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Untagged {
|
||||||
|
Variant {
|
||||||
|
#[serde(flatten)]
|
||||||
|
map: BTreeMap<u64, String>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Untagged::Variant {
|
||||||
|
map: {
|
||||||
|
let mut map = BTreeMap::new();
|
||||||
|
map.insert(100, "BTreeMap".to_owned());
|
||||||
|
map
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::U64(100),
|
||||||
|
Token::Str("BTreeMap"),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn expecting_message() {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
#[serde(expecting = "something strange...")]
|
||||||
|
enum Enum {
|
||||||
|
Untagged,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens_error::<Enum>(&[Token::Str("Untagged")], "something strange...");
|
||||||
|
}
|
||||||
+1
-1397
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user