mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-22 21:48:02 +00:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 422191fcb0 | |||
| 4ba748c902 | |||
| 14ed6f2dab | |||
| 30606a43aa | |||
| 9be3d32016 | |||
| 5daf1b89a1 | |||
| f8f5d0ca2f | |||
| 57873cce28 | |||
| 4ed0362c8e | |||
| 4cecaf8d02 | |||
| 50c696aabe | |||
| 2f58a20bc6 | |||
| 030459a040 | |||
| e9b530a000 | |||
| ea1a729088 | |||
| 857dcea774 | |||
| b98a9a8f9b | |||
| 3b135431fd | |||
| 945d12c0b4 | |||
| e36915300f | |||
| 85c05d301a | |||
| c2474bf6ee | |||
| a52f436788 | |||
| ad3335e5d6 | |||
| 4b00de0e22 | |||
| 8403fa018e | |||
| 0e9f1b42de | |||
| 0085d05e55 | |||
| 2eed855bff | |||
| c3eced410f | |||
| 8a630fea7c | |||
| 2e597ed3f0 | |||
| 0963121beb | |||
| 15b2714058 | |||
| 9ce107de25 | |||
| e47284c0e0 | |||
| 800620e2aa | |||
| 40c670e625 | |||
| ba260b0e5f | |||
| 8452e313cc | |||
| 0dccbb1f11 | |||
| deca49315a | |||
| 95407a4ca5 | |||
| 2fe9a860cd | |||
| e67d941b78 | |||
| d4042872f5 | |||
| 64af86b830 | |||
| 370c8a91cb | |||
| 972da59ebc | |||
| a42008f695 | |||
| e4ea2a56e9 | |||
| 7650a48fdd | |||
| d665a2f2b2 | |||
| 44e23254c9 | |||
| 552971196d | |||
| 0681cd5003 | |||
| d965367238 | |||
| a6df35b3d2 | |||
| 9fc180e62f | |||
| 5b815b7001 | |||
| 4831482695 | |||
| d3e5dd9cd7 | |||
| 8e8694261b |
+1
-1
@@ -22,7 +22,7 @@ efforts from contributors on the same issue.
|
||||
master you may be asked to rebase your changes.
|
||||
|
||||
- Commits should be as small as possible, while ensuring that each commit is
|
||||
correct independently (i.e., each commit should compile and pass tests).
|
||||
correct independently (i.e., each commit should compile and pass tests).
|
||||
|
||||
- If your patch is not getting reviewed or you need a specific person to review
|
||||
it, you can @-reply a reviewer asking for a review in the pull request or a
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "1.0.11" # remember to update html_root_url
|
||||
version = "1.0.16" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
|
||||
+210
-76
@@ -869,37 +869,206 @@ map_impl!(
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
macro_rules! parse_impl {
|
||||
($ty:ty) => {
|
||||
macro_rules! parse_ip_impl {
|
||||
($ty:ty; $size: expr) => {
|
||||
impl<'de> Deserialize<'de> for $ty {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = try!(String::deserialize(deserializer));
|
||||
s.parse().map_err(Error::custom)
|
||||
if deserializer.is_human_readable() {
|
||||
let s = try!(String::deserialize(deserializer));
|
||||
s.parse().map_err(Error::custom)
|
||||
} else {
|
||||
<[u8; $size]>::deserialize(deserializer).map(<$ty>::from)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::IpAddr);
|
||||
macro_rules! variant_identifier {
|
||||
(
|
||||
$name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* )
|
||||
$expecting_message: expr,
|
||||
$variants_name: ident
|
||||
) => {
|
||||
enum $name_kind {
|
||||
$( $variant ),*
|
||||
}
|
||||
|
||||
static $variants_name: &'static [&'static str] = &[ $( stringify!($variant) ),*];
|
||||
|
||||
impl<'de> Deserialize<'de> for $name_kind {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct KindVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for KindVisitor {
|
||||
type Value = $name_kind;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str($expecting_message)
|
||||
}
|
||||
|
||||
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
$(
|
||||
$index => Ok($name_kind :: $variant),
|
||||
)*
|
||||
_ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
$(
|
||||
stringify!($variant) => Ok($name_kind :: $variant),
|
||||
)*
|
||||
_ => Err(Error::unknown_variant(value, $variants_name)),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
$(
|
||||
$bytes => Ok($name_kind :: $variant),
|
||||
)*
|
||||
_ => {
|
||||
match str::from_utf8(value) {
|
||||
Ok(value) => Err(Error::unknown_variant(value, $variants_name)),
|
||||
Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_identifier(KindVisitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::Ipv4Addr);
|
||||
macro_rules! deserialize_enum {
|
||||
(
|
||||
$name: ident $name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* )
|
||||
$expecting_message: expr,
|
||||
$deserializer: expr
|
||||
) => {
|
||||
variant_identifier!{
|
||||
$name_kind ( $($variant; $bytes; $index),* )
|
||||
$expecting_message,
|
||||
VARIANTS
|
||||
}
|
||||
|
||||
struct EnumVisitor;
|
||||
impl<'de> Visitor<'de> for EnumVisitor {
|
||||
type Value = $name;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(concat!("a ", stringify!($name)))
|
||||
}
|
||||
|
||||
|
||||
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: EnumAccess<'de>,
|
||||
{
|
||||
match try!(data.variant()) {
|
||||
$(
|
||||
($name_kind :: $variant, v) => v.newtype_variant().map($name :: $variant),
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
$deserializer.deserialize_enum(stringify!($name), VARIANTS, EnumVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::Ipv6Addr);
|
||||
impl<'de> Deserialize<'de> for net::IpAddr {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
let s = try!(String::deserialize(deserializer));
|
||||
s.parse().map_err(Error::custom)
|
||||
} else {
|
||||
use lib::net::IpAddr;
|
||||
deserialize_enum!{
|
||||
IpAddr IpAddrKind (V4; b"V4"; 0, V6; b"V6"; 1)
|
||||
"`V4` or `V6`",
|
||||
deserializer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::SocketAddr);
|
||||
parse_ip_impl!(net::Ipv4Addr; 4);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::SocketAddrV4);
|
||||
parse_ip_impl!(net::Ipv6Addr; 16);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::SocketAddrV6);
|
||||
macro_rules! parse_socket_impl {
|
||||
($ty:ty, $new: expr) => {
|
||||
impl<'de> Deserialize<'de> for $ty {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
let s = try!(String::deserialize(deserializer));
|
||||
s.parse().map_err(Error::custom)
|
||||
} else {
|
||||
<(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de> Deserialize<'de> for net::SocketAddr {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
let s = try!(String::deserialize(deserializer));
|
||||
s.parse().map_err(Error::custom)
|
||||
} else {
|
||||
use lib::net::SocketAddr;
|
||||
deserialize_enum!{
|
||||
SocketAddr SocketAddrKind (V4; b"V4"; 0, V6; b"V6"; 1)
|
||||
"`V4` or `V6`",
|
||||
deserializer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_socket_impl!(net::SocketAddrV4, net::SocketAddrV4::new);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_socket_impl!(net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(ip, port, 0, 0));
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -984,70 +1153,10 @@ impl<'de> Deserialize<'de> for PathBuf {
|
||||
// #[derive(Deserialize)]
|
||||
// #[serde(variant_identifier)]
|
||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||
enum OsStringKind {
|
||||
Unix,
|
||||
Windows,
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||
static OSSTR_VARIANTS: &'static [&'static str] = &["Unix", "Windows"];
|
||||
|
||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||
impl<'de> Deserialize<'de> for OsStringKind {
|
||||
fn deserialize<D>(deserializer: D) -> Result<OsStringKind, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct KindVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for KindVisitor {
|
||||
type Value = OsStringKind;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("`Unix` or `Windows`")
|
||||
}
|
||||
|
||||
fn visit_u32<E>(self, value: u32) -> Result<OsStringKind, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
0 => Ok(OsStringKind::Unix),
|
||||
1 => Ok(OsStringKind::Windows),
|
||||
_ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<OsStringKind, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
"Unix" => Ok(OsStringKind::Unix),
|
||||
"Windows" => Ok(OsStringKind::Windows),
|
||||
_ => Err(Error::unknown_variant(value, OSSTR_VARIANTS)),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, value: &[u8]) -> Result<OsStringKind, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
b"Unix" => Ok(OsStringKind::Unix),
|
||||
b"Windows" => Ok(OsStringKind::Windows),
|
||||
_ => {
|
||||
match str::from_utf8(value) {
|
||||
Ok(value) => Err(Error::unknown_variant(value, OSSTR_VARIANTS)),
|
||||
Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_identifier(KindVisitor)
|
||||
}
|
||||
variant_identifier!{
|
||||
OsStringKind (Unix; b"Unix"; 0, Windows; b"Windows"; 1)
|
||||
"`Unix` or `Windows`",
|
||||
OSSTR_VARIANTS
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||
@@ -1112,10 +1221,10 @@ forwarded_impl!((T), Box<[T]>, Vec::into_boxed_slice);
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
forwarded_impl!((), Box<str>, String::into_boxed_str);
|
||||
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
#[cfg(all(not(feature = "unstable"), feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
forwarded_impl!((T), Arc<T>, Arc::new);
|
||||
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
#[cfg(all(not(feature = "unstable"), feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
forwarded_impl!((T), Rc<T>, Rc::new);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
@@ -1135,6 +1244,31 @@ where
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
macro_rules! box_forwarded_impl {
|
||||
($t:ident) => {
|
||||
impl<'de, T: ?Sized> Deserialize<'de> for $t<T>
|
||||
where
|
||||
Box<T>: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Box::deserialize(deserializer).map(Into::into)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
box_forwarded_impl!(Rc);
|
||||
|
||||
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
box_forwarded_impl!(Arc);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<'de, T> Deserialize<'de> for Cell<T>
|
||||
where
|
||||
T: Deserialize<'de> + Copy,
|
||||
|
||||
+68
-2
@@ -1011,6 +1011,72 @@ pub trait Deserializer<'de>: Sized {
|
||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>;
|
||||
|
||||
/// Determine whether `Deserialize` implementations should expect to
|
||||
/// deserialize their human-readable form.
|
||||
///
|
||||
/// Some types have a human-readable form that may be somewhat expensive to
|
||||
/// construct, as well as a binary form that is compact and efficient.
|
||||
/// Generally text-based formats like JSON and YAML will prefer to use the
|
||||
/// human-readable one and binary formats like Bincode will prefer the
|
||||
/// compact one.
|
||||
///
|
||||
/// ```
|
||||
/// # use std::ops::Add;
|
||||
/// # use std::str::FromStr;
|
||||
/// #
|
||||
/// # struct Timestamp;
|
||||
/// #
|
||||
/// # impl FromStr for Timestamp {
|
||||
/// # type Err = String;
|
||||
/// # fn from_str(_: &str) -> Result<Self, Self::Err> {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// # struct Duration;
|
||||
/// #
|
||||
/// # impl Duration {
|
||||
/// # fn seconds(_: u64) -> Self { unimplemented!() }
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl Add<Duration> for () {
|
||||
/// # type Output = Timestamp;
|
||||
/// # fn add(self, _: Duration) -> Self::Output {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// use serde::de::{self, Deserialize, Deserializer};
|
||||
///
|
||||
/// impl<'de> Deserialize<'de> for Timestamp {
|
||||
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
/// where D: Deserializer<'de>
|
||||
/// {
|
||||
/// if deserializer.is_human_readable() {
|
||||
/// // Deserialize from a human-readable string like "2015-05-15T17:01:00Z".
|
||||
/// let s = String::deserialize(deserializer)?;
|
||||
/// Timestamp::from_str(&s).map_err(de::Error::custom)
|
||||
/// } else {
|
||||
/// # // Make it look like an associated constant but compile on older rustc.
|
||||
/// # mod Timestamp { pub const EPOCH: () = (); }
|
||||
/// // Deserialize from a compact binary representation, seconds since
|
||||
/// // the Unix epoch.
|
||||
/// let n = u64::deserialize(deserializer)?;
|
||||
/// Ok(Timestamp::EPOCH + Duration::seconds(n))
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The default implementation of this method returns `true`. Data formats
|
||||
/// may override this to `false` to request a compact form for types that
|
||||
/// support one. Note that modifying this method to change a format from
|
||||
/// human-readable to compact or vice versa should be regarded as a breaking
|
||||
/// change, as a value serialized in human-readable mode is not required to
|
||||
/// deserialize from the same data in compact mode.
|
||||
#[inline]
|
||||
fn is_human_readable(&self) -> bool { true }
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1120,7 +1186,7 @@ pub trait Visitor<'de>: Sized {
|
||||
self.visit_i64(v as i64)
|
||||
}
|
||||
|
||||
/// The input contains an `i32`.
|
||||
/// The input contains an `i64`.
|
||||
///
|
||||
/// The default implementation fails with a type error.
|
||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||
@@ -1424,7 +1490,7 @@ pub trait SeqAccess<'de> {
|
||||
/// `Ok(None)` if there are no more remaining items.
|
||||
///
|
||||
/// `Deserialize` implementations should typically use
|
||||
/// `SeqAcccess::next_element` instead.
|
||||
/// `SeqAccess::next_element` instead.
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>;
|
||||
|
||||
@@ -733,7 +733,7 @@ where
|
||||
T: IntoDeserializer<'de, E>,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = SeqDeserializer<<Vec<T> as IntoIterator>::IntoIter, E>;
|
||||
type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
SeqDeserializer::new(self.into_iter())
|
||||
@@ -746,7 +746,7 @@ where
|
||||
T: IntoDeserializer<'de, E> + Eq + Ord,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = SeqDeserializer<<BTreeSet<T> as IntoIterator>::IntoIter, E>;
|
||||
type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
SeqDeserializer::new(self.into_iter())
|
||||
@@ -754,12 +754,13 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de, T, E> IntoDeserializer<'de, E> for HashSet<T>
|
||||
impl<'de, T, S, E> IntoDeserializer<'de, E> for HashSet<T, S>
|
||||
where
|
||||
T: IntoDeserializer<'de, E> + Eq + Hash,
|
||||
S: BuildHasher,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = SeqDeserializer<<HashSet<T> as IntoIterator>::IntoIter, E>;
|
||||
type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
SeqDeserializer::new(self.into_iter())
|
||||
@@ -1152,7 +1153,7 @@ where
|
||||
V: IntoDeserializer<'de, E>,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = MapDeserializer<'de, <BTreeMap<K, V> as IntoIterator>::IntoIter, E>;
|
||||
type Deserializer = MapDeserializer<'de, <Self as IntoIterator>::IntoIter, E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
MapDeserializer::new(self.into_iter())
|
||||
@@ -1160,13 +1161,14 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de, K, V, E> IntoDeserializer<'de, E> for HashMap<K, V>
|
||||
impl<'de, K, V, S, E> IntoDeserializer<'de, E> for HashMap<K, V, S>
|
||||
where
|
||||
K: IntoDeserializer<'de, E> + Eq + Hash,
|
||||
V: IntoDeserializer<'de, E>,
|
||||
S: BuildHasher,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = MapDeserializer<'de, <HashMap<K, V> as IntoIterator>::IntoIter, E>;
|
||||
type Deserializer = MapDeserializer<'de, <Self as IntoIterator>::IntoIter, E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
MapDeserializer::new(self.into_iter())
|
||||
|
||||
+33
-7
@@ -79,7 +79,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Serde types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.11")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.16")]
|
||||
|
||||
// Support using Serde without the standard library!
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
@@ -89,14 +89,40 @@
|
||||
//
|
||||
// https://github.com/serde-rs/serde/issues/812
|
||||
#![cfg_attr(feature = "unstable", feature(nonzero, specialization))]
|
||||
#![cfg_attr(all(feature = "std", feature = "unstable"), feature(into_boxed_c_str))]
|
||||
#![cfg_attr(feature = "alloc", feature(alloc))]
|
||||
|
||||
// Whitelisted clippy lints.
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(doc_markdown))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(linkedlist))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(zero_prefixed_literal))]
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||
// Whitelisted clippy lints
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(
|
||||
cast_lossless,
|
||||
doc_markdown,
|
||||
linkedlist,
|
||||
type_complexity,
|
||||
unreadable_literal,
|
||||
zero_prefixed_literal,
|
||||
))]
|
||||
// Whitelisted clippy_pedantic lints
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(
|
||||
// integer and float ser/de requires these sorts of casts
|
||||
cast_possible_truncation,
|
||||
cast_possible_wrap,
|
||||
cast_precision_loss,
|
||||
cast_sign_loss,
|
||||
// simplifies some macros
|
||||
invalid_upcast_comparisons,
|
||||
// things are often more readable this way
|
||||
option_unwrap_used,
|
||||
result_unwrap_used,
|
||||
shadow_reuse,
|
||||
single_match_else,
|
||||
stutter,
|
||||
use_self,
|
||||
// not practical
|
||||
missing_docs_in_private_items,
|
||||
// alternative is not stable
|
||||
empty_enum,
|
||||
use_debug,
|
||||
))]
|
||||
|
||||
// Blacklisted Rust lints.
|
||||
#![deny(missing_docs, unused_imports)]
|
||||
|
||||
+33
-9
@@ -834,26 +834,43 @@ mod content {
|
||||
type Value = TaggedContent<'de, T>;
|
||||
|
||||
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.write_str("any value")
|
||||
fmt.write_str("internally tagged enum")
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
|
||||
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
|
||||
where
|
||||
V: MapAccess<'de>,
|
||||
S: SeqAccess<'de>,
|
||||
{
|
||||
let tag = match try!(seq.next_element()) {
|
||||
Some(tag) => tag,
|
||||
None => {
|
||||
return Err(de::Error::missing_field(self.tag_name));
|
||||
}
|
||||
};
|
||||
let rest = de::value::SeqAccessDeserializer::new(seq);
|
||||
Ok(TaggedContent {
|
||||
tag: tag,
|
||||
content: try!(Content::deserialize(rest)),
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let mut tag = None;
|
||||
let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint()));
|
||||
let mut vec = Vec::with_capacity(size_hint::cautious(map.size_hint()));
|
||||
while let Some(k) =
|
||||
try!(visitor.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
|
||||
try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
|
||||
match k {
|
||||
TagOrContent::Tag => {
|
||||
if tag.is_some() {
|
||||
return Err(de::Error::duplicate_field(self.tag_name));
|
||||
}
|
||||
tag = Some(try!(visitor.next_value()));
|
||||
tag = Some(try!(map.next_value()));
|
||||
}
|
||||
TagOrContent::Content(k) => {
|
||||
let v = try!(visitor.next_value());
|
||||
let v = try!(map.next_value());
|
||||
vec.push((k, v));
|
||||
}
|
||||
}
|
||||
@@ -1802,9 +1819,16 @@ mod content {
|
||||
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name)
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, _: V) -> Result<(), V::Error>
|
||||
fn visit_seq<S>(self, _: S) -> Result<(), S::Error>
|
||||
where
|
||||
V: MapAccess<'de>,
|
||||
S: SeqAccess<'de>,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, _: M) -> Result<(), M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+54
-20
@@ -340,10 +340,10 @@ deref_impl!(<'a, T: ?Sized> Serialize for &'a mut T where T: Serialize);
|
||||
deref_impl!(<T: ?Sized> Serialize for Box<T> where T: Serialize);
|
||||
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
deref_impl!(<T> Serialize for Rc<T> where T: Serialize);
|
||||
deref_impl!(<T: ?Sized> Serialize for Rc<T> where T: Serialize);
|
||||
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
deref_impl!(<T> Serialize for Arc<T> where T: Serialize);
|
||||
deref_impl!(<T: ?Sized> Serialize for Arc<T> where T: Serialize);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned);
|
||||
@@ -506,9 +506,18 @@ impl Serialize for net::IpAddr {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
net::IpAddr::V4(ref a) => a.serialize(serializer),
|
||||
net::IpAddr::V6(ref a) => a.serialize(serializer),
|
||||
if serializer.is_human_readable() {
|
||||
match *self {
|
||||
net::IpAddr::V4(ref a) => a.serialize(serializer),
|
||||
net::IpAddr::V6(ref a) => a.serialize(serializer),
|
||||
}
|
||||
} else {
|
||||
match *self {
|
||||
net::IpAddr::V4(ref a) =>
|
||||
serializer.serialize_newtype_variant("IpAddr", 0, "V4", a),
|
||||
net::IpAddr::V6(ref a) =>
|
||||
serializer.serialize_newtype_variant("IpAddr", 1, "V6", a),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -519,9 +528,13 @@ impl Serialize for net::Ipv4Addr {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
/// "101.102.103.104".len()
|
||||
const MAX_LEN: usize = 15;
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
if serializer.is_human_readable() {
|
||||
const MAX_LEN: usize = 15;
|
||||
debug_assert_eq!(MAX_LEN, "101.102.103.104".len());
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
} else {
|
||||
self.octets().serialize(serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,9 +544,13 @@ impl Serialize for net::Ipv6Addr {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
/// "1000:1002:1003:1004:1005:1006:1007:1008".len()
|
||||
const MAX_LEN: usize = 39;
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
if serializer.is_human_readable() {
|
||||
const MAX_LEN: usize = 39;
|
||||
debug_assert_eq!(MAX_LEN, "1001:1002:1003:1004:1005:1006:1007:1008".len());
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
} else {
|
||||
self.octets().serialize(serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,9 +560,18 @@ impl Serialize for net::SocketAddr {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
net::SocketAddr::V4(ref addr) => addr.serialize(serializer),
|
||||
net::SocketAddr::V6(ref addr) => addr.serialize(serializer),
|
||||
if serializer.is_human_readable() {
|
||||
match *self {
|
||||
net::SocketAddr::V4(ref addr) => addr.serialize(serializer),
|
||||
net::SocketAddr::V6(ref addr) => addr.serialize(serializer),
|
||||
}
|
||||
} else {
|
||||
match *self {
|
||||
net::SocketAddr::V4(ref addr) =>
|
||||
serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr),
|
||||
net::SocketAddr::V6(ref addr) =>
|
||||
serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -556,9 +582,13 @@ impl Serialize for net::SocketAddrV4 {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
/// "101.102.103.104:65000".len()
|
||||
const MAX_LEN: usize = 21;
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
if serializer.is_human_readable() {
|
||||
const MAX_LEN: usize = 21;
|
||||
debug_assert_eq!(MAX_LEN, "101.102.103.104:65000".len());
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
} else {
|
||||
(self.ip(), self.port()).serialize(serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,9 +598,13 @@ impl Serialize for net::SocketAddrV6 {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
/// "[1000:1002:1003:1004:1005:1006:1007:1008]:65000".len()
|
||||
const MAX_LEN: usize = 47;
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
if serializer.is_human_readable() {
|
||||
const MAX_LEN: usize = 47;
|
||||
debug_assert_eq!(MAX_LEN, "[1001:1002:1003:1004:1005:1006:1007:1008]:65000".len());
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
} else {
|
||||
(self.ip(), self.port()).serialize(serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1363,6 +1363,56 @@ pub trait Serializer: Sized {
|
||||
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Display;
|
||||
|
||||
/// Determine whether `Serialize` implementations should serialize in
|
||||
/// human-readable form.
|
||||
///
|
||||
/// Some types have a human-readable form that may be somewhat expensive to
|
||||
/// construct, as well as a binary form that is compact and efficient.
|
||||
/// Generally text-based formats like JSON and YAML will prefer to use the
|
||||
/// human-readable one and binary formats like Bincode will prefer the
|
||||
/// compact one.
|
||||
///
|
||||
/// ```
|
||||
/// # use std::fmt::{self, Display};
|
||||
/// #
|
||||
/// # struct Timestamp;
|
||||
/// #
|
||||
/// # impl Timestamp {
|
||||
/// # fn seconds_since_epoch(&self) -> u64 { unimplemented!() }
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl Display for Timestamp {
|
||||
/// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// use serde::{Serialize, Serializer};
|
||||
///
|
||||
/// impl Serialize for Timestamp {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
/// where S: Serializer
|
||||
/// {
|
||||
/// if serializer.is_human_readable() {
|
||||
/// // Serialize to a human-readable string "2015-05-15T17:01:00Z".
|
||||
/// self.to_string().serialize(serializer)
|
||||
/// } else {
|
||||
/// // Serialize to a compact binary representation.
|
||||
/// self.seconds_since_epoch().serialize(serializer)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The default implementation of this method returns `true`. Data formats
|
||||
/// may override this to `false` to request a compact form for types that
|
||||
/// support one. Note that modifying this method to change a format from
|
||||
/// human-readable to compact or vice versa should be regarded as a breaking
|
||||
/// change, as a value serialized in human-readable mode is not required to
|
||||
/// deserialize from the same data in compact mode.
|
||||
#[inline]
|
||||
fn is_human_readable(&self) -> bool { true }
|
||||
}
|
||||
|
||||
/// Returned from `Serializer::serialize_seq`.
|
||||
@@ -1727,6 +1777,13 @@ pub trait SerializeStruct {
|
||||
where
|
||||
T: Serialize;
|
||||
|
||||
/// Indicate that a struct field has been skipped.
|
||||
#[inline]
|
||||
fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
|
||||
let _ = key;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Finish serializing a struct.
|
||||
fn end(self) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
@@ -1772,6 +1829,13 @@ pub trait SerializeStructVariant {
|
||||
where
|
||||
T: Serialize;
|
||||
|
||||
/// Indicate that a struct variant field has been skipped.
|
||||
#[inline]
|
||||
fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
|
||||
let _ = key;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Finish serializing a struct variant.
|
||||
fn end(self) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "1.0.11" # remember to update html_root_url
|
||||
version = "1.0.16" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
||||
@@ -20,5 +20,5 @@ proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "0.3.8"
|
||||
serde_derive_internals = { version = "=0.15.1", default-features = false, path = "../serde_derive_internals" }
|
||||
serde_derive_internals = { version = "=0.16.0", default-features = false, path = "../serde_derive_internals" }
|
||||
syn = { version = "0.11", features = ["visit"] }
|
||||
|
||||
+20
-10
@@ -10,12 +10,12 @@ use std::collections::HashSet;
|
||||
|
||||
use syn::{self, visit};
|
||||
|
||||
use internals::ast::Container;
|
||||
use internals::ast::{Body, Container};
|
||||
use internals::attr;
|
||||
|
||||
macro_rules! path {
|
||||
($($path:tt)+) => {
|
||||
syn::parse_path(stringify!($($path)+)).unwrap()
|
||||
syn::parse_path(quote!($($path)+).as_str()).unwrap()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ pub fn with_bound<F>(
|
||||
bound: &syn::Path,
|
||||
) -> syn::Generics
|
||||
where
|
||||
F: Fn(&attr::Field) -> bool,
|
||||
F: Fn(&attr::Field, Option<&attr::Variant>) -> bool,
|
||||
{
|
||||
struct FindTyParams {
|
||||
// Set of all generic type parameters on the current struct (A, B, C in
|
||||
@@ -124,17 +124,27 @@ where
|
||||
.map(|ty_param| ty_param.ident.clone())
|
||||
.collect();
|
||||
|
||||
let relevant_tys = cont.body
|
||||
.all_fields()
|
||||
.filter(|&field| filter(&field.attrs))
|
||||
.map(|field| &field.ty);
|
||||
|
||||
let mut visitor = FindTyParams {
|
||||
all_ty_params: all_ty_params,
|
||||
relevant_ty_params: HashSet::new(),
|
||||
};
|
||||
for ty in relevant_tys {
|
||||
visit::walk_ty(&mut visitor, ty);
|
||||
match cont.body {
|
||||
Body::Enum(ref variants) => {
|
||||
for variant in variants.iter() {
|
||||
let relevant_fields = variant
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|field| filter(&field.attrs, Some(&variant.attrs)));
|
||||
for field in relevant_fields {
|
||||
visit::walk_ty(&mut visitor, field.ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
Body::Struct(_, ref fields) => {
|
||||
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
|
||||
visit::walk_ty(&mut visitor, field.ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let new_predicates = generics
|
||||
|
||||
+253
-102
@@ -26,13 +26,14 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
|
||||
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms);
|
||||
let dummy_const = Ident::new(format!("_IMPL_DESERIALIZE_FOR_{}", ident));
|
||||
let body = Stmts(deserialize_body(&cont, ¶ms));
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
||||
let vis = &input.vis;
|
||||
quote! {
|
||||
impl #de_impl_generics #ident #ty_generics #where_clause {
|
||||
#vis fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error>
|
||||
where __D: _serde::Deserializer<'de>
|
||||
where __D: _serde::Deserializer<#delife>
|
||||
{
|
||||
#body
|
||||
}
|
||||
@@ -41,9 +42,9 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
|
||||
} else {
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl #de_impl_generics _serde::Deserialize<'de> for #ident #ty_generics #where_clause {
|
||||
impl #de_impl_generics _serde::Deserialize<#delife> for #ident #ty_generics #where_clause {
|
||||
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
|
||||
where __D: _serde::Deserializer<'de>
|
||||
where __D: _serde::Deserializer<#delife>
|
||||
{
|
||||
#body
|
||||
}
|
||||
@@ -75,7 +76,7 @@ struct Parameters {
|
||||
|
||||
/// Lifetimes borrowed from the deserializer. These will become bounds on
|
||||
/// the `'de` lifetime of the deserializer.
|
||||
borrowed: BTreeSet<syn::Lifetime>,
|
||||
borrowed: BorrowedLifetimes,
|
||||
|
||||
/// At least one field has a serde(getter) attribute, implying that the
|
||||
/// remote type has a private field.
|
||||
@@ -89,8 +90,8 @@ impl Parameters {
|
||||
Some(remote) => remote.clone(),
|
||||
None => cont.ident.clone().into(),
|
||||
};
|
||||
let generics = build_generics(cont);
|
||||
let borrowed = borrowed_lifetimes(cont);
|
||||
let generics = build_generics(cont, &borrowed);
|
||||
let has_getter = cont.body.has_getter();
|
||||
|
||||
Parameters {
|
||||
@@ -107,20 +108,12 @@ impl Parameters {
|
||||
fn type_name(&self) -> &str {
|
||||
self.this.segments.last().unwrap().ident.as_ref()
|
||||
}
|
||||
|
||||
fn de_lifetime_def(&self) -> syn::LifetimeDef {
|
||||
syn::LifetimeDef {
|
||||
attrs: Vec::new(),
|
||||
lifetime: syn::Lifetime::new("'de"),
|
||||
bounds: self.borrowed.iter().cloned().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All the generics in the input, plus a bound `T: Deserialize` for each generic
|
||||
// field type that will be deserialized by us, plus a bound `T: Default` for
|
||||
// each generic field type that will be set to a default value.
|
||||
fn build_generics(cont: &Container) -> syn::Generics {
|
||||
fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generics {
|
||||
let generics = bound::without_defaults(cont.generics);
|
||||
|
||||
let generics = bound::with_where_predicates_from_fields(cont, &generics, attr::Field::de_bound);
|
||||
@@ -136,11 +129,12 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
||||
attr::Default::Path(_) => generics,
|
||||
};
|
||||
|
||||
let delife = borrowed.de_lifetime();
|
||||
let generics = bound::with_bound(
|
||||
cont,
|
||||
&generics,
|
||||
needs_deserialize_bound,
|
||||
&path!(_serde::Deserialize<'de>),
|
||||
&path!(_serde::Deserialize<#delife>),
|
||||
);
|
||||
|
||||
bound::with_bound(
|
||||
@@ -157,14 +151,44 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
||||
// deserialized by us so we do not generate a bound. Fields with a `bound`
|
||||
// attribute specify their own bound so we do not generate one. All other fields
|
||||
// may need a `T: Deserialize` bound where T is the type of the field.
|
||||
fn needs_deserialize_bound(attrs: &attr::Field) -> bool {
|
||||
!attrs.skip_deserializing() && attrs.deserialize_with().is_none() && attrs.de_bound().is_none()
|
||||
fn needs_deserialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
|
||||
!field.skip_deserializing() &&
|
||||
field.deserialize_with().is_none() &&
|
||||
field.de_bound().is_none() &&
|
||||
variant.map_or(true, |variant| variant.deserialize_with().is_none())
|
||||
}
|
||||
|
||||
// Fields with a `default` attribute (not `default=...`), and fields with a
|
||||
// `skip_deserializing` attribute that do not also have `default=...`.
|
||||
fn requires_default(attrs: &attr::Field) -> bool {
|
||||
attrs.default() == &attr::Default::Default
|
||||
fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bool {
|
||||
field.default() == &attr::Default::Default
|
||||
}
|
||||
|
||||
enum BorrowedLifetimes {
|
||||
Borrowed(BTreeSet<syn::Lifetime>),
|
||||
Static,
|
||||
}
|
||||
|
||||
impl BorrowedLifetimes {
|
||||
fn de_lifetime(&self) -> syn::Lifetime {
|
||||
match *self {
|
||||
BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new("'de"),
|
||||
BorrowedLifetimes::Static => syn::Lifetime::new("'static"),
|
||||
}
|
||||
}
|
||||
|
||||
fn de_lifetime_def(&self) -> Option<syn::LifetimeDef> {
|
||||
match *self {
|
||||
BorrowedLifetimes::Borrowed(ref bounds) => {
|
||||
Some(syn::LifetimeDef {
|
||||
attrs: Vec::new(),
|
||||
lifetime: syn::Lifetime::new("'de"),
|
||||
bounds: bounds.iter().cloned().collect(),
|
||||
})
|
||||
}
|
||||
BorrowedLifetimes::Static => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The union of lifetimes borrowed by each field of the container.
|
||||
@@ -173,12 +197,19 @@ fn requires_default(attrs: &attr::Field) -> bool {
|
||||
// lifetimes `'a` and `'b` are borrowed but `'c` is not, the impl is:
|
||||
//
|
||||
// impl<'de: 'a + 'b, 'a, 'b, 'c> Deserialize<'de> for S<'a, 'b, 'c>
|
||||
fn borrowed_lifetimes(cont: &Container) -> BTreeSet<syn::Lifetime> {
|
||||
//
|
||||
// If any borrowed lifetime is `'static`, then `'de: 'static` would be redundant
|
||||
// and we use plain `'static` instead of `'de`.
|
||||
fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes {
|
||||
let mut lifetimes = BTreeSet::new();
|
||||
for field in cont.body.all_fields() {
|
||||
lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned());
|
||||
}
|
||||
lifetimes
|
||||
if lifetimes.iter().any(|b| b.ident == "'static") {
|
||||
BorrowedLifetimes::Static
|
||||
} else {
|
||||
BorrowedLifetimes::Borrowed(lifetimes)
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
||||
@@ -191,7 +222,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
||||
if fields.iter().any(|field| field.ident.is_none()) {
|
||||
panic!("struct has unnamed fields");
|
||||
}
|
||||
deserialize_struct(None, params, fields, &cont.attrs, None)
|
||||
deserialize_struct(None, params, fields, &cont.attrs, None, Untagged::No)
|
||||
}
|
||||
Body::Struct(Style::Tuple, ref fields) |
|
||||
Body::Struct(Style::Newtype, ref fields) => {
|
||||
@@ -257,6 +288,7 @@ fn deserialize_tuple(
|
||||
) -> Fragment {
|
||||
let this = ¶ms.this;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
// If there are getters (implying private fields), construct the local type
|
||||
// and use an `Into` conversion to get the remote type. If there are no
|
||||
@@ -318,10 +350,10 @@ fn deserialize_tuple(
|
||||
quote_block! {
|
||||
struct __Visitor #de_impl_generics #where_clause {
|
||||
marker: _serde::export::PhantomData<#this #ty_generics>,
|
||||
lifetime: _serde::export::PhantomData<&'de ()>,
|
||||
lifetime: _serde::export::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
|
||||
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
|
||||
type Value = #this #ty_generics;
|
||||
|
||||
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
|
||||
@@ -332,7 +364,7 @@ fn deserialize_tuple(
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::SeqAccess<'de>
|
||||
where __A: _serde::de::SeqAccess<#delife>
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
@@ -372,7 +404,7 @@ fn deserialize_seq(
|
||||
quote!(try!(_serde::de::SeqAccess::next_element::<#field_ty>(&mut __seq)))
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(
|
||||
params, field.ty, path);
|
||||
quote!({
|
||||
#wrapper
|
||||
@@ -420,6 +452,8 @@ fn deserialize_seq(
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &Field) -> Tokens {
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let value = match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
let field_ty = &field.ty;
|
||||
@@ -428,7 +462,7 @@ fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &F
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||
quote!({
|
||||
#wrapper
|
||||
try!(<#wrapper_ty as _serde::Deserialize>::deserialize(__e)).value
|
||||
@@ -447,25 +481,31 @@ fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &F
|
||||
quote! {
|
||||
#[inline]
|
||||
fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result<Self::Value, __E::Error>
|
||||
where __E: _serde::Deserializer<'de>
|
||||
where __E: _serde::Deserializer<#delife>
|
||||
{
|
||||
_serde::export::Ok(#result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Untagged {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
fn deserialize_struct(
|
||||
variant_ident: Option<&syn::Ident>,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Option<Tokens>,
|
||||
untagged: Untagged,
|
||||
) -> Fragment {
|
||||
let is_enum = variant_ident.is_some();
|
||||
let is_untagged = deserializer.is_some();
|
||||
|
||||
let this = ¶ms.this;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
// If there are getters (implying private fields), construct the local type
|
||||
// and use an `Into` conversion to get the remote type. If there are no
|
||||
@@ -524,18 +564,19 @@ fn deserialize_struct(
|
||||
quote!(mut __seq)
|
||||
};
|
||||
|
||||
let visit_seq = if is_untagged {
|
||||
// untagged struct variants do not get a visit_seq method
|
||||
None
|
||||
} else {
|
||||
Some(quote! {
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::SeqAccess<'de>
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
})
|
||||
// untagged struct variants do not get a visit_seq method
|
||||
let visit_seq = match untagged {
|
||||
Untagged::Yes => None,
|
||||
Untagged::No => {
|
||||
Some(quote! {
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::SeqAccess<#delife>
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
@@ -543,10 +584,10 @@ fn deserialize_struct(
|
||||
|
||||
struct __Visitor #de_impl_generics #where_clause {
|
||||
marker: _serde::export::PhantomData<#this #ty_generics>,
|
||||
lifetime: _serde::export::PhantomData<&'de ()>,
|
||||
lifetime: _serde::export::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
|
||||
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
|
||||
type Value = #this #ty_generics;
|
||||
|
||||
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
|
||||
@@ -557,7 +598,7 @@ fn deserialize_struct(
|
||||
|
||||
#[inline]
|
||||
fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::MapAccess<'de>
|
||||
where __A: _serde::de::MapAccess<#delife>
|
||||
{
|
||||
#visit_map
|
||||
}
|
||||
@@ -594,6 +635,7 @@ fn deserialize_externally_tagged_enum(
|
||||
) -> Fragment {
|
||||
let this = ¶ms.this;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
|
||||
@@ -659,10 +701,10 @@ fn deserialize_externally_tagged_enum(
|
||||
|
||||
struct __Visitor #de_impl_generics #where_clause {
|
||||
marker: _serde::export::PhantomData<#this #ty_generics>,
|
||||
lifetime: _serde::export::PhantomData<&'de ()>,
|
||||
lifetime: _serde::export::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
|
||||
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
|
||||
type Value = #this #ty_generics;
|
||||
|
||||
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
|
||||
@@ -670,7 +712,7 @@ fn deserialize_externally_tagged_enum(
|
||||
}
|
||||
|
||||
fn visit_enum<__A>(self, __data: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::EnumAccess<'de>
|
||||
where __A: _serde::de::EnumAccess<#delife>
|
||||
{
|
||||
#match_variant
|
||||
}
|
||||
@@ -751,6 +793,7 @@ fn deserialize_adjacently_tagged_enum(
|
||||
) -> Fragment {
|
||||
let this = ¶ms.this;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let variant_names_idents: Vec<_> = variants
|
||||
.iter()
|
||||
@@ -796,9 +839,8 @@ fn deserialize_adjacently_tagged_enum(
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
let deny_unknown_fields = cattrs.deny_unknown_fields();
|
||||
|
||||
/// If unknown fields are allowed, we pick the visitor that can
|
||||
/// step over those. Otherwise we pick the visitor that fails on
|
||||
/// unknown keys.
|
||||
// If unknown fields are allowed, we pick the visitor that can step over
|
||||
// those. Otherwise we pick the visitor that fails on unknown keys.
|
||||
let field_visitor_ty = if deny_unknown_fields {
|
||||
quote! { _serde::private::de::TagOrContentFieldVisitor }
|
||||
} else {
|
||||
@@ -853,13 +895,13 @@ fn deserialize_adjacently_tagged_enum(
|
||||
};
|
||||
}
|
||||
|
||||
/// Advance the map by one key, returning early in case of error.
|
||||
// Advance the map by one key, returning early in case of error.
|
||||
let next_key = quote! {
|
||||
try!(_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content))
|
||||
};
|
||||
|
||||
/// When allowing unknown fields, we want to transparently step through keys we don't care
|
||||
/// about until we find `tag`, `content`, or run out of keys.
|
||||
// When allowing unknown fields, we want to transparently step through keys
|
||||
// we don't care about until we find `tag`, `content`, or run out of keys.
|
||||
let next_relevant_key = if deny_unknown_fields {
|
||||
next_key
|
||||
} else {
|
||||
@@ -888,9 +930,9 @@ fn deserialize_adjacently_tagged_enum(
|
||||
}
|
||||
};
|
||||
|
||||
/// Step through remaining keys, looking for duplicates of previously-seen keys.
|
||||
/// When unknown fields are denied, any key that isn't a duplicate will at this
|
||||
/// point immediately produce an error.
|
||||
// Step through remaining keys, looking for duplicates of previously-seen
|
||||
// keys. When unknown fields are denied, any key that isn't a duplicate will
|
||||
// at this point immediately produce an error.
|
||||
let visit_remaining_keys = quote! {
|
||||
match #next_relevant_key {
|
||||
_serde::export::Some(_serde::private::de::TagOrContentField::Tag) => {
|
||||
@@ -911,14 +953,14 @@ fn deserialize_adjacently_tagged_enum(
|
||||
struct __Seed #de_impl_generics #where_clause {
|
||||
field: __Field,
|
||||
marker: _serde::export::PhantomData<#this #ty_generics>,
|
||||
lifetime: _serde::export::PhantomData<&'de ()>,
|
||||
lifetime: _serde::export::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
impl #de_impl_generics _serde::de::DeserializeSeed<'de> for __Seed #de_ty_generics #where_clause {
|
||||
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Seed #de_ty_generics #where_clause {
|
||||
type Value = #this #ty_generics;
|
||||
|
||||
fn deserialize<__D>(self, __deserializer: __D) -> _serde::export::Result<Self::Value, __D::Error>
|
||||
where __D: _serde::Deserializer<'de>
|
||||
where __D: _serde::Deserializer<#delife>
|
||||
{
|
||||
match self.field {
|
||||
#(#variant_arms)*
|
||||
@@ -928,10 +970,10 @@ fn deserialize_adjacently_tagged_enum(
|
||||
|
||||
struct __Visitor #de_impl_generics #where_clause {
|
||||
marker: _serde::export::PhantomData<#this #ty_generics>,
|
||||
lifetime: _serde::export::PhantomData<&'de ()>,
|
||||
lifetime: _serde::export::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
|
||||
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
|
||||
type Value = #this #ty_generics;
|
||||
|
||||
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
|
||||
@@ -939,7 +981,7 @@ fn deserialize_adjacently_tagged_enum(
|
||||
}
|
||||
|
||||
fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::MapAccess<'de>
|
||||
where __A: _serde::de::MapAccess<#delife>
|
||||
{
|
||||
// Visit the first relevant key.
|
||||
match #next_relevant_key {
|
||||
@@ -1003,7 +1045,7 @@ fn deserialize_adjacently_tagged_enum(
|
||||
}
|
||||
|
||||
fn visit_seq<__A>(self, mut __seq: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::SeqAccess<'de>
|
||||
where __A: _serde::de::SeqAccess<#delife>
|
||||
{
|
||||
// Visit the first element - the tag.
|
||||
match try!(_serde::de::SeqAccess::next_element(&mut __seq)) {
|
||||
@@ -1085,6 +1127,16 @@ fn deserialize_externally_tagged_variant(
|
||||
variant: &Variant,
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.deserialize_with() {
|
||||
let (wrapper, wrapper_ty, unwrap_fn) =
|
||||
wrap_deserialize_variant_with(params, &variant, path);
|
||||
return quote_block! {
|
||||
#wrapper
|
||||
_serde::export::Result::map(
|
||||
_serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn)
|
||||
};
|
||||
}
|
||||
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
match variant.style {
|
||||
@@ -1102,7 +1154,7 @@ fn deserialize_externally_tagged_variant(
|
||||
deserialize_tuple(Some(variant_ident), params, &variant.fields, cattrs, None)
|
||||
}
|
||||
Style::Struct => {
|
||||
deserialize_struct(Some(variant_ident), params, &variant.fields, cattrs, None)
|
||||
deserialize_struct(Some(variant_ident), params, &variant.fields, cattrs, None, Untagged::No)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1113,6 +1165,10 @@ fn deserialize_internally_tagged_variant(
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Tokens,
|
||||
) -> Fragment {
|
||||
if variant.attrs.deserialize_with().is_some() {
|
||||
return deserialize_untagged_variant(params, variant, cattrs, deserializer);
|
||||
}
|
||||
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
match variant.style {
|
||||
@@ -1125,8 +1181,23 @@ fn deserialize_internally_tagged_variant(
|
||||
_serde::export::Ok(#this::#variant_ident)
|
||||
}
|
||||
}
|
||||
Style::Newtype | Style::Struct => {
|
||||
deserialize_untagged_variant(params, variant, cattrs, deserializer)
|
||||
Style::Newtype => {
|
||||
deserialize_untagged_newtype_variant(
|
||||
variant_ident,
|
||||
params,
|
||||
&variant.fields[0],
|
||||
deserializer,
|
||||
)
|
||||
}
|
||||
Style::Struct => {
|
||||
deserialize_struct(
|
||||
Some(variant_ident),
|
||||
params,
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
Some(deserializer),
|
||||
Untagged::No,
|
||||
)
|
||||
}
|
||||
Style::Tuple => unreachable!("checked in serde_derive_internals"),
|
||||
}
|
||||
@@ -1138,6 +1209,16 @@ fn deserialize_untagged_variant(
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Tokens,
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.deserialize_with() {
|
||||
let (wrapper, wrapper_ty, unwrap_fn) =
|
||||
wrap_deserialize_variant_with(params, &variant, path);
|
||||
return quote_block! {
|
||||
#wrapper
|
||||
_serde::export::Result::map(
|
||||
<#wrapper_ty as _serde::Deserialize>::deserialize(#deserializer), #unwrap_fn)
|
||||
};
|
||||
}
|
||||
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
match variant.style {
|
||||
@@ -1178,6 +1259,7 @@ fn deserialize_untagged_variant(
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
Some(deserializer),
|
||||
Untagged::Yes,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1199,7 +1281,7 @@ fn deserialize_externally_tagged_newtype_variant(
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||
quote_block! {
|
||||
#wrapper
|
||||
_serde::export::Result::map(
|
||||
@@ -1227,7 +1309,7 @@ fn deserialize_untagged_newtype_variant(
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||
quote_block! {
|
||||
#wrapper
|
||||
_serde::export::Result::map(
|
||||
@@ -1340,6 +1422,7 @@ fn deserialize_custom_identifier(
|
||||
};
|
||||
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
let visitor_impl =
|
||||
Stmts(deserialize_identifier(this.clone(), &names_idents, is_variant, fallthrough),);
|
||||
|
||||
@@ -1348,10 +1431,10 @@ fn deserialize_custom_identifier(
|
||||
|
||||
struct __FieldVisitor #de_impl_generics #where_clause {
|
||||
marker: _serde::export::PhantomData<#this #ty_generics>,
|
||||
lifetime: _serde::export::PhantomData<&'de ()>,
|
||||
lifetime: _serde::export::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
impl #de_impl_generics _serde::de::Visitor<'de> for __FieldVisitor #de_ty_generics #where_clause {
|
||||
impl #de_impl_generics _serde::de::Visitor<#delife> for __FieldVisitor #de_ty_generics #where_clause {
|
||||
type Value = #this #ty_generics;
|
||||
|
||||
#visitor_impl
|
||||
@@ -1385,26 +1468,27 @@ fn deserialize_identifier(
|
||||
"field identifier"
|
||||
};
|
||||
|
||||
let visit_index = if is_variant {
|
||||
let variant_indices = 0u32..;
|
||||
let fallthrough_msg = format!("variant index 0 <= i < {}", fields.len());
|
||||
let visit_index = quote! {
|
||||
fn visit_u32<__E>(self, __value: u32) -> _serde::export::Result<Self::Value, __E>
|
||||
where __E: _serde::de::Error
|
||||
{
|
||||
match __value {
|
||||
#(
|
||||
#variant_indices => _serde::export::Ok(#constructors),
|
||||
)*
|
||||
_ => _serde::export::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value as u64),
|
||||
&#fallthrough_msg))
|
||||
}
|
||||
}
|
||||
};
|
||||
Some(visit_index)
|
||||
let index_expecting = if is_variant {
|
||||
"variant"
|
||||
} else {
|
||||
None
|
||||
"field"
|
||||
};
|
||||
|
||||
let variant_indices = 0u64..;
|
||||
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
|
||||
let visit_index = quote! {
|
||||
fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
|
||||
where __E: _serde::de::Error
|
||||
{
|
||||
match __value {
|
||||
#(
|
||||
#variant_indices => _serde::export::Ok(#constructors),
|
||||
)*
|
||||
_ => _serde::export::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&#fallthrough_msg))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let bytes_to_str = if fallthrough.is_some() {
|
||||
@@ -1529,7 +1613,7 @@ fn deserialize_map(
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(
|
||||
params, field.ty, path);
|
||||
quote!({
|
||||
#wrapper
|
||||
@@ -1662,22 +1746,23 @@ fn field_i(i: usize) -> Ident {
|
||||
/// in a trait to prevent it from accessing the internal `Deserialize` state.
|
||||
fn wrap_deserialize_with(
|
||||
params: &Parameters,
|
||||
field_ty: &syn::Ty,
|
||||
value_ty: Tokens,
|
||||
deserialize_with: &syn::Path,
|
||||
) -> (Tokens, Tokens) {
|
||||
let this = ¶ms.this;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let wrapper = quote! {
|
||||
struct __DeserializeWith #de_impl_generics #where_clause {
|
||||
value: #field_ty,
|
||||
value: #value_ty,
|
||||
phantom: _serde::export::PhantomData<#this #ty_generics>,
|
||||
lifetime: _serde::export::PhantomData<&'de ()>,
|
||||
lifetime: _serde::export::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
impl #de_impl_generics _serde::Deserialize<'de> for __DeserializeWith #de_ty_generics #where_clause {
|
||||
impl #de_impl_generics _serde::Deserialize<#delife> for __DeserializeWith #de_ty_generics #where_clause {
|
||||
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
|
||||
where __D: _serde::Deserializer<'de>
|
||||
where __D: _serde::Deserializer<#delife>
|
||||
{
|
||||
_serde::export::Ok(__DeserializeWith {
|
||||
value: try!(#deserialize_with(__deserializer)),
|
||||
@@ -1693,6 +1778,68 @@ fn wrap_deserialize_with(
|
||||
(wrapper, wrapper_ty)
|
||||
}
|
||||
|
||||
fn wrap_deserialize_field_with(
|
||||
params: &Parameters,
|
||||
field_ty: &syn::Ty,
|
||||
deserialize_with: &syn::Path,
|
||||
) -> (Tokens, Tokens) {
|
||||
wrap_deserialize_with(params, quote!(#field_ty), deserialize_with)
|
||||
}
|
||||
|
||||
fn wrap_deserialize_variant_with(
|
||||
params: &Parameters,
|
||||
variant: &Variant,
|
||||
deserialize_with: &syn::Path,
|
||||
) -> (Tokens, Tokens, Tokens) {
|
||||
let this = ¶ms.this;
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
let field_tys = variant.fields.iter().map(|field| field.ty);
|
||||
let (wrapper, wrapper_ty) =
|
||||
wrap_deserialize_with(params, quote!((#(#field_tys),*)), deserialize_with);
|
||||
|
||||
let field_access = (0..variant.fields.len()).map(|n| Ident::new(format!("{}", n)));
|
||||
let unwrap_fn = match variant.style {
|
||||
Style::Struct => {
|
||||
let field_idents = variant.fields.iter().map(|field| field.ident.as_ref().unwrap());
|
||||
quote! {
|
||||
{
|
||||
|__wrap| {
|
||||
#this::#variant_ident { #(#field_idents: __wrap.value.#field_access),* }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Style::Tuple => {
|
||||
quote! {
|
||||
{
|
||||
|__wrap| {
|
||||
#this::#variant_ident(#(__wrap.value.#field_access),*)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Style::Newtype => {
|
||||
quote! {
|
||||
{
|
||||
|__wrap| {
|
||||
#this::#variant_ident(__wrap.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Style::Unit => {
|
||||
quote! {
|
||||
{
|
||||
|__wrap| { #this::#variant_ident }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(wrapper, wrapper_ty, unwrap_fn)
|
||||
}
|
||||
|
||||
fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
|
||||
match *field.attrs.default() {
|
||||
attr::Default::Default => {
|
||||
@@ -1733,20 +1880,24 @@ struct DeImplGenerics<'a>(&'a Parameters);
|
||||
impl<'a> ToTokens for DeImplGenerics<'a> {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
let mut generics = self.0.generics.clone();
|
||||
generics.lifetimes.insert(0, self.0.de_lifetime_def());
|
||||
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
|
||||
generics.lifetimes.insert(0, de_lifetime);
|
||||
}
|
||||
let (impl_generics, _, _) = generics.split_for_impl();
|
||||
impl_generics.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
struct DeTyGenerics<'a>(&'a syn::Generics);
|
||||
struct DeTyGenerics<'a>(&'a Parameters);
|
||||
|
||||
impl<'a> ToTokens for DeTyGenerics<'a> {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
let mut generics = self.0.clone();
|
||||
generics
|
||||
.lifetimes
|
||||
.insert(0, syn::LifetimeDef::new("'de"));
|
||||
let mut generics = self.0.generics.clone();
|
||||
if self.0.borrowed.de_lifetime_def().is_some() {
|
||||
generics
|
||||
.lifetimes
|
||||
.insert(0, syn::LifetimeDef::new("'de"));
|
||||
}
|
||||
let (_, ty_generics, _) = generics.split_for_impl();
|
||||
ty_generics.to_tokens(tokens);
|
||||
}
|
||||
@@ -1755,7 +1906,7 @@ impl<'a> ToTokens for DeTyGenerics<'a> {
|
||||
fn split_with_de_lifetime(params: &Parameters,)
|
||||
-> (DeImplGenerics, DeTyGenerics, syn::TyGenerics, &syn::WhereClause) {
|
||||
let de_impl_generics = DeImplGenerics(¶ms);
|
||||
let de_ty_generics = DeTyGenerics(¶ms.generics);
|
||||
let de_ty_generics = DeTyGenerics(¶ms);
|
||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
(de_impl_generics, de_ty_generics, ty_generics, where_clause)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
//!
|
||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.11")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.16")]
|
||||
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
|
||||
|
||||
+160
-52
@@ -143,12 +143,16 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
||||
}
|
||||
}
|
||||
|
||||
// Fields with a `skip_serializing` or `serialize_with` attribute are not
|
||||
// serialized by us so we do not generate a bound. Fields with a `bound`
|
||||
// attribute specify their own bound so we do not generate one. All other fields
|
||||
// may need a `T: Serialize` bound where T is the type of the field.
|
||||
fn needs_serialize_bound(attrs: &attr::Field) -> bool {
|
||||
!attrs.skip_serializing() && attrs.serialize_with().is_none() && attrs.ser_bound().is_none()
|
||||
// Fields with a `skip_serializing` or `serialize_with` attribute, or which
|
||||
// belong to a variant with a `serialize_with` attribute, are not serialized by
|
||||
// us so we do not generate a bound. Fields with a `bound` attribute specify
|
||||
// their own bound so we do not generate one. All other fields may need a `T:
|
||||
// Serialize` bound where T is the type of the field.
|
||||
fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
|
||||
!field.skip_serializing() &&
|
||||
field.serialize_with().is_none() &&
|
||||
field.ser_bound().is_none() &&
|
||||
variant.map_or(true, |variant| variant.serialize_with().is_none())
|
||||
}
|
||||
|
||||
fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
||||
@@ -203,7 +207,7 @@ fn serialize_newtype_struct(
|
||||
|
||||
let mut field_expr = get_field(params, field, 0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -242,6 +246,7 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
|
||||
params,
|
||||
false,
|
||||
quote!(_serde::ser::SerializeStruct::serialize_field),
|
||||
quote!(_serde::ser::SerializeStruct::skip_field),
|
||||
);
|
||||
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
@@ -395,6 +400,19 @@ fn serialize_externally_tagged_variant(
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
let variant_name = variant.attrs.name().serialize_name();
|
||||
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
return quote_expr! {
|
||||
_serde::Serializer::serialize_newtype_variant(
|
||||
__serializer,
|
||||
#type_name,
|
||||
#variant_index,
|
||||
#variant_name,
|
||||
#ser,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
match variant.style {
|
||||
Style::Unit => {
|
||||
quote_expr! {
|
||||
@@ -410,7 +428,7 @@ fn serialize_externally_tagged_variant(
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -460,6 +478,20 @@ fn serialize_internally_tagged_variant(
|
||||
let enum_ident_str = params.type_name();
|
||||
let variant_ident_str = variant.ident.as_ref();
|
||||
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
return quote_expr! {
|
||||
_serde::private::ser::serialize_tagged_newtype(
|
||||
__serializer,
|
||||
#enum_ident_str,
|
||||
#variant_ident_str,
|
||||
#tag,
|
||||
#variant_name,
|
||||
#ser,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
match variant.style {
|
||||
Style::Unit => {
|
||||
quote_block! {
|
||||
@@ -474,7 +506,7 @@ fn serialize_internally_tagged_variant(
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -515,44 +547,57 @@ fn serialize_adjacently_tagged_variant(
|
||||
let variant_name = variant.attrs.name().serialize_name();
|
||||
|
||||
let inner = Stmts(
|
||||
match variant.style {
|
||||
Style::Unit => {
|
||||
return quote_block! {
|
||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
||||
__serializer, #type_name, 1));
|
||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
||||
&mut __struct, #tag, #variant_name));
|
||||
_serde::ser::SerializeStruct::end(__struct)
|
||||
};
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
quote_expr! {
|
||||
_serde::Serialize::serialize(#ser, __serializer)
|
||||
}
|
||||
Style::Newtype => {
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
} else {
|
||||
match variant.style {
|
||||
Style::Unit => {
|
||||
return quote_block! {
|
||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
||||
__serializer, #type_name, 1));
|
||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
||||
&mut __struct, #tag, #variant_name));
|
||||
_serde::ser::SerializeStruct::end(__struct)
|
||||
};
|
||||
}
|
||||
Style::Newtype => {
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
_serde::Serialize::serialize(#field_expr, __serializer)
|
||||
quote_expr! {
|
||||
_serde::Serialize::serialize(#field_expr, __serializer)
|
||||
}
|
||||
}
|
||||
Style::Tuple => {
|
||||
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
|
||||
}
|
||||
Style::Struct => {
|
||||
serialize_struct_variant(
|
||||
StructVariant::Untagged,
|
||||
params,
|
||||
&variant.fields,
|
||||
&variant_name,
|
||||
)
|
||||
}
|
||||
}
|
||||
Style::Tuple => {
|
||||
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
|
||||
}
|
||||
Style::Struct => {
|
||||
serialize_struct_variant(
|
||||
StructVariant::Untagged,
|
||||
params,
|
||||
&variant.fields,
|
||||
&variant_name,
|
||||
)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let fields_ty = variant.fields.iter().map(|f| &f.ty);
|
||||
let ref fields_ident: Vec<_> = match variant.style {
|
||||
Style::Unit => unreachable!(),
|
||||
Style::Unit => {
|
||||
if variant.attrs.serialize_with().is_some() {
|
||||
vec![]
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
Style::Newtype => vec![Ident::new("__field0")],
|
||||
Style::Tuple => {
|
||||
(0..variant.fields.len())
|
||||
@@ -576,7 +621,11 @@ fn serialize_adjacently_tagged_variant(
|
||||
|
||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
|
||||
let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a");
|
||||
let wrapper_generics = if let Style::Unit = variant.style {
|
||||
params.generics.clone()
|
||||
} else {
|
||||
bound::with_lifetime_bound(¶ms.generics, "'__a")
|
||||
};
|
||||
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
||||
|
||||
quote_block! {
|
||||
@@ -612,6 +661,13 @@ fn serialize_untagged_variant(
|
||||
variant: &Variant,
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
return quote_expr! {
|
||||
_serde::Serialize::serialize(#ser, __serializer)
|
||||
};
|
||||
}
|
||||
|
||||
match variant.style {
|
||||
Style::Unit => {
|
||||
quote_expr! {
|
||||
@@ -622,7 +678,7 @@ fn serialize_untagged_variant(
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -707,15 +763,23 @@ fn serialize_struct_variant<'a>(
|
||||
fields: &[Field],
|
||||
name: &str,
|
||||
) -> Fragment {
|
||||
let method = match context {
|
||||
let (method, skip_method) = match context {
|
||||
StructVariant::ExternallyTagged { .. } => {
|
||||
quote!(_serde::ser::SerializeStructVariant::serialize_field)
|
||||
(
|
||||
quote!(_serde::ser::SerializeStructVariant::serialize_field),
|
||||
quote!(_serde::ser::SerializeStructVariant::skip_field),
|
||||
)
|
||||
}
|
||||
StructVariant::InternallyTagged { .. } |
|
||||
StructVariant::Untagged => quote!(_serde::ser::SerializeStruct::serialize_field),
|
||||
StructVariant::Untagged => {
|
||||
(
|
||||
quote!(_serde::ser::SerializeStruct::serialize_field),
|
||||
quote!(_serde::ser::SerializeStruct::skip_field),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let serialize_fields = serialize_struct_visitor(fields, params, true, method);
|
||||
let serialize_fields = serialize_struct_visitor(fields, params, true, method, skip_method);
|
||||
|
||||
let mut serialized_fields = fields
|
||||
.iter()
|
||||
@@ -808,7 +872,7 @@ fn serialize_tuple_struct_visitor(
|
||||
.map(|path| quote!(#path(#field_expr)));
|
||||
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
let ser = quote! {
|
||||
@@ -829,6 +893,7 @@ fn serialize_struct_visitor(
|
||||
params: &Parameters,
|
||||
is_enum: bool,
|
||||
func: Tokens,
|
||||
skip_func: Tokens,
|
||||
) -> Vec<Tokens> {
|
||||
fields
|
||||
.iter()
|
||||
@@ -850,7 +915,7 @@ fn serialize_struct_visitor(
|
||||
.map(|path| quote!(#path(#field_expr)));
|
||||
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr)
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
let ser = quote! {
|
||||
@@ -859,28 +924,71 @@ fn serialize_struct_visitor(
|
||||
|
||||
match skip {
|
||||
None => ser,
|
||||
Some(skip) => quote!(if !#skip { #ser }),
|
||||
Some(skip) => {
|
||||
quote! {
|
||||
if !#skip {
|
||||
#ser
|
||||
} else {
|
||||
try!(#skip_func(&mut __serde_state, #key_expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn wrap_serialize_with(
|
||||
fn wrap_serialize_field_with(
|
||||
params: &Parameters,
|
||||
field_ty: &syn::Ty,
|
||||
serialize_with: &syn::Path,
|
||||
value: Tokens,
|
||||
field_expr: Tokens,
|
||||
) -> Tokens {
|
||||
wrap_serialize_with(params,
|
||||
serialize_with,
|
||||
&[field_ty],
|
||||
&[quote!(#field_expr)])
|
||||
}
|
||||
|
||||
fn wrap_serialize_variant_with(
|
||||
params: &Parameters,
|
||||
serialize_with: &syn::Path,
|
||||
variant: &Variant,
|
||||
) -> Tokens {
|
||||
let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect();
|
||||
let field_exprs: Vec<_> = variant.fields.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| {
|
||||
let id = field.ident.as_ref().map_or_else(|| Ident::new(format!("__field{}", i)),
|
||||
|id| id.clone());
|
||||
quote!(#id)
|
||||
})
|
||||
.collect();
|
||||
wrap_serialize_with(params, serialize_with, field_tys.as_slice(), field_exprs.as_slice())
|
||||
}
|
||||
|
||||
fn wrap_serialize_with(
|
||||
params: &Parameters,
|
||||
serialize_with: &syn::Path,
|
||||
field_tys: &[&syn::Ty],
|
||||
field_exprs: &[Tokens],
|
||||
) -> Tokens {
|
||||
let this = ¶ms.this;
|
||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
|
||||
let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a");
|
||||
let wrapper_generics = if field_exprs.len() == 0 {
|
||||
params.generics.clone()
|
||||
} else {
|
||||
bound::with_lifetime_bound(¶ms.generics, "'__a")
|
||||
};
|
||||
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
||||
|
||||
let field_access = (0..field_exprs.len()).map(|n| Ident::new(format!("{}", n)));
|
||||
|
||||
quote!({
|
||||
struct __SerializeWith #wrapper_impl_generics #where_clause {
|
||||
value: &'__a #field_ty,
|
||||
values: (#(&'__a #field_tys, )*),
|
||||
phantom: _serde::export::PhantomData<#this #ty_generics>,
|
||||
}
|
||||
|
||||
@@ -888,12 +996,12 @@ fn wrap_serialize_with(
|
||||
fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||
where __S: _serde::Serializer
|
||||
{
|
||||
#serialize_with(self.value, __s)
|
||||
#serialize_with(#(self.values.#field_access, )* __s)
|
||||
}
|
||||
}
|
||||
|
||||
&__SerializeWith {
|
||||
value: #value,
|
||||
values: (#(#field_exprs, )*),
|
||||
phantom: _serde::export::PhantomData::<#this #ty_generics>,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.15.1" # remember to update html_root_url
|
||||
version = "0.16.0" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "AST representation used by Serde derive macros. Unstable."
|
||||
|
||||
@@ -510,6 +510,8 @@ pub struct Variant {
|
||||
skip_deserializing: bool,
|
||||
skip_serializing: bool,
|
||||
other: bool,
|
||||
serialize_with: Option<syn::Path>,
|
||||
deserialize_with: Option<syn::Path>,
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
@@ -520,6 +522,8 @@ impl Variant {
|
||||
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
||||
let mut rename_all = Attr::none(cx, "rename_all");
|
||||
let mut other = BoolAttr::none(cx, "other");
|
||||
let mut serialize_with = Attr::none(cx, "serialize_with");
|
||||
let mut deserialize_with = Attr::none(cx, "deserialize_with");
|
||||
|
||||
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
for meta_item in meta_items {
|
||||
@@ -569,6 +573,32 @@ impl Variant {
|
||||
other.set_true();
|
||||
}
|
||||
|
||||
// Parse `#[serde(with = "...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
let mut ser_path = path.clone();
|
||||
ser_path.segments.push("serialize".into());
|
||||
serialize_with.set(ser_path);
|
||||
let mut de_path = path;
|
||||
de_path.segments.push("deserialize".into());
|
||||
deserialize_with.set(de_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(serialize_with = "...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
serialize_with.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(deserialize_with = "...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
deserialize_with.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem(ref meta_item) => {
|
||||
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
|
||||
}
|
||||
@@ -595,6 +625,8 @@ impl Variant {
|
||||
skip_deserializing: skip_deserializing.get(),
|
||||
skip_serializing: skip_serializing.get(),
|
||||
other: other.get(),
|
||||
serialize_with: serialize_with.get(),
|
||||
deserialize_with: deserialize_with.get(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,6 +658,14 @@ impl Variant {
|
||||
pub fn other(&self) -> bool {
|
||||
self.other
|
||||
}
|
||||
|
||||
pub fn serialize_with(&self) -> Option<&syn::Path> {
|
||||
self.serialize_with.as_ref()
|
||||
}
|
||||
|
||||
pub fn deserialize_with(&self) -> Option<&syn::Path> {
|
||||
self.deserialize_with.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents field attribute information
|
||||
|
||||
@@ -27,6 +27,8 @@ pub enum RenameRule {
|
||||
ScreamingSnakeCase,
|
||||
/// Rename direct children to "kebab-case" style.
|
||||
KebabCase,
|
||||
/// Rename direct children to "SCREAMING-KEBAB-CASE" style.
|
||||
ScreamingKebabCase
|
||||
}
|
||||
|
||||
impl RenameRule {
|
||||
@@ -47,6 +49,7 @@ impl RenameRule {
|
||||
}
|
||||
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
|
||||
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
|
||||
ScreamingKebabCase => ScreamingSnakeCase.apply_to_variant(variant).replace('_', "-")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +77,7 @@ impl RenameRule {
|
||||
}
|
||||
ScreamingSnakeCase => field.to_ascii_uppercase(),
|
||||
KebabCase => field.replace('_', "-"),
|
||||
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,6 +93,7 @@ impl FromStr for RenameRule {
|
||||
"snake_case" => Ok(SnakeCase),
|
||||
"SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
|
||||
"kebab-case" => Ok(KebabCase),
|
||||
"SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
@@ -96,12 +101,12 @@ impl FromStr for RenameRule {
|
||||
|
||||
#[test]
|
||||
fn rename_variants() {
|
||||
for &(original, lower, camel, snake, screaming, kebab) in
|
||||
for &(original, lower, camel, snake, screaming, kebab, screaming_kebab) in
|
||||
&[
|
||||
("Outcome", "outcome", "outcome", "outcome", "OUTCOME", "outcome"),
|
||||
("VeryTasty", "verytasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty"),
|
||||
("A", "a", "a", "a", "A", "a"),
|
||||
("Z42", "z42", "z42", "z42", "Z42", "z42"),
|
||||
("Outcome", "outcome", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"),
|
||||
("VeryTasty", "verytasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"),
|
||||
("A", "a", "a", "a", "A", "a", "A"),
|
||||
("Z42", "z42", "z42", "z42", "Z42", "z42", "Z42"),
|
||||
] {
|
||||
assert_eq!(None.apply_to_variant(original), original);
|
||||
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
||||
@@ -110,17 +115,18 @@ fn rename_variants() {
|
||||
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
||||
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
|
||||
assert_eq!(KebabCase.apply_to_variant(original), kebab);
|
||||
assert_eq!(ScreamingKebabCase.apply_to_variant(original), screaming_kebab);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_fields() {
|
||||
for &(original, pascal, camel, screaming, kebab) in
|
||||
for &(original, pascal, camel, screaming, kebab, screaming_kebab) in
|
||||
&[
|
||||
("outcome", "Outcome", "outcome", "OUTCOME", "outcome"),
|
||||
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty"),
|
||||
("a", "A", "a", "A", "a"),
|
||||
("z42", "Z42", "z42", "Z42", "z42"),
|
||||
("outcome", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"),
|
||||
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"),
|
||||
("a", "A", "a", "A", "a", "A"),
|
||||
("z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
||||
] {
|
||||
assert_eq!(None.apply_to_field(original), original);
|
||||
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
||||
@@ -128,5 +134,6 @@ fn rename_fields() {
|
||||
assert_eq!(SnakeCase.apply_to_field(original), original);
|
||||
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
|
||||
assert_eq!(KebabCase.apply_to_field(original), kebab);
|
||||
assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ use Ctxt;
|
||||
pub fn check(cx: &Ctxt, cont: &Container) {
|
||||
check_getter(cx, cont);
|
||||
check_identifier(cx, cont);
|
||||
check_variant_skip_attrs(cx, cont);
|
||||
}
|
||||
|
||||
/// Getters are only allowed inside structs (not enums) with the `remote`
|
||||
@@ -94,3 +95,58 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Skip-(de)serializing attributes are not allowed on variants marked
|
||||
/// (de)serialize_with.
|
||||
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
||||
let variants = match cont.body {
|
||||
Body::Enum(ref variants) => variants,
|
||||
Body::Struct(_, _) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
for variant in variants.iter() {
|
||||
if variant.attrs.serialize_with().is_some() {
|
||||
if variant.attrs.skip_serializing() {
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||
#[serde(skip_serializing)]", variant.ident));
|
||||
}
|
||||
|
||||
for (i, field) in variant.fields.iter().enumerate() {
|
||||
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i),
|
||||
|ident| format!("`{}`", ident));
|
||||
|
||||
if field.attrs.skip_serializing() {
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||
a field {} marked with #[serde(skip_serializing)]",
|
||||
variant.ident, ident));
|
||||
}
|
||||
|
||||
if field.attrs.skip_serializing_if().is_some() {
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||
a field {} marked with #[serde(skip_serializing_if)]",
|
||||
variant.ident, ident));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if variant.attrs.deserialize_with().is_some() {
|
||||
if variant.attrs.skip_deserializing() {
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] and \
|
||||
#[serde(skip_deserializing)]", variant.ident));
|
||||
}
|
||||
|
||||
for (i, field) in variant.fields.iter().enumerate() {
|
||||
if field.attrs.skip_deserializing() {
|
||||
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i),
|
||||
|ident| format!("`{}`", ident));
|
||||
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] \
|
||||
and a field {} marked with #[serde(skip_deserializing)]",
|
||||
variant.ident, ident));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.15.1")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.16.0")]
|
||||
|
||||
extern crate syn;
|
||||
#[macro_use]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_test"
|
||||
version = "1.0.11" # remember to update html_root_url
|
||||
version = "1.0.16" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Token De/Serializer for testing De/Serialize implementations"
|
||||
|
||||
@@ -47,8 +47,20 @@ pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
||||
where
|
||||
T: Serialize + Deserialize<'de> + PartialEq + Debug,
|
||||
{
|
||||
assert_ser_tokens(value, tokens);
|
||||
assert_de_tokens(value, tokens);
|
||||
assert_tokens_readable(value, tokens, None);
|
||||
}
|
||||
|
||||
// Not public API
|
||||
#[doc(hidden)]
|
||||
/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
|
||||
///
|
||||
/// See: `assert_tokens`
|
||||
pub fn assert_tokens_readable<'de, T>(value: &T, tokens: &'de [Token], human_readable: Option<bool>)
|
||||
where
|
||||
T: Serialize + Deserialize<'de> + PartialEq + Debug,
|
||||
{
|
||||
assert_ser_tokens_readable(value, tokens, human_readable);
|
||||
assert_de_tokens_readable(value, tokens, human_readable);
|
||||
}
|
||||
|
||||
/// Asserts that `value` serializes to the given `tokens`.
|
||||
@@ -84,7 +96,19 @@ pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let mut ser = Serializer::new(tokens);
|
||||
assert_ser_tokens_readable(value, tokens, None)
|
||||
}
|
||||
|
||||
// Not public API
|
||||
#[doc(hidden)]
|
||||
/// Asserts that `value` serializes to the given `tokens`.
|
||||
///
|
||||
/// See: `assert_ser_tokens`
|
||||
pub fn assert_ser_tokens_readable<T>(value: &T, tokens: &[Token], human_readable: Option<bool>)
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let mut ser = Serializer::readable(tokens, human_readable);
|
||||
match value.serialize(&mut ser) {
|
||||
Ok(_) => {}
|
||||
Err(err) => panic!("value failed to serialize: {}", err),
|
||||
@@ -183,7 +207,16 @@ pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
||||
where
|
||||
T: Deserialize<'de> + PartialEq + Debug,
|
||||
{
|
||||
let mut de = Deserializer::new(tokens);
|
||||
assert_de_tokens_readable(value, tokens, None)
|
||||
}
|
||||
|
||||
// Not public API
|
||||
#[doc(hidden)]
|
||||
pub fn assert_de_tokens_readable<'de, T>(value: &T, tokens: &'de [Token], human_readable: Option<bool>)
|
||||
where
|
||||
T: Deserialize<'de> + PartialEq + Debug,
|
||||
{
|
||||
let mut de = Deserializer::readable(tokens, human_readable);
|
||||
match T::deserialize(&mut de) {
|
||||
Ok(v) => assert_eq!(v, *value),
|
||||
Err(e) => panic!("tokens failed to deserialize: {}", e),
|
||||
|
||||
+20
-1
@@ -16,6 +16,7 @@ use token::Token;
|
||||
#[derive(Debug)]
|
||||
pub struct Deserializer<'de> {
|
||||
tokens: &'de [Token],
|
||||
is_human_readable: Option<bool>,
|
||||
}
|
||||
|
||||
macro_rules! assert_next_token {
|
||||
@@ -48,7 +49,13 @@ macro_rules! end_of_tokens {
|
||||
|
||||
impl<'de> Deserializer<'de> {
|
||||
pub fn new(tokens: &'de [Token]) -> Self {
|
||||
Deserializer { tokens: tokens }
|
||||
Deserializer::readable(tokens, None)
|
||||
}
|
||||
|
||||
// Not public API
|
||||
#[doc(hidden)]
|
||||
pub fn readable(tokens: &'de [Token], is_human_readable: Option<bool>) -> Self {
|
||||
Deserializer { tokens: tokens, is_human_readable: is_human_readable }
|
||||
}
|
||||
|
||||
fn peek_token_opt(&self) -> Option<Token> {
|
||||
@@ -364,6 +371,18 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
_ => self.deserialize_any(visitor),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_human_readable(&self) -> bool {
|
||||
match self.is_human_readable {
|
||||
Some(is) => is,
|
||||
None => {
|
||||
panic!("There is no serde_test API currently for testing types \
|
||||
that have different human-readable and compact \
|
||||
representation. See \
|
||||
https://github.com/serde-rs/serde/issues/1065.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.11")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.16")]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
@@ -168,8 +168,12 @@ mod token;
|
||||
mod assert;
|
||||
|
||||
pub use token::Token;
|
||||
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error, assert_de_tokens,
|
||||
assert_de_tokens_error};
|
||||
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error,
|
||||
assert_de_tokens, assert_de_tokens_error};
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
pub use assert::{assert_tokens_readable, assert_de_tokens_readable, assert_ser_tokens_readable};
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
|
||||
+20
-1
@@ -15,12 +15,19 @@ use token::Token;
|
||||
#[derive(Debug)]
|
||||
pub struct Serializer<'a> {
|
||||
tokens: &'a [Token],
|
||||
is_human_readable: Option<bool>,
|
||||
}
|
||||
|
||||
impl<'a> Serializer<'a> {
|
||||
/// Creates the serializer.
|
||||
pub fn new(tokens: &'a [Token]) -> Self {
|
||||
Serializer { tokens: tokens }
|
||||
Serializer::readable(tokens, None)
|
||||
}
|
||||
|
||||
// Not public API
|
||||
#[doc(hidden)]
|
||||
pub fn readable(tokens: &'a [Token], is_human_readable: Option<bool>) -> Self {
|
||||
Serializer { tokens: tokens, is_human_readable: is_human_readable }
|
||||
}
|
||||
|
||||
/// Pulls the next token off of the serializer, ignoring it.
|
||||
@@ -282,6 +289,18 @@ impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> {
|
||||
Ok(Variant { ser: self, end: Token::StructVariantEnd })
|
||||
}
|
||||
}
|
||||
|
||||
fn is_human_readable(&self) -> bool {
|
||||
match self.is_human_readable {
|
||||
Some(is) => is,
|
||||
None => {
|
||||
panic!("There is no serde_test API currently for testing types \
|
||||
that have different human-readable and compact \
|
||||
representation. See \
|
||||
https://github.com/serde-rs/serde/issues/1065.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Variant<'s, 'a: 's> {
|
||||
|
||||
@@ -10,7 +10,7 @@ unstable = ["serde/unstable", "compiletest_rs"]
|
||||
[dev-dependencies]
|
||||
fnv = "1.0"
|
||||
rustc-serialize = "0.3.16"
|
||||
serde = { path = "../serde" }
|
||||
serde = { path = "../serde", features = ["rc"] }
|
||||
serde_derive = { path = "../serde_derive" }
|
||||
serde_test = { path = "../serde_test" }
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Newtype` cannot have both #[serde(deserialize_with)] and a field 0 marked with #[serde(skip_deserializing)]
|
||||
enum Enum {
|
||||
#[serde(deserialize_with = "deserialize_some_newtype_variant")]
|
||||
Newtype(#[serde(skip_deserializing)] String),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Struct` cannot have both #[serde(deserialize_with)] and a field `f1` marked with #[serde(skip_deserializing)]
|
||||
enum Enum {
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
Struct {
|
||||
#[serde(skip_deserializing)]
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Tuple` cannot have both #[serde(deserialize_with)] and a field 0 marked with #[serde(skip_deserializing)]
|
||||
enum Enum {
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
Tuple(#[serde(skip_deserializing)] String, u8),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Unit` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]
|
||||
enum Enum {
|
||||
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||
#[serde(skip_deserializing)]
|
||||
Unit,
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Newtype` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||
Newtype(#[serde(skip_serializing)] String),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Newtype` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing_if)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||
Newtype(#[serde(skip_serializing_if = "always")] String),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
Struct {
|
||||
#[serde(skip_serializing)]
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing_if)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||
Struct {
|
||||
#[serde(skip_serializing_if = "always")]
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Tuple` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
Tuple(#[serde(skip_serializing)] String, u8),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Tuple` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing_if)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
Tuple(#[serde(skip_serializing_if = "always")] String, u8),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Unit` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||
#[serde(skip_serializing)]
|
||||
Unit,
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -13,7 +13,7 @@ extern crate compiletest_rs as compiletest;
|
||||
use std::env;
|
||||
|
||||
fn run_mode(mode: &'static str) {
|
||||
let mut config = compiletest::default_config();
|
||||
let mut config = compiletest::Config::default();
|
||||
|
||||
config.mode = mode.parse().expect("invalid mode");
|
||||
config.target_rustcflags = Some("-L deps/target/debug/deps".to_owned());
|
||||
|
||||
@@ -73,3 +73,29 @@ macro_rules! hashmap {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! seq_impl {
|
||||
(seq $first:expr,) => {
|
||||
seq_impl!(seq $first)
|
||||
};
|
||||
($first:expr,) => {
|
||||
seq_impl!($first)
|
||||
};
|
||||
(seq $first:expr) => {
|
||||
$first.into_iter()
|
||||
};
|
||||
($first:expr) => {
|
||||
Some($first).into_iter()
|
||||
};
|
||||
(seq $first:expr , $( $elem: tt)*) => {
|
||||
$first.into_iter().chain(seq!( $($elem)* ))
|
||||
};
|
||||
($first:expr , $($elem: tt)*) => {
|
||||
Some($first).into_iter().chain(seq!( $($elem)* ))
|
||||
}
|
||||
}
|
||||
macro_rules! seq {
|
||||
($($tt: tt)*) => {
|
||||
seq_impl!($($tt)*).collect::<Vec<_>>()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,11 +6,14 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
extern crate serde;
|
||||
use self::serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||
use self::serde::de::{self, Unexpected};
|
||||
|
||||
extern crate serde_test;
|
||||
use self::serde_test::{Token, assert_tokens, assert_ser_tokens, assert_de_tokens,
|
||||
@@ -811,6 +814,145 @@ fn test_serialize_with_enum() {
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
enum WithVariant {
|
||||
#[serde(serialize_with="serialize_unit_variant_as_i8")]
|
||||
#[serde(deserialize_with="deserialize_i8_as_unit_variant")]
|
||||
Unit,
|
||||
|
||||
#[serde(serialize_with="SerializeWith::serialize_with")]
|
||||
#[serde(deserialize_with="DeserializeWith::deserialize_with")]
|
||||
Newtype(i32),
|
||||
|
||||
#[serde(serialize_with="serialize_variant_as_string")]
|
||||
#[serde(deserialize_with="deserialize_string_as_variant")]
|
||||
Tuple(String, u8),
|
||||
|
||||
#[serde(serialize_with="serialize_variant_as_string")]
|
||||
#[serde(deserialize_with="deserialize_string_as_variant")]
|
||||
Struct {
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
}
|
||||
|
||||
fn serialize_unit_variant_as_i8<S>(serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
serializer.serialize_i8(0)
|
||||
}
|
||||
|
||||
fn deserialize_i8_as_unit_variant<'de, D>(deserializer: D) -> Result<(), D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
let n = i8::deserialize(deserializer)?;
|
||||
match n {
|
||||
0 => Ok(()),
|
||||
_ => Err(de::Error::invalid_value(Unexpected::Signed(n as i64), &"0")),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_variant_as_string<S>(f1: &str,
|
||||
f2: &u8,
|
||||
serializer: S)
|
||||
-> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(format!("{};{:?}", f1, f2).as_str())
|
||||
}
|
||||
|
||||
fn deserialize_string_as_variant<'de, D>(deserializer: D) -> Result<(String, u8), D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
let mut pieces = s.split(';');
|
||||
let f1 = match pieces.next() {
|
||||
Some(x) => x,
|
||||
None => return Err(de::Error::invalid_length(0, &"2")),
|
||||
};
|
||||
let f2 = match pieces.next() {
|
||||
Some(x) => x,
|
||||
None => return Err(de::Error::invalid_length(1, &"2")),
|
||||
};
|
||||
let f2 = match f2.parse() {
|
||||
Ok(n) => n,
|
||||
Err(_) => {
|
||||
return Err(de::Error::invalid_value(Unexpected::Str(f2), &"an 8-bit signed integer"));
|
||||
}
|
||||
};
|
||||
Ok((f1.into(), f2))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_with_variant() {
|
||||
assert_ser_tokens(
|
||||
&WithVariant::Unit,
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Unit" },
|
||||
Token::I8(0),
|
||||
],
|
||||
);
|
||||
|
||||
assert_ser_tokens(
|
||||
&WithVariant::Newtype(123),
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Newtype" },
|
||||
Token::Bool(true),
|
||||
],
|
||||
);
|
||||
|
||||
assert_ser_tokens(
|
||||
&WithVariant::Tuple("hello".into(), 0),
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Tuple" },
|
||||
Token::Str("hello;0"),
|
||||
],
|
||||
);
|
||||
|
||||
assert_ser_tokens(
|
||||
&WithVariant::Struct { f1: "world".into(), f2: 1 },
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Struct" },
|
||||
Token::Str("world;1"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_with_variant() {
|
||||
assert_de_tokens(
|
||||
&WithVariant::Unit,
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Unit" },
|
||||
Token::I8(0),
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&WithVariant::Newtype(123),
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Newtype" },
|
||||
Token::Bool(true),
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&WithVariant::Tuple("hello".into(), 0),
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Tuple" },
|
||||
Token::Str("hello;0"),
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&WithVariant::Struct { f1: "world".into(), f2: 1 },
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Struct" },
|
||||
Token::Str("world;1"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
struct DeserializeWithStruct<B>
|
||||
where
|
||||
|
||||
+165
-39
@@ -6,8 +6,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(feature = "unstable", feature(into_boxed_c_str))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
@@ -17,6 +15,8 @@ use std::path::{Path, PathBuf};
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
use std::default::Default;
|
||||
use std::ffi::{CString, OsString};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
use std::ffi::CStr;
|
||||
@@ -28,7 +28,7 @@ extern crate fnv;
|
||||
use self::fnv::FnvHasher;
|
||||
|
||||
extern crate serde_test;
|
||||
use self::serde_test::{Token, assert_de_tokens, assert_de_tokens_error};
|
||||
use self::serde_test::{Token, assert_de_tokens, assert_de_tokens_error, assert_de_tokens_readable};
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
@@ -109,25 +109,37 @@ enum EnumSkipAll {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! declare_test {
|
||||
($name:ident { $($value:expr => $tokens:expr,)+ }) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
$(
|
||||
// Test ser/de roundtripping
|
||||
assert_de_tokens(&$value, $tokens);
|
||||
|
||||
// Test that the tokens are ignorable
|
||||
assert_de_tokens_ignore($tokens);
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! declare_tests {
|
||||
(
|
||||
readable: $readable:tt
|
||||
$($name:ident { $($value:expr => $tokens:expr,)+ })+
|
||||
) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $name() {
|
||||
$(
|
||||
// Test ser/de roundtripping
|
||||
assert_de_tokens_readable(&$value, $tokens, Some($readable));
|
||||
|
||||
// Test that the tokens are ignorable
|
||||
assert_de_tokens_ignore($tokens);
|
||||
)+
|
||||
}
|
||||
)+
|
||||
};
|
||||
|
||||
($($name:ident { $($value:expr => $tokens:expr,)+ })+) => {
|
||||
$(
|
||||
declare_test!($name { $($value => $tokens,)+ });
|
||||
#[test]
|
||||
fn $name() {
|
||||
$(
|
||||
// Test ser/de roundtripping
|
||||
assert_de_tokens(&$value, $tokens);
|
||||
|
||||
// Test that the tokens are ignorable
|
||||
assert_de_tokens_ignore($tokens);
|
||||
)+
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
@@ -521,6 +533,15 @@ declare_tests! {
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::U32(0),
|
||||
Token::I32(1),
|
||||
|
||||
Token::U32(1),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Struct { name: "Struct", len: 3 },
|
||||
Token::Str("a"),
|
||||
@@ -716,17 +737,6 @@ declare_tests! {
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_net_ipv4addr {
|
||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_ipv6addr {
|
||||
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
|
||||
}
|
||||
test_net_socketaddr {
|
||||
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
|
||||
}
|
||||
test_path {
|
||||
Path::new("/usr/local/lib") => &[
|
||||
Token::BorrowedStr("/usr/local/lib"),
|
||||
@@ -742,6 +752,131 @@ declare_tests! {
|
||||
Token::Bytes(b"abc"),
|
||||
],
|
||||
}
|
||||
test_rc {
|
||||
Rc::new(true) => &[
|
||||
Token::Bool(true),
|
||||
],
|
||||
}
|
||||
test_arc {
|
||||
Arc::new(true) => &[
|
||||
Token::Bool(true),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
declare_tests! {
|
||||
readable: true
|
||||
test_net_ipv4addr_readable {
|
||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_ipv6addr_readable {
|
||||
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
|
||||
}
|
||||
test_net_ipaddr_readable {
|
||||
"1.2.3.4".parse::<net::IpAddr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_socketaddr_readable {
|
||||
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
|
||||
}
|
||||
}
|
||||
|
||||
declare_tests! {
|
||||
readable: false
|
||||
test_net_ipv4addr_compact {
|
||||
net::Ipv4Addr::from(*b"1234") => &seq![
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd
|
||||
],
|
||||
}
|
||||
test_net_ipv6addr_compact {
|
||||
net::Ipv6Addr::from(*b"1234567890123456") => &seq![
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd
|
||||
],
|
||||
}
|
||||
test_net_ipaddr_compact {
|
||||
net::IpAddr::from(*b"1234") => &seq![
|
||||
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd
|
||||
],
|
||||
}
|
||||
test_net_socketaddr_compact {
|
||||
net::SocketAddr::from((*b"1234567890123456", 1234)) => &seq![
|
||||
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
|
||||
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd
|
||||
],
|
||||
net::SocketAddr::from((*b"1234", 1234)) => &seq![
|
||||
Token::NewtypeVariant { name: "SocketAddr", variant: "V4" },
|
||||
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd
|
||||
],
|
||||
net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234) => &seq![
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd
|
||||
],
|
||||
net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0) => &seq![
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
declare_tests! {
|
||||
test_rc_dst {
|
||||
Rc::<str>::from("s") => &[
|
||||
Token::Str("s"),
|
||||
],
|
||||
Rc::<[bool]>::from(&[true][..]) => &[
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::Bool(true),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_arc_dst {
|
||||
Arc::<str>::from("s") => &[
|
||||
Token::Str("s"),
|
||||
],
|
||||
Arc::<[bool]>::from(&[true][..]) => &[
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::Bool(true),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -793,15 +928,6 @@ fn test_cstr() {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
#[test]
|
||||
fn test_net_ipaddr() {
|
||||
assert_de_tokens(
|
||||
&"1.2.3.4".parse::<net::IpAddr>().unwrap(),
|
||||
&[Token::Str("1.2.3.4")],
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
#[test]
|
||||
fn test_cstr_internal_null() {
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
// successfully when there are a variety of generics and non-(de)serializable
|
||||
// types involved.
|
||||
|
||||
#![deny(warnings)]
|
||||
|
||||
#![cfg_attr(feature = "unstable", feature(non_ascii_idents))]
|
||||
|
||||
// Clippy false positive
|
||||
@@ -373,6 +375,146 @@ fn test_gen() {
|
||||
#[serde(with = "vis::SDef")]
|
||||
s: vis::S,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum ExternallyTaggedVariantWith {
|
||||
#[allow(dead_code)]
|
||||
Normal { f1: String },
|
||||
|
||||
#[serde(serialize_with = "ser_x")]
|
||||
#[serde(deserialize_with = "de_x")]
|
||||
#[allow(dead_code)]
|
||||
Newtype(X),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Tuple(String, u8),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Struct {
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
|
||||
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||
#[allow(dead_code)]
|
||||
Unit,
|
||||
}
|
||||
assert_ser::<ExternallyTaggedVariantWith>();
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(tag = "t")]
|
||||
enum InternallyTaggedVariantWith {
|
||||
#[allow(dead_code)]
|
||||
Normal { f1: String },
|
||||
|
||||
#[serde(serialize_with = "ser_x")]
|
||||
#[serde(deserialize_with = "de_x")]
|
||||
#[allow(dead_code)]
|
||||
Newtype(X),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Struct {
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
|
||||
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||
#[allow(dead_code)]
|
||||
Unit,
|
||||
}
|
||||
assert_ser::<InternallyTaggedVariantWith>();
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(tag = "t", content = "c")]
|
||||
enum AdjacentlyTaggedVariantWith {
|
||||
#[allow(dead_code)]
|
||||
Normal { f1: String },
|
||||
|
||||
#[serde(serialize_with = "ser_x")]
|
||||
#[serde(deserialize_with = "de_x")]
|
||||
#[allow(dead_code)]
|
||||
Newtype(X),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Tuple(String, u8),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Struct {
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
|
||||
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||
#[allow(dead_code)]
|
||||
Unit,
|
||||
}
|
||||
assert_ser::<AdjacentlyTaggedVariantWith>();
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum UntaggedVariantWith {
|
||||
#[allow(dead_code)]
|
||||
Normal { f1: String },
|
||||
|
||||
#[serde(serialize_with = "ser_x")]
|
||||
#[serde(deserialize_with = "de_x")]
|
||||
#[allow(dead_code)]
|
||||
Newtype(X),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Tuple(String, u8),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Struct {
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
|
||||
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||
#[allow(dead_code)]
|
||||
Unit,
|
||||
}
|
||||
assert_ser::<UntaggedVariantWith>();
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct StaticStrStruct<'a> {
|
||||
a: &'a str,
|
||||
b: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct StaticStrTupleStruct<'a>(&'a str, &'static str);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct StaticStrNewtypeStruct(&'static str);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum StaticStrEnum<'a> {
|
||||
Struct {
|
||||
a: &'a str,
|
||||
b: &'static str,
|
||||
},
|
||||
Tuple(&'a str, &'static str),
|
||||
Newtype(&'static str),
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -414,3 +556,29 @@ impl DeserializeWith for X {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize_some_unit_variant<S>(_: S) -> StdResult<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn deserialize_some_unit_variant<'de, D>(_: D) -> StdResult<(), D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn serialize_some_other_variant<S>(_: &str, _: &u8, _: S) -> StdResult<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn deserialize_some_other_variant<'de, D>(_: D) -> StdResult<(String, u8), D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn is_zero(n: &u8) -> bool { *n == 0 }
|
||||
|
||||
@@ -23,7 +23,10 @@ fn test_variant_identifier() {
|
||||
Bbb,
|
||||
}
|
||||
|
||||
assert_de_tokens(&V::Aaa, &[Token::U8(0)]);
|
||||
assert_de_tokens(&V::Aaa, &[Token::U16(0)]);
|
||||
assert_de_tokens(&V::Aaa, &[Token::U32(0)]);
|
||||
assert_de_tokens(&V::Aaa, &[Token::U64(0)]);
|
||||
assert_de_tokens(&V::Aaa, &[Token::Str("Aaa")]);
|
||||
assert_de_tokens(&V::Aaa, &[Token::Bytes(b"Aaa")]);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![deny(trivial_numeric_casts)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
@@ -589,11 +591,10 @@ fn test_internally_tagged_enum() {
|
||||
#[serde(tag = "type")]
|
||||
enum InternallyTagged {
|
||||
A { a: u8 },
|
||||
B { b: u8 },
|
||||
C,
|
||||
D(BTreeMap<String, String>),
|
||||
E(Newtype),
|
||||
F(Struct),
|
||||
B,
|
||||
C(BTreeMap<String, String>),
|
||||
D(Newtype),
|
||||
E(Struct),
|
||||
}
|
||||
|
||||
assert_tokens(
|
||||
@@ -611,35 +612,62 @@ fn test_internally_tagged_enum() {
|
||||
],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::B { b: 2 },
|
||||
assert_de_tokens(
|
||||
&InternallyTagged::A { a: 1 },
|
||||
&[
|
||||
Token::Struct { name: "InternallyTagged", len: 2 },
|
||||
|
||||
Token::Str("type"),
|
||||
Token::Str("B"),
|
||||
|
||||
Token::Str("b"),
|
||||
Token::U8(2),
|
||||
|
||||
Token::StructEnd,
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::Str("A"),
|
||||
Token::U8(1),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::C,
|
||||
&InternallyTagged::B,
|
||||
&[
|
||||
Token::Struct { name: "InternallyTagged", len: 1 },
|
||||
|
||||
Token::Str("type"),
|
||||
Token::Str("C"),
|
||||
Token::Str("B"),
|
||||
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&InternallyTagged::B,
|
||||
&[
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::Str("B"),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::D(BTreeMap::new()),
|
||||
&InternallyTagged::C(BTreeMap::new()),
|
||||
&[
|
||||
Token::Map { len: Some(1) },
|
||||
|
||||
Token::Str("type"),
|
||||
Token::Str("C"),
|
||||
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<InternallyTagged>(
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::Str("C"),
|
||||
Token::Map { len: Some(0) },
|
||||
Token::MapEnd,
|
||||
Token::SeqEnd,
|
||||
],
|
||||
"invalid type: sequence, expected a map",
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::D(Newtype(BTreeMap::new())),
|
||||
&[
|
||||
Token::Map { len: Some(1) },
|
||||
|
||||
@@ -651,24 +679,12 @@ fn test_internally_tagged_enum() {
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::E(Newtype(BTreeMap::new())),
|
||||
&[
|
||||
Token::Map { len: Some(1) },
|
||||
|
||||
Token::Str("type"),
|
||||
Token::Str("E"),
|
||||
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::F(Struct { f: 6 }),
|
||||
&InternallyTagged::E(Struct { f: 6 }),
|
||||
&[
|
||||
Token::Struct { name: "Struct", len: 2 },
|
||||
|
||||
Token::Str("type"),
|
||||
Token::Str("F"),
|
||||
Token::Str("E"),
|
||||
|
||||
Token::Str("f"),
|
||||
Token::U8(6),
|
||||
@@ -677,6 +693,16 @@ fn test_internally_tagged_enum() {
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&InternallyTagged::E(Struct { f: 6 }),
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::Str("E"),
|
||||
Token::U8(6),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<InternallyTagged>(
|
||||
&[Token::Map { len: Some(0) }, Token::MapEnd],
|
||||
"missing field `type`",
|
||||
@@ -691,7 +717,7 @@ fn test_internally_tagged_enum() {
|
||||
|
||||
Token::MapEnd,
|
||||
],
|
||||
"unknown variant `Z`, expected one of `A`, `B`, `C`, `D`, `E`, `F`",
|
||||
"unknown variant `Z`, expected one of `A`, `B`, `C`, `D`, `E`",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1149,7 +1175,7 @@ fn test_rename_all() {
|
||||
SerializeMap {
|
||||
serialize: bool,
|
||||
serialize_seq: bool,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
@@ -1159,6 +1185,13 @@ fn test_rename_all() {
|
||||
serialize_seq: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename_all = "SCREAMING-KEBAB-CASE")]
|
||||
struct ScreamingKebab {
|
||||
serialize: bool,
|
||||
serialize_seq: bool,
|
||||
}
|
||||
|
||||
assert_tokens(
|
||||
&E::Serialize {
|
||||
serialize: true,
|
||||
@@ -1218,4 +1251,19 @@ fn test_rename_all() {
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&ScreamingKebab {
|
||||
serialize: true,
|
||||
serialize_seq: true,
|
||||
},
|
||||
&[
|
||||
Token::Struct { name: "ScreamingKebab", len: 2 },
|
||||
Token::Str("SERIALIZE"),
|
||||
Token::Bool(true),
|
||||
Token::Str("SERIALIZE-SEQ"),
|
||||
Token::Bool(true),
|
||||
Token::StructEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
extern crate serde_test;
|
||||
use self::serde_test::{Token, assert_tokens_readable};
|
||||
|
||||
use std::net;
|
||||
|
||||
#[macro_use]
|
||||
#[allow(unused_macros)]
|
||||
mod macros;
|
||||
|
||||
#[test]
|
||||
fn ip_addr_roundtrip() {
|
||||
|
||||
assert_tokens_readable(
|
||||
&net::IpAddr::from(*b"1234"),
|
||||
&seq![
|
||||
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
Some(false),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn socked_addr_roundtrip() {
|
||||
|
||||
assert_tokens_readable(
|
||||
&net::SocketAddr::from((*b"1234567890123456", 1234)),
|
||||
&seq![
|
||||
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
|
||||
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
Some(false),
|
||||
);
|
||||
}
|
||||
+129
-18
@@ -14,6 +14,8 @@ use std::net;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
use std::ffi::CString;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::str;
|
||||
@@ -21,7 +23,8 @@ use std::str;
|
||||
extern crate serde;
|
||||
|
||||
extern crate serde_test;
|
||||
use self::serde_test::{Token, assert_ser_tokens, assert_ser_tokens_error};
|
||||
use self::serde_test::{Token, assert_ser_tokens, assert_ser_tokens_error,
|
||||
assert_ser_tokens_readable};
|
||||
|
||||
extern crate fnv;
|
||||
use self::fnv::FnvHasher;
|
||||
@@ -63,6 +66,20 @@ enum Enum {
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! declare_tests {
|
||||
(
|
||||
readable: $readable:tt
|
||||
$($name:ident { $($value:expr => $tokens:expr,)+ })+
|
||||
) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $name() {
|
||||
$(
|
||||
assert_ser_tokens_readable(&$value, $tokens, Some($readable));
|
||||
)+
|
||||
}
|
||||
)+
|
||||
};
|
||||
|
||||
($($name:ident { $($value:expr => $tokens:expr,)+ })+) => {
|
||||
$(
|
||||
#[test]
|
||||
@@ -352,17 +369,6 @@ declare_tests! {
|
||||
Token::StructEnd,
|
||||
],
|
||||
}
|
||||
test_net_ipv4addr {
|
||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_ipv6addr {
|
||||
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
|
||||
}
|
||||
test_net_socketaddr {
|
||||
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
|
||||
}
|
||||
test_path {
|
||||
Path::new("/usr/local/lib") => &[
|
||||
Token::Str("/usr/local/lib"),
|
||||
@@ -383,15 +389,120 @@ declare_tests! {
|
||||
Token::Bytes(b"abc"),
|
||||
],
|
||||
}
|
||||
test_rc {
|
||||
Rc::new(true) => &[
|
||||
Token::Bool(true),
|
||||
],
|
||||
}
|
||||
test_arc {
|
||||
Arc::new(true) => &[
|
||||
Token::Bool(true),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
declare_tests! {
|
||||
readable: true
|
||||
test_net_ipv4addr_readable {
|
||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_ipv6addr_readable {
|
||||
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
|
||||
}
|
||||
test_net_ipaddr_readable {
|
||||
"1.2.3.4".parse::<net::IpAddr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_socketaddr_readable {
|
||||
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
|
||||
}
|
||||
}
|
||||
|
||||
declare_tests! {
|
||||
readable: false
|
||||
test_net_ipv4addr_compact {
|
||||
net::Ipv4Addr::from(*b"1234") => &seq![
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
}
|
||||
test_net_ipv6addr_compact {
|
||||
net::Ipv6Addr::from(*b"1234567890123456") => &seq![
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
}
|
||||
test_net_ipaddr_compact {
|
||||
net::IpAddr::from(*b"1234") => &seq![
|
||||
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
}
|
||||
test_net_socketaddr_compact {
|
||||
net::SocketAddr::from((*b"1234567890123456", 1234)) => &seq![
|
||||
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
|
||||
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234) => &seq![
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0) => &seq![
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
// Serde's implementation is not unstable, but the constructors are.
|
||||
#[cfg(feature = "unstable")]
|
||||
#[test]
|
||||
fn test_net_ipaddr() {
|
||||
assert_ser_tokens(
|
||||
&"1.2.3.4".parse::<net::IpAddr>().unwrap(),
|
||||
&[Token::Str("1.2.3.4")],
|
||||
);
|
||||
declare_tests! {
|
||||
test_rc_dst {
|
||||
Rc::<str>::from("s") => &[
|
||||
Token::Str("s"),
|
||||
],
|
||||
Rc::<[bool]>::from(&[true][..]) => &[
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::Bool(true),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_arc_dst {
|
||||
Arc::<str>::from("s") => &[
|
||||
Token::Str("s"),
|
||||
],
|
||||
Arc::<[bool]>::from(&[true][..]) => &[
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::Bool(true),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user