Compare commits

...

51 Commits

Author SHA1 Message Date
David Tolnay 382f3c2771 Release 1.0.41 2018-04-19 22:13:45 -07:00
David Tolnay 85ca12a8c3 Deserialize any integer from any buffered integer type 2018-04-19 22:11:14 -07:00
David Tolnay 541f9180cf Release 1.0.40 2018-04-19 10:31:33 -07:00
David Tolnay 3c4961c48e Lenient byte and string deserialization from buffered content 2018-04-19 10:21:55 -07:00
David Tolnay 184264ee92 Release 1.0.39 2018-04-17 11:35:45 -07:00
David Tolnay 6050229e7e Simplify counting remaining elements 2018-04-17 00:15:09 -07:00
David Tolnay e1db820c9f Implement all &Content deserializer hints 2018-04-17 00:15:05 -07:00
David Tolnay 0081cc961d Implement all Content deserializer hints 2018-04-17 00:14:59 -07:00
David Tolnay 9bc05803fe Fix clippy lint about literal in format string 2018-04-15 22:07:47 -07:00
David Tolnay 8d113e67d6 Release 1.0.38 2018-04-14 20:30:18 -07:00
David Tolnay 6e206ce053 Name formatter args with a leading double underscore 2018-04-13 00:21:21 -07:00
David Tolnay 47fc9af472 Emit borrowed methods only if collect_other_fields
Without collect_other_fields, the visit_borrowed_str and
visit_borrowed_bytes implementations that were being generated were
identical to their default implementation of forwarding to visit_str and
visit_bytes.
2018-04-13 00:17:34 -07:00
David Tolnay 1651f86d56 Simplify Option that is always Some 2018-04-13 00:17:30 -07:00
David Tolnay 1157ac0118 Eliminate unnecessary braces in wrap_deserialize_variant_with 2018-04-12 23:48:38 -07:00
David Tolnay 202c10147e Fix deserialize_with on a struct variant with one field 2018-04-12 23:44:53 -07:00
David Tolnay 9f38ca032e Format with rustfmt 0.4.1 2018-04-12 23:04:47 -07:00
David Tolnay 00178ba795 Eliminate generic functions in bound.rs 2018-04-12 22:48:31 -07:00
David Tolnay 24700ebeb6 Move associated type search into with_bounds 2018-04-12 22:46:53 -07:00
David Tolnay f06001c086 Name type_params consistently with Syn 2018-04-12 22:04:34 -07:00
David Tolnay ec773fb7db Make use of Generics::type_params iterator 2018-04-12 22:03:40 -07:00
David Tolnay da8b457f66 Simplify with_where_predicates_from_fields 2018-04-12 21:47:08 -07:00
David Tolnay a6e94e7122 Merge pull request #1213 from Osspial/assoc_type_derive
Support #[derive(Serialize, Deserialize)] when using associated types
2018-04-12 18:13:46 -07:00
Osspial 629bf7b354 Fix clippy warnings 2018-04-12 18:40:06 -04:00
Osspial 4415d10c61 Fix associated types only working for first generic parameter
Also, removes extraneous `where for`
2018-04-12 16:44:34 -04:00
Osspial def8d6e8af Add associated type test 2018-04-10 11:16:32 -04:00
Osspial 2e824e9aba Limit type bounds to associated types 2018-04-10 10:53:37 -04:00
Osspial fd14332729 Ignore skipped fields 2018-04-09 23:57:20 -04:00
Osspial c413775574 Add partially-working where bounds for associated types 2018-04-09 23:22:18 -04:00
David Tolnay 5efb22ebee Format no_std test code with rustfmt 0.4.1 2018-04-07 19:22:24 -07:00
David Tolnay 3e535325e1 Remove unused compiler_builtins_lib feature 2018-04-07 19:20:55 -07:00
David Tolnay 5653e5b15c Remove eh_unwind_resume lang item
It appears this is no longer needed.
2018-04-07 19:20:07 -07:00
David Tolnay 8d85860064 Remove no longer needed compiler_builtins
The `compiler_builtins` crate is now automatically injected whenever the
`core` crate is injected.
2018-04-07 19:18:38 -07:00
David Tolnay eed18ffab2 Release 1.0.37 2018-04-01 22:30:32 -07:00
David Tolnay f8e1fa8ebc Use Generics::make_where_clause helper 2018-04-01 22:25:50 -07:00
David Tolnay 860241aa88 Merge pull request #1205 from mitsuhiko/bugfix/tuple-struct-flatten
Produce error message for use of flatten in tuple structs
2018-04-02 07:09:39 +02:00
David Tolnay 6f6c60867d Merge pull request #1204 from mitsuhiko/bugfix/flatten-struct-variant
Produce error message for use of flatten within struct variant
2018-04-02 07:09:23 +02:00
Armin Ronacher 77376f39ea Produce error message for use of flatten in tuple structs 2018-04-01 22:11:21 +02:00
Armin Ronacher 302fac91a3 Produce error message for use of flatten within struct variant 2018-04-01 22:01:24 +02:00
David Tolnay 9c659d9d86 Format with rustfmt 0.4.1 2018-04-01 00:06:54 +02:00
David Tolnay 21698f264a Merge pull request #1201 from alexcrichton/proc-macro2-v3
Update to syn/quote/proc-macro2 new apis
2018-03-31 23:56:29 +02:00
David Tolnay ba002e1119 Update signature of Lifetime::new 2018-03-31 23:46:25 +02:00
David Tolnay 8b44eb8bfc Add parens to TraitBound 2018-03-31 23:45:30 +02:00
David Tolnay d82a0cc5ff Remove use of Span::located_at 2018-03-31 23:44:50 +02:00
David Tolnay 801fd1dc19 Drop the patch dependencies 2018-03-31 23:09:01 +02:00
David Tolnay 222779d46c Document that rc impls require a feature
Fixes #1203.
2018-03-30 10:31:54 +02:00
Alex Crichton b1c1d964e1 Update to syn/quote/proc-macro2 new apis 2018-03-29 00:54:05 -07:00
David Tolnay b77cfb635d Less eye-catching rustc version badge 2018-03-28 14:59:53 +02:00
David Tolnay c42c08a25b Merge pull request #1199 from serde-rs/rustc
Rustc version badge
2018-03-28 14:44:12 +02:00
David Tolnay 48997cbb5b Rustc version badge 2018-03-28 14:35:01 +02:00
David Tolnay d8ccd8809e Merge pull request #1198 from serde-rs/call_site
Prefer call site spans
2018-03-28 11:03:01 +02:00
David Tolnay d2b65e0a5d Prefer call site spans 2018-03-28 10:49:30 +02:00
36 changed files with 2491 additions and 1162 deletions
+3 -1
View File
@@ -1,9 +1,11 @@
# Serde   [![Build Status]][travis] [![Latest Version]][crates.io] # Serde   [![Build Status]][travis] [![Latest Version]][crates.io] [![Rustc Version 1.13+]][rustc]
[Build Status]: https://api.travis-ci.org/serde-rs/serde.svg?branch=master [Build Status]: https://api.travis-ci.org/serde-rs/serde.svg?branch=master
[travis]: https://travis-ci.org/serde-rs/serde [travis]: https://travis-ci.org/serde-rs/serde
[Latest Version]: https://img.shields.io/crates/v/serde.svg [Latest Version]: https://img.shields.io/crates/v/serde.svg
[crates.io]: https://crates.io/crates/serde [crates.io]: https://crates.io/crates/serde
[Rustc Version 1.13+]: https://img.shields.io/badge/rustc-1.13+-lightgray.svg
[rustc]: https://blog.rust-lang.org/2016/11/10/Rust-1.13.html
**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** **Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**
-1
View File
@@ -1,2 +1 @@
error_on_line_overflow = false error_on_line_overflow = false
same_line_attributes = false
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "1.0.36" # remember to update html_root_url version = "1.0.41" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
+132 -42
View File
@@ -9,33 +9,33 @@
use lib::*; use lib::*;
macro_rules! int_to_int { macro_rules! int_to_int {
($dst:ident, $n:ident) => ( ($dst:ident, $n:ident) => {
if $dst::min_value() as i64 <= $n as i64 && $n as i64 <= $dst::max_value() as i64 { if $dst::min_value() as i64 <= $n as i64 && $n as i64 <= $dst::max_value() as i64 {
Some($n as $dst) Some($n as $dst)
} else { } else {
None None
} }
) };
} }
macro_rules! int_to_uint { macro_rules! int_to_uint {
($dst:ident, $n:ident) => ( ($dst:ident, $n:ident) => {
if 0 <= $n && $n as u64 <= $dst::max_value() as u64 { if 0 <= $n && $n as u64 <= $dst::max_value() as u64 {
Some($n as $dst) Some($n as $dst)
} else { } else {
None None
} }
) };
} }
macro_rules! uint_to { macro_rules! uint_to {
($dst:ident, $n:ident) => ( ($dst:ident, $n:ident) => {
if $n as u64 <= $dst::max_value() as u64 { if $n as u64 <= $dst::max_value() as u64 {
Some($n as $dst) Some($n as $dst)
} else { } else {
None None
} }
) };
} }
pub trait FromPrimitive: Sized { pub trait FromPrimitive: Sized {
@@ -52,54 +52,144 @@ pub trait FromPrimitive: Sized {
} }
macro_rules! impl_from_primitive_for_int { macro_rules! impl_from_primitive_for_int {
($t:ident) => ( ($t:ident) => {
impl FromPrimitive for $t { impl FromPrimitive for $t {
#[inline] fn from_isize(n: isize) -> Option<Self> { int_to_int!($t, n) } #[inline]
#[inline] fn from_i8(n: i8) -> Option<Self> { int_to_int!($t, n) } fn from_isize(n: isize) -> Option<Self> {
#[inline] fn from_i16(n: i16) -> Option<Self> { int_to_int!($t, n) } int_to_int!($t, n)
#[inline] fn from_i32(n: i32) -> Option<Self> { int_to_int!($t, n) } }
#[inline] fn from_i64(n: i64) -> Option<Self> { int_to_int!($t, n) } #[inline]
#[inline] fn from_usize(n: usize) -> Option<Self> { uint_to!($t, n) } fn from_i8(n: i8) -> Option<Self> {
#[inline] fn from_u8(n: u8) -> Option<Self> { uint_to!($t, n) } int_to_int!($t, n)
#[inline] fn from_u16(n: u16) -> Option<Self> { uint_to!($t, n) } }
#[inline] fn from_u32(n: u32) -> Option<Self> { uint_to!($t, n) } #[inline]
#[inline] fn from_u64(n: u64) -> Option<Self> { uint_to!($t, n) } fn from_i16(n: i16) -> Option<Self> {
int_to_int!($t, n)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
int_to_int!($t, n)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
int_to_int!($t, n)
}
#[inline]
fn from_usize(n: usize) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
uint_to!($t, n)
}
} }
) };
} }
macro_rules! impl_from_primitive_for_uint { macro_rules! impl_from_primitive_for_uint {
($t:ident) => ( ($t:ident) => {
impl FromPrimitive for $t { impl FromPrimitive for $t {
#[inline] fn from_isize(n: isize) -> Option<Self> { int_to_uint!($t, n) } #[inline]
#[inline] fn from_i8(n: i8) -> Option<Self> { int_to_uint!($t, n) } fn from_isize(n: isize) -> Option<Self> {
#[inline] fn from_i16(n: i16) -> Option<Self> { int_to_uint!($t, n) } int_to_uint!($t, n)
#[inline] fn from_i32(n: i32) -> Option<Self> { int_to_uint!($t, n) } }
#[inline] fn from_i64(n: i64) -> Option<Self> { int_to_uint!($t, n) } #[inline]
#[inline] fn from_usize(n: usize) -> Option<Self> { uint_to!($t, n) } fn from_i8(n: i8) -> Option<Self> {
#[inline] fn from_u8(n: u8) -> Option<Self> { uint_to!($t, n) } int_to_uint!($t, n)
#[inline] fn from_u16(n: u16) -> Option<Self> { uint_to!($t, n) } }
#[inline] fn from_u32(n: u32) -> Option<Self> { uint_to!($t, n) } #[inline]
#[inline] fn from_u64(n: u64) -> Option<Self> { uint_to!($t, n) } fn from_i16(n: i16) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline]
fn from_usize(n: usize) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
uint_to!($t, n)
}
} }
) };
} }
macro_rules! impl_from_primitive_for_float { macro_rules! impl_from_primitive_for_float {
($t:ident) => ( ($t:ident) => {
impl FromPrimitive for $t { impl FromPrimitive for $t {
#[inline] fn from_isize(n: isize) -> Option<Self> { Some(n as Self) } #[inline]
#[inline] fn from_i8(n: i8) -> Option<Self> { Some(n as Self) } fn from_isize(n: isize) -> Option<Self> {
#[inline] fn from_i16(n: i16) -> Option<Self> { Some(n as Self) } Some(n as Self)
#[inline] fn from_i32(n: i32) -> Option<Self> { Some(n as Self) } }
#[inline] fn from_i64(n: i64) -> Option<Self> { Some(n as Self) } #[inline]
#[inline] fn from_usize(n: usize) -> Option<Self> { Some(n as Self) } fn from_i8(n: i8) -> Option<Self> {
#[inline] fn from_u8(n: u8) -> Option<Self> { Some(n as Self) } Some(n as Self)
#[inline] fn from_u16(n: u16) -> Option<Self> { Some(n as Self) } }
#[inline] fn from_u32(n: u32) -> Option<Self> { Some(n as Self) } #[inline]
#[inline] fn from_u64(n: u64) -> Option<Self> { Some(n as Self) } fn from_i16(n: i16) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_usize(n: usize) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
Some(n as Self)
}
} }
) };
} }
impl_from_primitive_for_int!(isize); impl_from_primitive_for_int!(isize);
+56 -15
View File
@@ -470,7 +470,11 @@ impl<'de> Deserialize<'de> for CString {
} }
macro_rules! forwarded_impl { macro_rules! forwarded_impl {
(( $($id: ident),* ), $ty: ty, $func: expr) => { (
$(#[doc = $doc:tt])*
( $($id: ident),* ), $ty: ty, $func: expr
) => {
$(#[doc = $doc])*
impl<'de $(, $id : Deserialize<'de>,)*> Deserialize<'de> for $ty { impl<'de $(, $id : Deserialize<'de>,)*> Deserialize<'de> for $ty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
@@ -1073,7 +1077,7 @@ map_impl!(
#[cfg(feature = "std")] #[cfg(feature = "std")]
macro_rules! parse_ip_impl { macro_rules! parse_ip_impl {
($ty:ty; $size: expr) => { ($ty:ty; $size:expr) => {
impl<'de> Deserialize<'de> for $ty { impl<'de> Deserialize<'de> for $ty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
@@ -1087,7 +1091,7 @@ macro_rules! parse_ip_impl {
} }
} }
} }
} };
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
@@ -1230,7 +1234,7 @@ parse_ip_impl!(net::Ipv6Addr; 16);
#[cfg(feature = "std")] #[cfg(feature = "std")]
macro_rules! parse_socket_impl { macro_rules! parse_socket_impl {
($ty:ty, $new: expr) => { ($ty:ty, $new:expr) => {
impl<'de> Deserialize<'de> for $ty { impl<'de> Deserialize<'de> for $ty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
@@ -1244,7 +1248,7 @@ macro_rules! parse_socket_impl {
} }
} }
} }
} };
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
@@ -1272,10 +1276,7 @@ parse_socket_impl!(net::SocketAddrV4, net::SocketAddrV4::new);
#[cfg(feature = "std")] #[cfg(feature = "std")]
parse_socket_impl!(net::SocketAddrV6, |ip, port| net::SocketAddrV6::new( parse_socket_impl!(net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(
ip, ip, port, 0, 0
port,
0,
0
)); ));
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -1432,10 +1433,28 @@ forwarded_impl!((T), Box<[T]>, Vec::into_boxed_slice);
forwarded_impl!((), Box<str>, String::into_boxed_str); forwarded_impl!((), Box<str>, String::into_boxed_str);
#[cfg(all(not(feature = "unstable"), 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); forwarded_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde.
///
/// Deserializing a data structure containing `Arc` will not attempt to
/// deduplicate `Arc` references to the same data. Every deserialized `Arc`
/// will end up with a strong count of 1.
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
(T), Arc<T>, Arc::new
}
#[cfg(all(not(feature = "unstable"), 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); forwarded_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde.
///
/// Deserializing a data structure containing `Rc` will not attempt to
/// deduplicate `Rc` references to the same data. Every deserialized `Rc`
/// will end up with a strong count of 1.
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
(T), Rc<T>, Rc::new
}
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T> impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T>
@@ -1456,7 +1475,11 @@ where
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))]
macro_rules! box_forwarded_impl { macro_rules! box_forwarded_impl {
($t:ident) => { (
$(#[doc = $doc:tt])*
$t:ident
) => {
$(#[doc = $doc])*
impl<'de, T: ?Sized> Deserialize<'de> for $t<T> impl<'de, T: ?Sized> Deserialize<'de> for $t<T>
where where
Box<T>: Deserialize<'de>, Box<T>: Deserialize<'de>,
@@ -1468,14 +1491,32 @@ macro_rules! box_forwarded_impl {
Box::deserialize(deserializer).map(Into::into) Box::deserialize(deserializer).map(Into::into)
} }
} }
} };
} }
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))]
box_forwarded_impl!(Rc); box_forwarded_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde.
///
/// Deserializing a data structure containing `Rc` will not attempt to
/// deduplicate `Rc` references to the same data. Every deserialized `Rc`
/// will end up with a strong count of 1.
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
Rc
}
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))]
box_forwarded_impl!(Arc); box_forwarded_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde.
///
/// Deserializing a data structure containing `Arc` will not attempt to
/// deduplicate `Arc` references to the same data. Every deserialized `Arc`
/// will end up with a strong count of 1.
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
Arc
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
+5 -11
View File
@@ -37,10 +37,10 @@
use lib::*; use lib::*;
use self::private::{First, Second};
use de::{self, Expected, IntoDeserializer, SeqAccess}; use de::{self, Expected, IntoDeserializer, SeqAccess};
use private::de::size_hint; use private::de::size_hint;
use ser; use ser;
use self::private::{First, Second};
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -652,11 +652,8 @@ where
{ {
/// Check for remaining elements after passing a `SeqDeserializer` to /// Check for remaining elements after passing a `SeqDeserializer` to
/// `Visitor::visit_seq`. /// `Visitor::visit_seq`.
pub fn end(mut self) -> Result<(), E> { pub fn end(self) -> Result<(), E> {
let mut remaining = 0; let remaining = self.iter.count();
while self.iter.next().is_some() {
remaining += 1;
}
if remaining == 0 { if remaining == 0 {
Ok(()) Ok(())
} else { } else {
@@ -849,11 +846,8 @@ where
{ {
/// Check for remaining elements after passing a `MapDeserializer` to /// Check for remaining elements after passing a `MapDeserializer` to
/// `Visitor::visit_map`. /// `Visitor::visit_map`.
pub fn end(mut self) -> Result<(), E> { pub fn end(self) -> Result<(), E> {
let mut remaining = 0; let remaining = self.iter.count();
while self.iter.next().is_some() {
remaining += 1;
}
if remaining == 0 { if remaining == 0 {
Ok(()) Ok(())
} else { } else {
+32 -29
View File
@@ -79,7 +79,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here. // Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.36")] #![doc(html_root_url = "https://docs.rs/serde/1.0.41")]
// Support using Serde without the standard library! // Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and // Unstable functionality only if the user asks for it. For tracking and
@@ -90,10 +90,13 @@
#![cfg_attr(feature = "alloc", feature(alloc))] #![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints // Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", #![cfg_attr(
allow(cast_lossless, const_static_lifetime, doc_markdown, linkedlist, feature = "cargo-clippy",
needless_pass_by_value, redundant_field_names, type_complexity, allow(
unreadable_literal, zero_prefixed_literal))] cast_lossless, const_static_lifetime, doc_markdown, linkedlist, needless_pass_by_value,
redundant_field_names, type_complexity, unreadable_literal, zero_prefixed_literal
)
)]
// Whitelisted clippy_pedantic lints // Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow( #![cfg_attr(feature = "cargo-clippy", allow(
// integer and float ser/de requires these sorts of casts // integer and float ser/de requires these sorts of casts
@@ -135,16 +138,16 @@ extern crate core;
/// module. /// module.
mod lib { mod lib {
mod core { mod core {
#[cfg(feature = "std")]
pub use std::*;
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
pub use core::*; pub use core::*;
#[cfg(feature = "std")]
pub use std::*;
} }
pub use self::core::{cmp, iter, mem, ops, slice, str}; pub use self::core::{cmp, iter, mem, ops, slice, str};
pub use self::core::{isize, i16, i32, i64, i8};
pub use self::core::{usize, u16, u32, u64, u8};
pub use self::core::{f32, f64}; pub use self::core::{f32, f64};
pub use self::core::{i16, i32, i64, i8, isize};
pub use self::core::{u16, u32, u64, u8, usize};
pub use self::core::cell::{Cell, RefCell}; pub use self::core::cell::{Cell, RefCell};
pub use self::core::clone::{self, Clone}; pub use self::core::clone::{self, Clone};
@@ -155,40 +158,40 @@ mod lib {
pub use self::core::option::{self, Option}; pub use self::core::option::{self, Option};
pub use self::core::result::{self, Result}; pub use self::core::result::{self, Result};
#[cfg(feature = "std")]
pub use std::borrow::{Cow, ToOwned};
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::borrow::{Cow, ToOwned}; pub use alloc::borrow::{Cow, ToOwned};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::string::String; pub use std::borrow::{Cow, ToOwned};
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::string::{String, ToString}; pub use alloc::string::{String, ToString};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::vec::Vec; pub use std::string::String;
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::vec::Vec; pub use alloc::vec::Vec;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::boxed::Box; pub use std::vec::Vec;
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::boxed::Box; pub use alloc::boxed::Box;
#[cfg(feature = "std")]
pub use std::boxed::Box;
#[cfg(all(feature = "rc", feature = "std"))]
pub use std::rc::Rc;
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
pub use alloc::rc::Rc; pub use alloc::rc::Rc;
#[cfg(all(feature = "rc", feature = "std"))] #[cfg(all(feature = "rc", feature = "std"))]
pub use std::sync::Arc; pub use std::rc::Rc;
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
pub use alloc::arc::Arc; pub use alloc::arc::Arc;
#[cfg(all(feature = "rc", feature = "std"))]
pub use std::sync::Arc;
#[cfg(feature = "std")]
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; pub use alloc::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(feature = "std")]
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::{error, net}; pub use std::{error, net};
@@ -206,16 +209,16 @@ mod lib {
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::path::{Path, PathBuf}; pub use std::path::{Path, PathBuf};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::time::{Duration, SystemTime, UNIX_EPOCH};
#[cfg(feature = "std")]
pub use std::sync::{Mutex, RwLock}; pub use std::sync::{Mutex, RwLock};
#[cfg(feature = "std")]
pub use std::time::{Duration, SystemTime, UNIX_EPOCH};
#[cfg(feature = "unstable")] #[cfg(feature = "unstable")]
#[allow(deprecated)] #[allow(deprecated)]
pub use core::nonzero::{NonZero, Zeroable}; pub use core::nonzero::{NonZero, Zeroable};
#[cfg(feature = "unstable")] #[cfg(feature = "unstable")]
pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize}; pub use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -223,13 +226,13 @@ mod lib {
#[macro_use] #[macro_use]
mod macros; mod macros;
pub mod ser;
pub mod de; pub mod de;
pub mod ser;
#[doc(inline)]
pub use ser::{Serialize, Serializer};
#[doc(inline)] #[doc(inline)]
pub use de::{Deserialize, Deserializer}; pub use de::{Deserialize, Deserializer};
#[doc(inline)]
pub use ser::{Serialize, Serializer};
// Generated code uses these to support no_std. Not public API. // Generated code uses these to support no_std. Not public API.
#[doc(hidden)] #[doc(hidden)]
+627 -90
View File
@@ -11,13 +11,13 @@ use lib::*;
use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor}; use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use de::{Unexpected, MapAccess}; use de::{MapAccess, Unexpected};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub use self::content::{Content, ContentDeserializer, ContentRefDeserializer, pub use self::content::{Content, ContentDeserializer, ContentRefDeserializer, EnumDeserializer,
InternallyTaggedUnitVisitor, TagContentOtherField, InternallyTaggedUnitVisitor, TagContentOtherField,
TagContentOtherFieldVisitor, TagOrContentField, TagOrContentFieldVisitor, TagContentOtherFieldVisitor, TagOrContentField, TagOrContentFieldVisitor,
TaggedContentVisitor, UntaggedUnitVisitor, EnumDeserializer}; TaggedContentVisitor, UntaggedUnitVisitor};
/// If the missing field is of type `Option<T>` then treat is as `None`, /// If the missing field is of type `Option<T>` then treat is as `None`,
/// otherwise it is an error. /// otherwise it is an error.
@@ -228,9 +228,9 @@ mod content {
use lib::*; use lib::*;
use de::{self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, MapAccess, SeqAccess,
Unexpected, Visitor};
use super::size_hint; use super::size_hint;
use de::{self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, MapAccess,
SeqAccess, Unexpected, Visitor};
/// Used from generated code to buffer the contents of the Deserializer when /// Used from generated code to buffer the contents of the Deserializer when
/// deserializing untagged enums and internally tagged enums. /// deserializing untagged enums and internally tagged enums.
@@ -1013,6 +1013,62 @@ mod content {
err: PhantomData<E>, err: PhantomData<E>,
} }
impl<'de, E> ContentDeserializer<'de, E>
where
E: de::Error,
{
#[cold]
fn invalid_type(self, exp: &Expected) -> E {
de::Error::invalid_type(self.content.unexpected(), exp)
}
fn deserialize_integer<V>(self, visitor: V) -> Result<V::Value, E>
where
V: Visitor<'de>,
{
match self.content {
Content::U8(v) => visitor.visit_u8(v),
Content::U16(v) => visitor.visit_u16(v),
Content::U32(v) => visitor.visit_u32(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I8(v) => visitor.visit_i8(v),
Content::I16(v) => visitor.visit_i16(v),
Content::I32(v) => visitor.visit_i32(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
}
}
fn visit_content_seq<'de, V, E>(content: Vec<Content<'de>>, visitor: V) -> Result<V::Value, E>
where
V: Visitor<'de>,
E: de::Error,
{
let seq = content.into_iter().map(ContentDeserializer::new);
let mut seq_visitor = de::value::SeqDeserializer::new(seq);
let value = try!(visitor.visit_seq(&mut seq_visitor));
try!(seq_visitor.end());
Ok(value)
}
fn visit_content_map<'de, V, E>(
content: Vec<(Content<'de>, Content<'de>)>,
visitor: V,
) -> Result<V::Value, E>
where
V: Visitor<'de>,
E: de::Error,
{
let map = content
.into_iter()
.map(|(k, v)| (ContentDeserializer::new(k), ContentDeserializer::new(v)));
let mut map_visitor = de::value::MapDeserializer::new(map);
let value = try!(visitor.visit_map(&mut map_visitor));
try!(map_visitor.end());
Ok(value)
}
/// Used when deserializing an internally tagged enum because the content will /// Used when deserializing an internally tagged enum because the content will
/// be used exactly once. /// be used exactly once.
impl<'de, E> Deserializer<'de> for ContentDeserializer<'de, E> impl<'de, E> Deserializer<'de> for ContentDeserializer<'de, E>
@@ -1046,21 +1102,152 @@ mod content {
Content::None => visitor.visit_none(), Content::None => visitor.visit_none(),
Content::Some(v) => visitor.visit_some(ContentDeserializer::new(*v)), Content::Some(v) => visitor.visit_some(ContentDeserializer::new(*v)),
Content::Newtype(v) => visitor.visit_newtype_struct(ContentDeserializer::new(*v)), Content::Newtype(v) => visitor.visit_newtype_struct(ContentDeserializer::new(*v)),
Content::Seq(v) => { Content::Seq(v) => visit_content_seq(v, visitor),
let seq = v.into_iter().map(ContentDeserializer::new); Content::Map(v) => visit_content_map(v, visitor),
let mut seq_visitor = de::value::SeqDeserializer::new(seq); }
let value = try!(visitor.visit_seq(&mut seq_visitor)); }
try!(seq_visitor.end());
Ok(value) fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
} where
Content::Map(v) => { V: Visitor<'de>,
let map = v.into_iter() {
.map(|(k, v)| (ContentDeserializer::new(k), ContentDeserializer::new(v))); match self.content {
let mut map_visitor = de::value::MapDeserializer::new(map); Content::Bool(v) => visitor.visit_bool(v),
let value = try!(visitor.visit_map(&mut map_visitor)); _ => Err(self.invalid_type(&visitor)),
try!(map_visitor.end()); }
Ok(value) }
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::F32(v) => visitor.visit_f32(v),
Content::F64(v) => visitor.visit_f64(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::F64(v) => visitor.visit_f64(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::Char(v) => visitor.visit_char(v),
Content::String(v) => visitor.visit_string(v),
Content::Str(v) => visitor.visit_borrowed_str(v),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_string(visitor)
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::String(v) => visitor.visit_string(v),
Content::Str(v) => visitor.visit_borrowed_str(v),
Content::ByteBuf(v) => visitor.visit_byte_buf(v),
Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_byte_buf(visitor)
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::String(v) => visitor.visit_string(v),
Content::Str(v) => visitor.visit_borrowed_str(v),
Content::ByteBuf(v) => visitor.visit_byte_buf(v),
Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
Content::Seq(v) => visit_content_seq(v, visitor),
_ => Err(self.invalid_type(&visitor)),
} }
} }
@@ -1076,6 +1263,44 @@ mod content {
} }
} }
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::Unit => visitor.visit_unit(),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
// As a special case, allow deserializing untagged newtype
// variant containing unit struct.
//
// #[derive(Deserialize)]
// struct Info;
//
// #[derive(Deserialize)]
// #[serde(tag = "topic")]
// enum Message {
// Info(Info),
// }
//
// We want {"topic":"Info"} to deserialize even though
// ordinarily unit structs do not deserialize from empty map.
Content::Map(ref v) if v.is_empty() => visitor.visit_unit(),
_ => self.deserialize_any(visitor),
}
}
fn deserialize_newtype_struct<V>( fn deserialize_newtype_struct<V>(
self, self,
_name: &str, _name: &str,
@@ -1087,6 +1312,61 @@ mod content {
visitor.visit_newtype_struct(self) visitor.visit_newtype_struct(self)
} }
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::Seq(v) => visit_content_seq(v, visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
_len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::Map(v) => visit_content_map(v, visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::Seq(v) => visit_content_seq(v, visitor),
Content::Map(v) => visit_content_map(v, visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_enum<V>( fn deserialize_enum<V>(
self, self,
_name: &str, _name: &str,
@@ -1129,38 +1409,23 @@ mod content {
visitor.visit_enum(EnumDeserializer::new(variant, value)) visitor.visit_enum(EnumDeserializer::new(variant, value))
} }
fn deserialize_unit_struct<V>( fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.content { match self.content {
// As a special case, allow deserializing untagged newtype Content::String(v) => visitor.visit_string(v),
// variant containing unit struct. Content::Str(v) => visitor.visit_borrowed_str(v),
// _ => Err(self.invalid_type(&visitor)),
// #[derive(Deserialize)]
// struct Info;
//
// #[derive(Deserialize)]
// #[serde(tag = "topic")]
// enum Message {
// Info(Info),
// }
//
// We want {"topic":"Info"} to deserialize even though
// ordinarily unit structs do not deserialize from empty map.
Content::Map(ref v) if v.is_empty() => visitor.visit_unit(),
_ => self.deserialize_any(visitor),
} }
} }
forward_to_deserialize_any! { fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes where
byte_buf unit seq tuple tuple_struct map struct identifier V: Visitor<'de>,
ignored_any {
drop(self);
visitor.visit_unit()
} }
} }
@@ -1184,7 +1449,8 @@ mod content {
} }
impl<'de, E> EnumDeserializer<'de, E> impl<'de, E> EnumDeserializer<'de, E>
where E: de::Error where
E: de::Error,
{ {
pub fn new(variant: Content<'de>, value: Option<Content<'de>>) -> EnumDeserializer<'de, E> { pub fn new(variant: Content<'de>, value: Option<Content<'de>>) -> EnumDeserializer<'de, E> {
EnumDeserializer { EnumDeserializer {
@@ -1451,6 +1717,68 @@ mod content {
err: PhantomData<E>, err: PhantomData<E>,
} }
impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
#[cold]
fn invalid_type(self, exp: &Expected) -> E {
de::Error::invalid_type(self.content.unexpected(), exp)
}
fn deserialize_integer<V>(self, visitor: V) -> Result<V::Value, E>
where
V: Visitor<'de>,
{
match *self.content {
Content::U8(v) => visitor.visit_u8(v),
Content::U16(v) => visitor.visit_u16(v),
Content::U32(v) => visitor.visit_u32(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I8(v) => visitor.visit_i8(v),
Content::I16(v) => visitor.visit_i16(v),
Content::I32(v) => visitor.visit_i32(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
}
}
fn visit_content_seq_ref<'a, 'de, V, E>(
content: &'a [Content<'de>],
visitor: V,
) -> Result<V::Value, E>
where
V: Visitor<'de>,
E: de::Error,
{
let seq = content.into_iter().map(ContentRefDeserializer::new);
let mut seq_visitor = de::value::SeqDeserializer::new(seq);
let value = try!(visitor.visit_seq(&mut seq_visitor));
try!(seq_visitor.end());
Ok(value)
}
fn visit_content_map_ref<'a, 'de, V, E>(
content: &'a [(Content<'de>, Content<'de>)],
visitor: V,
) -> Result<V::Value, E>
where
V: Visitor<'de>,
E: de::Error,
{
let map = content.into_iter().map(|&(ref k, ref v)| {
(
ContentRefDeserializer::new(k),
ContentRefDeserializer::new(v),
)
});
let mut map_visitor = de::value::MapDeserializer::new(map);
let value = try!(visitor.visit_map(&mut map_visitor));
try!(map_visitor.end());
Ok(value)
}
/// Used when deserializing an untagged enum because the content may need to be /// Used when deserializing an untagged enum because the content may need to be
/// used more than once. /// used more than once.
impl<'de, 'a, E> Deserializer<'de> for ContentRefDeserializer<'a, 'de, E> impl<'de, 'a, E> Deserializer<'de> for ContentRefDeserializer<'a, 'de, E>
@@ -1486,28 +1814,155 @@ mod content {
Content::Newtype(ref v) => { Content::Newtype(ref v) => {
visitor.visit_newtype_struct(ContentRefDeserializer::new(v)) visitor.visit_newtype_struct(ContentRefDeserializer::new(v))
} }
Content::Seq(ref v) => { Content::Seq(ref v) => visit_content_seq_ref(v, visitor),
let seq = v.into_iter().map(ContentRefDeserializer::new); Content::Map(ref v) => visit_content_map_ref(v, visitor),
let mut seq_visitor = de::value::SeqDeserializer::new(seq);
let value = try!(visitor.visit_seq(&mut seq_visitor));
try!(seq_visitor.end());
Ok(value)
}
Content::Map(ref v) => {
let map = v.into_iter().map(|&(ref k, ref v)| {
(
ContentRefDeserializer::new(k),
ContentRefDeserializer::new(v),
)
});
let mut map_visitor = de::value::MapDeserializer::new(map);
let value = try!(visitor.visit_map(&mut map_visitor));
try!(map_visitor.end());
Ok(value)
}
} }
} }
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.content {
Content::Bool(v) => visitor.visit_bool(v),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_integer(visitor)
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.content {
Content::F32(v) => visitor.visit_f32(v),
Content::F64(v) => visitor.visit_f64(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.content {
Content::F64(v) => visitor.visit_f64(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.content {
Content::Char(v) => visitor.visit_char(v),
Content::String(ref v) => visitor.visit_str(v),
Content::Str(v) => visitor.visit_borrowed_str(v),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.content {
Content::String(ref v) => visitor.visit_str(v),
Content::Str(v) => visitor.visit_borrowed_str(v),
Content::ByteBuf(ref v) => visitor.visit_bytes(v),
Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.content {
Content::String(ref v) => visitor.visit_str(v),
Content::Str(v) => visitor.visit_borrowed_str(v),
Content::ByteBuf(ref v) => visitor.visit_bytes(v),
Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
Content::Seq(ref v) => visit_content_seq_ref(v, visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_bytes(visitor)
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, E> fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, E>
where where
V: Visitor<'de>, V: Visitor<'de>,
@@ -1520,6 +1975,27 @@ mod content {
} }
} }
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.content {
Content::Unit => visitor.visit_unit(),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, E> fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, E>
where where
V: Visitor<'de>, V: Visitor<'de>,
@@ -1527,6 +2003,61 @@ mod content {
visitor.visit_newtype_struct(self) visitor.visit_newtype_struct(self)
} }
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.content {
Content::Seq(ref v) => visit_content_seq_ref(v, visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
_len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.content {
Content::Map(ref v) => visit_content_map_ref(v, visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match *self.content {
Content::Seq(ref v) => visit_content_seq_ref(v, visitor),
Content::Map(ref v) => visit_content_map_ref(v, visitor),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_enum<V>( fn deserialize_enum<V>(
self, self,
_name: &str, _name: &str,
@@ -1573,10 +2104,22 @@ mod content {
}) })
} }
forward_to_deserialize_any! { fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes where
byte_buf unit unit_struct seq tuple tuple_struct map struct V: Visitor<'de>,
identifier ignored_any {
match *self.content {
Content::String(ref v) => visitor.visit_str(v),
Content::Str(v) => visitor.visit_borrowed_str(v),
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
} }
} }
@@ -2082,12 +2625,13 @@ where
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapDeserializer<'a, 'de: 'a, E>( pub struct FlatMapDeserializer<'a, 'de: 'a, E>(
pub &'a mut Vec<Option<(Content<'de>, Content<'de>)>>, pub &'a mut Vec<Option<(Content<'de>, Content<'de>)>>,
pub PhantomData<E> pub PhantomData<E>,
); );
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E> impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
where E: Error where
E: Error,
{ {
type Error = E; type Error = E;
@@ -2102,7 +2646,7 @@ impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
self, self,
name: &'static str, name: &'static str,
variants: &'static [&'static str], variants: &'static [&'static str],
visitor: V visitor: V,
) -> Result<V::Value, Self::Error> ) -> Result<V::Value, Self::Error>
where where
V: Visitor<'de>, V: Visitor<'de>,
@@ -2113,15 +2657,12 @@ impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
// about. // about.
let use_item = match *item { let use_item = match *item {
None => false, None => false,
Some((ref c, _)) => c.as_str().map_or(false, |x| variants.contains(&x)) Some((ref c, _)) => c.as_str().map_or(false, |x| variants.contains(&x)),
}; };
if use_item { if use_item {
let (key, value) = item.take().unwrap(); let (key, value) = item.take().unwrap();
return visitor.visit_enum(EnumDeserializer::new( return visitor.visit_enum(EnumDeserializer::new(key, Some(value)));
key,
Some(value)
));
} }
} }
@@ -2142,7 +2683,7 @@ impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
self, self,
_: &'static str, _: &'static str,
fields: &'static [&'static str], fields: &'static [&'static str],
visitor: V visitor: V,
) -> Result<V::Value, Self::Error> ) -> Result<V::Value, Self::Error>
where where
V: Visitor<'de>, V: Visitor<'de>,
@@ -2150,11 +2691,7 @@ impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
visitor.visit_map(FlatMapAccess::new(self.0.iter_mut(), Some(fields))) visitor.visit_map(FlatMapAccess::new(self.0.iter_mut(), Some(fields)))
} }
fn deserialize_newtype_struct<V>( fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
self,
_name: &str,
visitor: V,
) -> Result<V::Value, Self::Error>
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
@@ -2180,7 +2717,7 @@ pub struct FlatMapAccess<'a, 'de: 'a, E> {
impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> { impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> {
fn new( fn new(
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
fields: Option<&'static [&'static str]> fields: Option<&'static [&'static str]>,
) -> FlatMapAccess<'a, 'de, E> { ) -> FlatMapAccess<'a, 'de, E> {
FlatMapAccess { FlatMapAccess {
iter: iter, iter: iter,
@@ -2193,7 +2730,8 @@ impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> {
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E> impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
where E: Error where
E: Error,
{ {
type Error = E; type Error = E;
@@ -2208,13 +2746,12 @@ impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
let use_item = match *item { let use_item = match *item {
None => false, None => false,
Some((ref c, _)) => { Some((ref c, _)) => {
c.as_str().map_or(self.fields.is_none(), |key| { c.as_str()
match self.fields { .map_or(self.fields.is_none(), |key| match self.fields {
None => true, None => true,
Some(fields) if fields.contains(&key) => true, Some(fields) if fields.contains(&key) => true,
_ => false _ => false,
} })
})
} }
}; };
+1 -1
View File
@@ -8,5 +8,5 @@
mod macros; mod macros;
pub mod ser;
pub mod de; pub mod de;
pub mod ser;
+35 -17
View File
@@ -11,12 +11,8 @@ use lib::*;
use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer}; use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use self::content::{ use self::content::{Content, ContentSerializer, SerializeStructVariantAsMapValue,
SerializeStructVariantAsMapValue, SerializeTupleVariantAsMapValue};
SerializeTupleVariantAsMapValue,
ContentSerializer,
Content,
};
/// Used to check that serde(getter) attributes return the expected type. /// Used to check that serde(getter) attributes return the expected type.
/// Not public API. /// Not public API.
@@ -1042,16 +1038,20 @@ pub struct FlatMapSerializer<'a, M: 'a>(pub &'a mut M);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> FlatMapSerializer<'a, M> impl<'a, M> FlatMapSerializer<'a, M>
where where
M: SerializeMap + 'a M: SerializeMap + 'a,
{ {
fn bad_type(self, what: Unsupported) -> M::Error { fn bad_type(self, what: Unsupported) -> M::Error {
ser::Error::custom(format_args!("can only flatten structs and maps (got {})", what)) ser::Error::custom(format_args!(
"can only flatten structs and maps (got {})",
what
))
} }
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> Serializer for FlatMapSerializer<'a, M> impl<'a, M> Serializer for FlatMapSerializer<'a, M>
where M: SerializeMap + 'a where
M: SerializeMap + 'a,
{ {
type Ok = (); type Ok = ();
type Error = M::Error; type Error = M::Error;
@@ -1219,7 +1219,10 @@ impl<'a, M> Serializer for FlatMapSerializer<'a, M>
_: usize, _: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> { ) -> Result<Self::SerializeStructVariant, Self::Error> {
try!(self.0.serialize_key(inner_variant)); try!(self.0.serialize_key(inner_variant));
Ok(FlatMapSerializeStructVariantAsMapValue::new(self.0, inner_variant)) Ok(FlatMapSerializeStructVariantAsMapValue::new(
self.0,
inner_variant,
))
} }
} }
@@ -1228,7 +1231,8 @@ pub struct FlatMapSerializeMap<'a, M: 'a>(&'a mut M);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> ser::SerializeMap for FlatMapSerializeMap<'a, M> impl<'a, M> ser::SerializeMap for FlatMapSerializeMap<'a, M>
where M: SerializeMap + 'a where
M: SerializeMap + 'a,
{ {
type Ok = (); type Ok = ();
type Error = M::Error; type Error = M::Error;
@@ -1257,12 +1261,17 @@ pub struct FlatMapSerializeStruct<'a, M: 'a>(&'a mut M);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> ser::SerializeStruct for FlatMapSerializeStruct<'a, M> impl<'a, M> ser::SerializeStruct for FlatMapSerializeStruct<'a, M>
where M: SerializeMap + 'a where
M: SerializeMap + 'a,
{ {
type Ok = (); type Ok = ();
type Error = M::Error; type Error = M::Error;
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> fn serialize_field<T: ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Self::Error>
where where
T: Serialize, T: Serialize,
{ {
@@ -1283,7 +1292,8 @@ pub struct FlatMapSerializeStructVariantAsMapValue<'a, M: 'a> {
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> FlatMapSerializeStructVariantAsMapValue<'a, M> impl<'a, M> FlatMapSerializeStructVariantAsMapValue<'a, M>
where M: SerializeMap + 'a where
M: SerializeMap + 'a,
{ {
fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> { fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> {
FlatMapSerializeStructVariantAsMapValue { FlatMapSerializeStructVariantAsMapValue {
@@ -1296,12 +1306,17 @@ impl<'a, M> FlatMapSerializeStructVariantAsMapValue<'a, M>
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> ser::SerializeStructVariant for FlatMapSerializeStructVariantAsMapValue<'a, M> impl<'a, M> ser::SerializeStructVariant for FlatMapSerializeStructVariantAsMapValue<'a, M>
where M: SerializeMap + 'a where
M: SerializeMap + 'a,
{ {
type Ok = (); type Ok = ();
type Error = M::Error; type Error = M::Error;
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> fn serialize_field<T: ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Self::Error>
where where
T: Serialize, T: Serialize,
{ {
@@ -1311,7 +1326,10 @@ impl<'a, M> ser::SerializeStructVariant for FlatMapSerializeStructVariantAsMapVa
} }
fn end(self) -> Result<(), Self::Error> { fn end(self) -> Result<(), Self::Error> {
try!(self.map.serialize_value(&Content::Struct(self.name, self.fields))); try!(
self.map
.serialize_value(&Content::Struct(self.name, self.fields))
);
Ok(()) Ok(())
} }
} }
+30 -8
View File
@@ -320,8 +320,12 @@ map_impl!(HashMap<K: Eq + Hash, V, H: BuildHasher>);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
macro_rules! deref_impl { macro_rules! deref_impl {
($($desc:tt)+) => { (
impl $($desc)+ { $(#[doc = $doc:tt])*
<$($desc:tt)+
) => {
$(#[doc = $doc])*
impl <$($desc)+ {
#[inline] #[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@@ -340,10 +344,30 @@ deref_impl!(<'a, T: ?Sized> Serialize for &'a mut T where T: Serialize);
deref_impl!(<T: ?Sized> Serialize for Box<T> where T: Serialize); deref_impl!(<T: ?Sized> Serialize for Box<T> where T: Serialize);
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
deref_impl!(<T: ?Sized> Serialize for Rc<T> where T: Serialize); deref_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde.
///
/// Serializing a data structure containing `Rc` will serialize a copy of
/// the contents of the `Rc` each time the `Rc` is referenced within the
/// data structure. Serialization will not attempt to deduplicate these
/// repeated data.
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
<T: ?Sized> Serialize for Rc<T> where T: Serialize
}
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
deref_impl!(<T: ?Sized> Serialize for Arc<T> where T: Serialize); deref_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde.
///
/// Serializing a data structure containing `Arc` will serialize a copy of
/// the contents of the `Arc` each time the `Arc` is referenced within the
/// data structure. Serialization will not attempt to deduplicate these
/// repeated data.
///
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
<T: ?Sized> Serialize for Arc<T> where T: Serialize
}
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned); deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned);
@@ -521,11 +545,9 @@ macro_rules! serialize_display_bounded_length {
// write! only provides fmt::Formatter to Display implementations, which // write! only provides fmt::Formatter to Display implementations, which
// has methods write_str and write_char but no method to write arbitrary // has methods write_str and write_char but no method to write arbitrary
// bytes. Therefore `written` must be valid UTF-8. // bytes. Therefore `written` must be valid UTF-8.
let written_str = unsafe { let written_str = unsafe { str::from_utf8_unchecked(written) };
str::from_utf8_unchecked(written)
};
$serializer.serialize_str(written_str) $serializer.serialize_str(written_str)
}} }};
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
+5 -5
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.36" # remember to update html_root_url version = "1.0.41" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -23,10 +23,10 @@ name = "serde_derive"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
proc-macro2 = "0.2" proc-macro2 = "0.3"
quote = "0.4" quote = "0.5"
serde_derive_internals = { version = "=0.22.2", default-features = false, path = "../serde_derive_internals" } serde_derive_internals = { version = "=0.23.1", default-features = false, path = "../serde_derive_internals" }
syn = { version = "0.12", features = ["visit"] } syn = { version = "0.13", features = ["visit"] }
[dev-dependencies] [dev-dependencies]
serde = { version = "1.0", path = "../serde" } serde = { version = "1.0", path = "../serde" }
+119 -151
View File
@@ -8,13 +8,14 @@
use std::collections::HashSet; use std::collections::HashSet;
use syn::{self, visit}; use syn;
use syn::punctuated::Punctuated; use syn::punctuated::{Pair, Punctuated};
use syn::visit::{self, Visit};
use internals::ast::{Data, Container}; use internals::ast::{Container, Data};
use internals::attr; use internals::attr;
use proc_macro2::{Span, Term}; use proc_macro2::Span;
// Remove the default from every type parameter because in the generated impls // Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not // they look like associated types: "error: associated type bindings are not
@@ -25,13 +26,11 @@ pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
.params .params
.iter() .iter()
.map(|param| match *param { .map(|param| match *param {
syn::GenericParam::Type(ref param) => { syn::GenericParam::Type(ref param) => syn::GenericParam::Type(syn::TypeParam {
syn::GenericParam::Type(syn::TypeParam { eq_token: None,
eq_token: None, default: None,
default: None, ..param.clone()
..param.clone() }),
})
}
_ => param.clone(), _ => param.clone(),
}) })
.collect(), .collect(),
@@ -44,45 +43,25 @@ pub fn with_where_predicates(
predicates: &[syn::WherePredicate], predicates: &[syn::WherePredicate],
) -> syn::Generics { ) -> syn::Generics {
let mut generics = generics.clone(); let mut generics = generics.clone();
if generics.where_clause.is_none() { generics
generics.where_clause = Some(syn::WhereClause { .make_where_clause()
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates .predicates
.extend(predicates.into_iter().cloned()); .extend(predicates.into_iter().cloned());
generics generics
} }
pub fn with_where_predicates_from_fields<F>( pub fn with_where_predicates_from_fields(
cont: &Container, cont: &Container,
generics: &syn::Generics, generics: &syn::Generics,
from_field: F, from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
) -> syn::Generics ) -> syn::Generics {
where
F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
{
let predicates = cont.data let predicates = cont.data
.all_fields() .all_fields()
.flat_map(|field| from_field(&field.attrs)) .flat_map(|field| from_field(&field.attrs))
.flat_map(|predicates| predicates.to_vec()); .flat_map(|predicates| predicates.to_vec());
let mut generics = generics.clone(); let mut generics = generics.clone();
if generics.where_clause.is_none() { generics.make_where_clause().predicates.extend(predicates);
generics.where_clause = Some(syn::WhereClause {
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates
.extend(predicates);
generics generics
} }
@@ -97,26 +76,39 @@ where
// #[serde(skip_serializing)] // #[serde(skip_serializing)]
// c: C, // c: C,
// } // }
pub fn with_bound<F>( pub fn with_bound(
cont: &Container, cont: &Container,
generics: &syn::Generics, generics: &syn::Generics,
filter: F, filter: fn(&attr::Field, Option<&attr::Variant>) -> bool,
bound: &syn::Path, bound: &syn::Path,
) -> syn::Generics ) -> syn::Generics {
where struct FindTyParams<'ast> {
F: Fn(&attr::Field, Option<&attr::Variant>) -> bool,
{
struct FindTyParams {
// Set of all generic type parameters on the current struct (A, B, C in // Set of all generic type parameters on the current struct (A, B, C in
// the example). Initialized up front. // the example). Initialized up front.
all_ty_params: HashSet<syn::Ident>, all_type_params: HashSet<syn::Ident>,
// Set of generic type parameters used in fields for which filter // Set of generic type parameters used in fields for which filter
// returns true (A and B in the example). Filled in as the visitor sees // returns true (A and B in the example). Filled in as the visitor sees
// them. // them.
relevant_ty_params: HashSet<syn::Ident>, relevant_type_params: HashSet<syn::Ident>,
// Fields whose type is an associated type of one of the generic type
// parameters.
associated_type_usage: Vec<&'ast syn::TypePath>,
} }
impl<'ast> visit::Visit<'ast> for FindTyParams { impl<'ast> Visit<'ast> for FindTyParams<'ast> {
fn visit_path(&mut self, path: &syn::Path) { fn visit_field(&mut self, field: &'ast syn::Field) {
if let syn::Type::Path(ref ty) = field.ty {
if let Some(Pair::Punctuated(ref t, _)) = ty.path.segments.first() {
if self.all_type_params.contains(&t.ident) {
self.associated_type_usage.push(ty);
}
}
}
self.visit_type(&field.ty);
}
fn visit_path(&mut self, path: &'ast syn::Path) {
if let Some(seg) = path.segments.last() { if let Some(seg) = path.segments.last() {
if seg.into_value().ident == "PhantomData" { if seg.into_value().ident == "PhantomData" {
// Hardcoded exception, because PhantomData<T> implements // Hardcoded exception, because PhantomData<T> implements
@@ -126,8 +118,8 @@ where
} }
if path.leading_colon.is_none() && path.segments.len() == 1 { if path.leading_colon.is_none() && path.segments.len() == 1 {
let id = path.segments[0].ident; let id = path.segments[0].ident;
if self.all_ty_params.contains(&id) { if self.all_type_params.contains(&id) {
self.relevant_ty_params.insert(id); self.relevant_type_params.insert(id);
} }
} }
visit::visit_path(self, path); visit::visit_path(self, path);
@@ -139,21 +131,15 @@ where
// mac: T!(), // mac: T!(),
// marker: PhantomData<T>, // marker: PhantomData<T>,
// } // }
fn visit_macro(&mut self, _mac: &syn::Macro) {} fn visit_macro(&mut self, _mac: &'ast syn::Macro) {}
} }
let all_ty_params: HashSet<_> = generics let all_type_params = generics.type_params().map(|param| param.ident).collect();
.params
.iter()
.filter_map(|param| match *param {
syn::GenericParam::Type(ref param) => Some(param.ident),
_ => None,
})
.collect();
let mut visitor = FindTyParams { let mut visitor = FindTyParams {
all_ty_params: all_ty_params, all_type_params: all_type_params,
relevant_ty_params: HashSet::new(), relevant_type_params: HashSet::new(),
associated_type_usage: Vec::new(),
}; };
match cont.data { match cont.data {
Data::Enum(ref variants) => for variant in variants.iter() { Data::Enum(ref variants) => for variant in variants.iter() {
@@ -162,54 +148,47 @@ where
.iter() .iter()
.filter(|field| filter(&field.attrs, Some(&variant.attrs))); .filter(|field| filter(&field.attrs, Some(&variant.attrs)));
for field in relevant_fields { for field in relevant_fields {
visit::visit_type(&mut visitor, field.ty); visitor.visit_field(field.original);
} }
}, },
Data::Struct(_, ref fields) => { Data::Struct(_, ref fields) => {
for field in fields.iter().filter(|field| filter(&field.attrs, None)) { for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
visit::visit_type(&mut visitor, field.ty); visitor.visit_field(field.original);
} }
} }
} }
let relevant_type_params = visitor.relevant_type_params;
let associated_type_usage = visitor.associated_type_usage;
let new_predicates = generics let new_predicates = generics
.params .type_params()
.iter() .map(|param| param.ident)
.filter_map(|param| match *param { .filter(|id| relevant_type_params.contains(id))
syn::GenericParam::Type(ref param) => Some(param.ident), .map(|id| syn::TypePath {
_ => None, qself: None,
path: id.into(),
}) })
.filter(|id| visitor.relevant_ty_params.contains(id)) .chain(associated_type_usage.into_iter().cloned())
.map(|id| { .map(|bounded_ty| {
syn::WherePredicate::Type(syn::PredicateType { syn::WherePredicate::Type(syn::PredicateType {
lifetimes: None, lifetimes: None,
// the type parameter that is being bounded e.g. T // the type parameter that is being bounded e.g. T
bounded_ty: syn::Type::Path(syn::TypePath { bounded_ty: syn::Type::Path(bounded_ty),
qself: None,
path: id.into(),
}),
colon_token: Default::default(), colon_token: Default::default(),
// the bound e.g. Serialize // the bound e.g. Serialize
bounds: vec![ bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
syn::TypeParamBound::Trait(syn::TraitBound { paren_token: None,
modifier: syn::TraitBoundModifier::None, modifier: syn::TraitBoundModifier::None,
lifetimes: None, lifetimes: None,
path: bound.clone(), path: bound.clone(),
}), })].into_iter()
].into_iter().collect(), .collect(),
}) })
}); });
let mut generics = generics.clone(); let mut generics = generics.clone();
if generics.where_clause.is_none() { generics
generics.where_clause = Some(syn::WhereClause { .make_where_clause()
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates .predicates
.extend(new_predicates); .extend(new_predicates);
generics generics
@@ -221,15 +200,8 @@ pub fn with_self_bound(
bound: &syn::Path, bound: &syn::Path,
) -> syn::Generics { ) -> syn::Generics {
let mut generics = generics.clone(); let mut generics = generics.clone();
if generics.where_clause.is_none() { generics
generics.where_clause = Some(syn::WhereClause { .make_where_clause()
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates .predicates
.push(syn::WherePredicate::Type(syn::PredicateType { .push(syn::WherePredicate::Type(syn::PredicateType {
lifetimes: None, lifetimes: None,
@@ -237,19 +209,19 @@ pub fn with_self_bound(
bounded_ty: type_of_item(cont), bounded_ty: type_of_item(cont),
colon_token: Default::default(), colon_token: Default::default(),
// the bound e.g. Default // the bound e.g. Default
bounds: vec![ bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
syn::TypeParamBound::Trait(syn::TraitBound { paren_token: None,
modifier: syn::TraitBoundModifier::None, modifier: syn::TraitBoundModifier::None,
lifetimes: None, lifetimes: None,
path: bound.clone(), path: bound.clone(),
}), })].into_iter()
].into_iter().collect(), .collect(),
})); }));
generics generics
} }
pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics { pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
let bound = syn::Lifetime::new(Term::intern(lifetime), Span::def_site()); let bound = syn::Lifetime::new(lifetime, Span::call_site());
let def = syn::LifetimeDef { let def = syn::LifetimeDef {
attrs: Vec::new(), attrs: Vec::new(),
lifetime: bound, lifetime: bound,
@@ -259,21 +231,18 @@ pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Gen
let params = Some(syn::GenericParam::Lifetime(def)) let params = Some(syn::GenericParam::Lifetime(def))
.into_iter() .into_iter()
.chain(generics.params .chain(generics.params.iter().cloned().map(|mut param| {
.iter() match param {
.cloned() syn::GenericParam::Lifetime(ref mut param) => {
.map(|mut param| { param.bounds.push(bound);
match param {
syn::GenericParam::Lifetime(ref mut param) => {
param.bounds.push(bound);
}
syn::GenericParam::Type(ref mut param) => {
param.bounds.push(syn::TypeParamBound::Lifetime(bound));
}
syn::GenericParam::Const(_) => {}
} }
param syn::GenericParam::Type(ref mut param) => {
})) param.bounds.push(syn::TypeParamBound::Lifetime(bound));
}
syn::GenericParam::Const(_) => {}
}
param
}))
.collect(); .collect();
syn::Generics { syn::Generics {
@@ -287,36 +256,35 @@ fn type_of_item(cont: &Container) -> syn::Type {
qself: None, qself: None,
path: syn::Path { path: syn::Path {
leading_colon: None, leading_colon: None,
segments: vec![ segments: vec![syn::PathSegment {
syn::PathSegment { ident: cont.ident,
ident: cont.ident, arguments: syn::PathArguments::AngleBracketed(
arguments: syn::PathArguments::AngleBracketed( syn::AngleBracketedGenericArguments {
syn::AngleBracketedGenericArguments { colon2_token: None,
colon2_token: None, lt_token: Default::default(),
lt_token: Default::default(), args: cont.generics
args: cont.generics .params
.params .iter()
.iter() .map(|param| match *param {
.map(|param| match *param { syn::GenericParam::Type(ref param) => {
syn::GenericParam::Type(ref param) => { syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
syn::GenericArgument::Type(syn::Type::Path(syn::TypePath { qself: None,
qself: None, path: param.ident.into(),
path: param.ident.into(), }))
})) }
} syn::GenericParam::Lifetime(ref param) => {
syn::GenericParam::Lifetime(ref param) => { syn::GenericArgument::Lifetime(param.lifetime)
syn::GenericArgument::Lifetime(param.lifetime) }
} syn::GenericParam::Const(_) => {
syn::GenericParam::Const(_) => { panic!("Serde does not support const generics yet");
panic!("Serde does not support const generics yet"); }
} })
}) .collect(),
.collect(), gt_token: Default::default(),
gt_token: Default::default(), },
}, ),
), }].into_iter()
}, .collect(),
].into_iter().collect(),
}, },
}) })
} }
+168 -156
View File
@@ -6,15 +6,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use syn::{self, Ident, Index, Member}; use proc_macro2::{Literal, Span};
use quote::{ToTokens, Tokens};
use syn::punctuated::Punctuated; use syn::punctuated::Punctuated;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use quote::{ToTokens, Tokens}; use syn::{self, Ident, Index, Member};
use proc_macro2::{Literal, Span, Term};
use bound; use bound;
use fragment::{Expr, Fragment, Match, Stmts}; use fragment::{Expr, Fragment, Match, Stmts};
use internals::ast::{Data, Container, Field, Style, Variant}; use internals::ast::{Container, Data, Field, Style, Variant};
use internals::{self, attr}; use internals::{self, attr};
use std::collections::BTreeSet; use std::collections::BTreeSet;
@@ -27,7 +27,10 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
let ident = &cont.ident; let ident = &cont.ident;
let params = Parameters::new(&cont); let params = Parameters::new(&cont);
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(&params); let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(&params);
let dummy_const = Ident::new(&format!("_IMPL_DESERIALIZE_FOR_{}", ident), Span::def_site()); let dummy_const = Ident::new(
&format!("_IMPL_DESERIALIZE_FOR_{}", ident),
Span::call_site(),
);
let body = Stmts(deserialize_body(&cont, &params)); let body = Stmts(deserialize_body(&cont, &params));
let delife = params.borrowed.de_lifetime(); let delife = params.borrowed.de_lifetime();
@@ -181,8 +184,8 @@ enum BorrowedLifetimes {
impl BorrowedLifetimes { impl BorrowedLifetimes {
fn de_lifetime(&self) -> syn::Lifetime { fn de_lifetime(&self) -> syn::Lifetime {
match *self { match *self {
BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new(Term::intern("'de"), Span::def_site()), BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new("'de", Span::call_site()),
BorrowedLifetimes::Static => syn::Lifetime::new(Term::intern("'static"), Span::def_site()), BorrowedLifetimes::Static => syn::Lifetime::new("'static", Span::call_site()),
} }
} }
@@ -190,7 +193,7 @@ impl BorrowedLifetimes {
match *self { match *self {
BorrowedLifetimes::Borrowed(ref bounds) => Some(syn::LifetimeDef { BorrowedLifetimes::Borrowed(ref bounds) => Some(syn::LifetimeDef {
attrs: Vec::new(), attrs: Vec::new(),
lifetime: syn::Lifetime::new(Term::intern("'de"), Span::def_site()), lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None, colon_token: None,
bounds: bounds.iter().cloned().collect(), bounds: bounds.iter().cloned().collect(),
}), }),
@@ -268,7 +271,8 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<St
let code = match cont.data { let code = match cont.data {
Data::Struct(Style::Struct, ref fields) => { Data::Struct(Style::Struct, ref fields) => {
if let Some(code) = deserialize_struct_in_place(None, params, fields, &cont.attrs, None) { if let Some(code) = deserialize_struct_in_place(None, params, fields, &cont.attrs, None)
{
code code
} else { } else {
return None; return None;
@@ -321,8 +325,8 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
impl<'de> _serde::de::Visitor<'de> for __Visitor { impl<'de> _serde::de::Visitor<'de> for __Visitor {
type Value = #this; type Value = #this;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
_serde::export::Formatter::write_str(formatter, #expecting) _serde::export::Formatter::write_str(__formatter, #expecting)
} }
#[inline] #[inline]
@@ -415,8 +419,8 @@ fn deserialize_tuple(
impl #de_impl_generics _serde::de::Visitor<#delife> 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; type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
_serde::export::Formatter::write_str(formatter, #expecting) _serde::export::Formatter::write_str(__formatter, #expecting)
} }
#visit_newtype_struct #visit_newtype_struct
@@ -503,8 +507,8 @@ fn deserialize_tuple_in_place(
impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause {
type Value = (); type Value = ();
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
_serde::export::Formatter::write_str(formatter, #expecting) _serde::export::Formatter::write_str(__formatter, #expecting)
} }
#visit_newtype_struct #visit_newtype_struct
@@ -549,8 +553,9 @@ fn deserialize_seq(
let visit = match field.attrs.deserialize_with() { let visit = match field.attrs.deserialize_with() {
None => { None => {
let field_ty = &field.ty; let field_ty = &field.ty;
let span = Span::def_site().located_at(field.original.span()); let span = field.original.span();
let func = quote_spanned!(span=> _serde::de::SeqAccess::next_element::<#field_ty>); let func =
quote_spanned!(span=> _serde::de::SeqAccess::next_element::<#field_ty>);
quote!(try!(#func(&mut __seq))) quote!(try!(#func(&mut __seq)))
} }
Some(path) => { Some(path) => {
@@ -637,13 +642,12 @@ fn deserialize_seq_in_place(
.enumerate() .enumerate()
.map(|(field_index, (_, field))| { .map(|(field_index, (_, field))| {
// If there's no field name, assume we're a tuple-struct and use a numeric index // If there's no field name, assume we're a tuple-struct and use a numeric index
let field_name = field let field_name = field.ident.map(Member::Named).unwrap_or_else(|| {
.ident Member::Unnamed(Index {
.map(Member::Named)
.unwrap_or_else(|| Member::Unnamed(Index {
index: field_index as u32, index: field_index as u32,
span: Span::call_site(), span: Span::call_site(),
})); })
});
let dot = quote_spanned!(Span::call_site()=> .); let dot = quote_spanned!(Span::call_site()=> .);
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
@@ -871,8 +875,8 @@ fn deserialize_struct(
impl #de_impl_generics _serde::de::Visitor<#delife> 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; type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
_serde::export::Formatter::write_str(formatter, #expecting) _serde::export::Formatter::write_str(__formatter, #expecting)
} }
#visit_seq #visit_seq
@@ -919,8 +923,8 @@ fn deserialize_struct_in_place(
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs)); let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs));
let (field_visitor, fields_stmt, visit_map) = deserialize_struct_as_struct_in_place_visitor( let (field_visitor, fields_stmt, visit_map) =
params, fields, cattrs); deserialize_struct_as_struct_in_place_visitor(params, fields, cattrs);
let field_visitor = Stmts(field_visitor); let field_visitor = Stmts(field_visitor);
let fields_stmt = Stmts(fields_stmt); let fields_stmt = Stmts(fields_stmt);
@@ -978,8 +982,8 @@ fn deserialize_struct_in_place(
impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause {
type Value = (); type Value = ();
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
_serde::export::Formatter::write_str(formatter, #expecting) _serde::export::Formatter::write_str(__formatter, #expecting)
} }
#visit_seq #visit_seq
@@ -1059,9 +1063,7 @@ fn deserialize_externally_tagged_enum(
let variant_name = field_i(i); let variant_name = field_i(i);
let block = Match(deserialize_externally_tagged_variant( let block = Match(deserialize_externally_tagged_variant(
params, params, variant, cattrs,
variant,
cattrs,
)); ));
quote! { quote! {
@@ -1102,8 +1104,8 @@ fn deserialize_externally_tagged_enum(
impl #de_impl_generics _serde::de::Visitor<#delife> 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; type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
_serde::export::Formatter::write_str(formatter, #expecting) _serde::export::Formatter::write_str(__formatter, #expecting)
} }
fn visit_enum<__A>(self, __data: __A) -> _serde::export::Result<Self::Value, __A::Error> fn visit_enum<__A>(self, __data: __A) -> _serde::export::Result<Self::Value, __A::Error>
@@ -1161,9 +1163,9 @@ fn deserialize_internally_tagged_enum(
params, params,
variant, variant,
cattrs, cattrs,
quote!( quote! {
_serde::private::de::ContentDeserializer::<__D::Error>::new(__tagged.content) _serde::private::de::ContentDeserializer::<__D::Error>::new(__tagged.content)
), },
)); ));
quote! { quote! {
@@ -1373,8 +1375,8 @@ fn deserialize_adjacently_tagged_enum(
impl #de_impl_generics _serde::de::Visitor<#delife> 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; type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
_serde::export::Formatter::write_str(formatter, #expecting) _serde::export::Formatter::write_str(__formatter, #expecting)
} }
fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error> fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error>
@@ -1525,8 +1527,7 @@ fn deserialize_externally_tagged_variant(
cattrs: &attr::Container, cattrs: &attr::Container,
) -> Fragment { ) -> Fragment {
if let Some(path) = variant.attrs.deserialize_with() { if let Some(path) = variant.attrs.deserialize_with() {
let (wrapper, wrapper_ty, unwrap_fn) = let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path);
wrap_deserialize_variant_with(params, variant, path);
return quote_block! { return quote_block! {
#wrapper #wrapper
_serde::export::Result::map( _serde::export::Result::map(
@@ -1608,8 +1609,7 @@ fn deserialize_untagged_variant(
deserializer: Tokens, deserializer: Tokens,
) -> Fragment { ) -> Fragment {
if let Some(path) = variant.attrs.deserialize_with() { if let Some(path) = variant.attrs.deserialize_with() {
let (wrapper, wrapper_ty, unwrap_fn) = let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path);
wrap_deserialize_variant_with(params, variant, path);
return quote_block! { return quote_block! {
#wrapper #wrapper
_serde::export::Result::map( _serde::export::Result::map(
@@ -1715,7 +1715,7 @@ fn deserialize_untagged_newtype_variant(
fn deserialize_generated_identifier( fn deserialize_generated_identifier(
fields: &[(String, Ident)], fields: &[(String, Ident)],
cattrs: &attr::Container, cattrs: &attr::Container,
is_variant: bool is_variant: bool,
) -> Fragment { ) -> Fragment {
let this = quote!(__Field); let this = quote!(__Field);
let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident)| ident).collect(); let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident)| ident).collect();
@@ -1810,12 +1810,7 @@ fn deserialize_custom_identifier(
let names_idents: Vec<_> = ordinary let names_idents: Vec<_> = ordinary
.iter() .iter()
.map(|variant| { .map(|variant| (variant.attrs.name().deserialize_name(), variant.ident))
(
variant.attrs.name().deserialize_name(),
variant.ident,
)
})
.collect(); .collect();
let names = names_idents.iter().map(|&(ref name, _)| name); let names = names_idents.iter().map(|&(ref name, _)| name);
@@ -1872,12 +1867,16 @@ fn deserialize_identifier(
fields: &[(String, Ident)], fields: &[(String, Ident)],
is_variant: bool, is_variant: bool,
fallthrough: Option<Tokens>, fallthrough: Option<Tokens>,
collect_other_fields: bool collect_other_fields: bool,
) -> Fragment { ) -> Fragment {
let field_strs = fields.iter().map(|&(ref name, _)| name); let field_strs = fields.iter().map(|&(ref name, _)| name);
let field_borrowed_strs = fields.iter().map(|&(ref name, _)| name); let field_borrowed_strs = fields.iter().map(|&(ref name, _)| name);
let field_bytes = fields.iter().map(|&(ref name, _)| Literal::byte_string(name.as_bytes())); let field_bytes = fields
let field_borrowed_bytes = fields.iter().map(|&(ref name, _)| Literal::byte_string(name.as_bytes())); .iter()
.map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
let field_borrowed_bytes = fields
.iter()
.map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
let constructors: &Vec<_> = &fields let constructors: &Vec<_> = &fields
.iter() .iter()
@@ -1892,10 +1891,54 @@ fn deserialize_identifier(
let index_expecting = if is_variant { "variant" } else { "field" }; let index_expecting = if is_variant { "variant" } else { "field" };
let bytes_to_str = if fallthrough.is_some() || collect_other_fields {
None
} else {
Some(quote! {
let __value = &_serde::export::from_utf8_lossy(__value);
})
};
let (
value_as_str_content,
value_as_borrowed_str_content,
value_as_bytes_content,
value_as_borrowed_bytes_content,
) = if !collect_other_fields {
(None, None, None, None)
} else {
(
Some(quote! {
let __value = _serde::private::de::Content::String(__value.to_string());
}),
Some(quote! {
let __value = _serde::private::de::Content::Str(__value);
}),
Some(quote! {
let __value = _serde::private::de::Content::ByteBuf(__value.to_vec());
}),
Some(quote! {
let __value = _serde::private::de::Content::Bytes(__value);
}),
)
};
let fallthrough_arm = if let Some(fallthrough) = fallthrough {
fallthrough
} else if is_variant {
quote! {
_serde::export::Err(_serde::de::Error::unknown_variant(__value, VARIANTS))
}
} else {
quote! {
_serde::export::Err(_serde::de::Error::unknown_field(__value, FIELDS))
}
};
let variant_indices = 0u64..; let variant_indices = 0u64..;
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len()); let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
let visit_other = if collect_other_fields { let visit_other = if collect_other_fields {
Some(quote! { quote! {
fn visit_bool<__E>(self, __value: bool) -> Result<Self::Value, __E> fn visit_bool<__E>(self, __value: bool) -> Result<Self::Value, __E>
where __E: _serde::de::Error where __E: _serde::de::Error
{ {
@@ -1973,9 +2016,38 @@ fn deserialize_identifier(
{ {
Ok(__Field::__other(_serde::private::de::Content::Unit)) Ok(__Field::__other(_serde::private::de::Content::Unit))
} }
})
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::export::Result<Self::Value, __E>
where __E: _serde::de::Error
{
match __value {
#(
#field_borrowed_strs => _serde::export::Ok(#constructors),
)*
_ => {
#value_as_borrowed_str_content
#fallthrough_arm
}
}
}
fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::export::Result<Self::Value, __E>
where __E: _serde::de::Error
{
match __value {
#(
#field_borrowed_bytes => _serde::export::Ok(#constructors),
)*
_ => {
#bytes_to_str
#value_as_borrowed_bytes_content
#fallthrough_arm
}
}
}
}
} else { } else {
Some(quote! { quote! {
fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E> fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
where __E: _serde::de::Error where __E: _serde::de::Error
{ {
@@ -1988,52 +2060,12 @@ fn deserialize_identifier(
&#fallthrough_msg)) &#fallthrough_msg))
} }
} }
})
};
let bytes_to_str = if fallthrough.is_some() || collect_other_fields {
None
} else {
Some(quote! {
let __value = &_serde::export::from_utf8_lossy(__value);
})
};
let (value_as_str_content, value_as_borrowed_str_content,
value_as_bytes_content, value_as_borrowed_bytes_content) = if !collect_other_fields {
(None, None, None, None)
} else {
(
Some(quote! {
let __value = _serde::private::de::Content::String(__value.to_string());
}),
Some(quote! {
let __value = _serde::private::de::Content::Str(__value);
}),
Some(quote! {
let __value = _serde::private::de::Content::ByteBuf(__value.to_vec());
}),
Some(quote! {
let __value = _serde::private::de::Content::Bytes(__value);
})
)
};
let fallthrough_arm = if let Some(fallthrough) = fallthrough {
fallthrough
} else if is_variant {
quote! {
_serde::export::Err(_serde::de::Error::unknown_variant(__value, VARIANTS))
}
} else {
quote! {
_serde::export::Err(_serde::de::Error::unknown_field(__value, FIELDS))
} }
}; };
quote_block! { quote_block! {
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
_serde::export::Formatter::write_str(formatter, #expecting) _serde::export::Formatter::write_str(__formatter, #expecting)
} }
#visit_other #visit_other
@@ -2052,35 +2084,6 @@ fn deserialize_identifier(
} }
} }
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::export::Result<Self::Value, __E>
where __E: _serde::de::Error
{
match __value {
#(
#field_borrowed_strs => _serde::export::Ok(#constructors),
)*
_ => {
#value_as_borrowed_str_content
#fallthrough_arm
}
}
}
fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::export::Result<Self::Value, __E>
where __E: _serde::de::Error
{
match __value {
#(
#field_borrowed_bytes => _serde::export::Ok(#constructors),
)*
_ => {
#bytes_to_str
#value_as_borrowed_bytes_content
#fallthrough_arm
}
}
}
fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::export::Result<Self::Value, __E> fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::export::Result<Self::Value, __E>
where __E: _serde::de::Error where __E: _serde::de::Error
{ {
@@ -2193,8 +2196,9 @@ fn deserialize_map(
let visit = match field.attrs.deserialize_with() { let visit = match field.attrs.deserialize_with() {
None => { None => {
let field_ty = &field.ty; let field_ty = &field.ty;
let span = Span::def_site().located_at(field.original.span()); let span = field.original.span();
let func = quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>); let func =
quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>);
quote! { quote! {
try!(#func(&mut __map)) try!(#func(&mut __map))
} }
@@ -2473,7 +2477,12 @@ fn deserialize_map_in_place(
// If missing_expr unconditionally returns an error, don't try // If missing_expr unconditionally returns an error, don't try
// to assign its value to self.place. Maybe this could be handled // to assign its value to self.place. Maybe this could be handled
// more elegantly. // more elegantly.
if missing_expr.as_ref().into_tokens().to_string().starts_with("return ") { if missing_expr
.as_ref()
.into_tokens()
.to_string()
.starts_with("return ")
{
let missing_expr = Stmts(missing_expr); let missing_expr = Stmts(missing_expr);
quote! { quote! {
if !#name { if !#name {
@@ -2522,7 +2531,7 @@ fn deserialize_map_in_place(
} }
fn field_i(i: usize) -> Ident { fn field_i(i: usize) -> Ident {
Ident::new(&format!("__field{}", i), Span::def_site()) Ident::new(&format!("__field{}", i), Span::call_site())
} }
/// This function wraps the expression in `#[serde(deserialize_with = "...")]` /// This function wraps the expression in `#[serde(deserialize_with = "...")]`
@@ -2582,35 +2591,37 @@ fn wrap_deserialize_variant_with(
let (wrapper, wrapper_ty) = let (wrapper, wrapper_ty) =
wrap_deserialize_with(params, &quote!((#(#field_tys),*)), deserialize_with); wrap_deserialize_with(params, &quote!((#(#field_tys),*)), deserialize_with);
let field_access = (0..variant.fields.len()).map(|n| Member::Unnamed(Index { let field_access = (0..variant.fields.len()).map(|n| {
index: n as u32, Member::Unnamed(Index {
span: Span::call_site(), index: n as u32,
})); span: Span::call_site(),
})
});
let unwrap_fn = match variant.style { let unwrap_fn = match variant.style {
Style::Struct if variant.fields.len() == 1 => {
let field_ident = variant.fields[0].ident.unwrap();
quote! {
|__wrap| #this::#variant_ident { #field_ident: __wrap.value }
}
}
Style::Struct => { Style::Struct => {
let field_idents = variant let field_idents = variant
.fields .fields
.iter() .iter()
.map(|field| field.ident.as_ref().unwrap()); .map(|field| field.ident.as_ref().unwrap());
quote!({ quote! {
|__wrap| { |__wrap| #this::#variant_ident { #(#field_idents: __wrap.value.#field_access),* }
#this::#variant_ident { #(#field_idents: __wrap.value.#field_access),* } }
}
})
} }
Style::Tuple => quote!({ Style::Tuple => quote! {
|__wrap| { |__wrap| #this::#variant_ident(#(__wrap.value.#field_access),*)
#this::#variant_ident(#(__wrap.value.#field_access),*) },
} Style::Newtype => quote! {
}), |__wrap| #this::#variant_ident(__wrap.value)
Style::Newtype => quote!({ },
|__wrap| { Style::Unit => quote! {
#this::#variant_ident(__wrap.value) |__wrap| #this::#variant_ident
} },
}),
Style::Unit => quote!({
|__wrap| { #this::#variant_ident }
}),
}; };
(wrapper, wrapper_ty, unwrap_fn) (wrapper, wrapper_ty, unwrap_fn)
@@ -2638,7 +2649,7 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
let name = field.attrs.name().deserialize_name(); let name = field.attrs.name().deserialize_name();
match field.attrs.deserialize_with() { match field.attrs.deserialize_with() {
None => { None => {
let span = Span::def_site().located_at(field.original.span()); let span = field.original.span();
let func = quote_spanned!(span=> _serde::private::de::missing_field); let func = quote_spanned!(span=> _serde::private::de::missing_field);
quote_expr! { quote_expr! {
try!(#func(#name)) try!(#func(#name))
@@ -2683,7 +2694,8 @@ impl<'a> ToTokens for InPlaceImplGenerics<'a> {
param.bounds.push(place_lifetime.lifetime); param.bounds.push(place_lifetime.lifetime);
} }
syn::GenericParam::Type(ref mut param) => { syn::GenericParam::Type(ref mut param) => {
param.bounds param
.bounds
.push(syn::TypeParamBound::Lifetime(place_lifetime.lifetime)); .push(syn::TypeParamBound::Lifetime(place_lifetime.lifetime));
} }
syn::GenericParam::Const(_) => {} syn::GenericParam::Const(_) => {}
@@ -2721,7 +2733,7 @@ impl<'a> ToTokens for DeTypeGenerics<'a> {
if self.0.borrowed.de_lifetime_def().is_some() { if self.0.borrowed.de_lifetime_def().is_some() {
let def = syn::LifetimeDef { let def = syn::LifetimeDef {
attrs: Vec::new(), attrs: Vec::new(),
lifetime: syn::Lifetime::new(Term::intern("'de"), Span::def_site()), lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None, colon_token: None,
bounds: Punctuated::new(), bounds: Punctuated::new(),
}; };
@@ -2747,7 +2759,7 @@ impl<'a> ToTokens for InPlaceTypeGenerics<'a> {
if self.0.borrowed.de_lifetime_def().is_some() { if self.0.borrowed.de_lifetime_def().is_some() {
let def = syn::LifetimeDef { let def = syn::LifetimeDef {
attrs: Vec::new(), attrs: Vec::new(),
lifetime: syn::Lifetime::new(Term::intern("'de"), Span::def_site()), lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None, colon_token: None,
bounds: Punctuated::new(), bounds: Punctuated::new(),
}; };
@@ -2772,7 +2784,7 @@ impl<'a> DeTypeGenerics<'a> {
fn place_lifetime() -> syn::LifetimeDef { fn place_lifetime() -> syn::LifetimeDef {
syn::LifetimeDef { syn::LifetimeDef {
attrs: Vec::new(), attrs: Vec::new(),
lifetime: syn::Lifetime::new(Term::intern("'place"), Span::def_site()), lifetime: syn::Lifetime::new("'place", Span::call_site()),
colon_token: None, colon_token: None,
bounds: Punctuated::new(), bounds: Punctuated::new(),
} }
+14 -4
View File
@@ -22,9 +22,11 @@
//! //!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html //! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.36")] #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.41")]
#![cfg_attr(feature = "cargo-clippy", allow(enum_variant_names, redundant_field_names, #![cfg_attr(
too_many_arguments, used_underscore_binding))] feature = "cargo-clippy",
allow(enum_variant_names, redundant_field_names, too_many_arguments, used_underscore_binding)
)]
// The `quote!` macro requires deep recursion. // The `quote!` macro requires deep recursion.
#![recursion_limit = "512"] #![recursion_limit = "512"]
@@ -41,13 +43,21 @@ extern crate proc_macro2;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use syn::DeriveInput; use syn::DeriveInput;
// Quote's default is def_site but it appears call_site is likely to stabilize
// before def_site. Thus we try to use only call_site.
macro_rules! quote {
($($tt:tt)*) => {
quote_spanned!($crate::proc_macro2::Span::call_site()=> $($tt)*)
}
}
#[macro_use] #[macro_use]
mod bound; mod bound;
#[macro_use] #[macro_use]
mod fragment; mod fragment;
mod ser;
mod de; mod de;
mod ser;
#[proc_macro_derive(Serialize, attributes(serde))] #[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream { pub fn derive_serialize(input: TokenStream) -> TokenStream {
+65 -63
View File
@@ -6,14 +6,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use syn::{self, Ident, Index, Member};
use syn::spanned::Spanned;
use quote::Tokens;
use proc_macro2::Span; use proc_macro2::Span;
use quote::Tokens;
use syn::spanned::Spanned;
use syn::{self, Ident, Index, Member};
use bound; use bound;
use fragment::{Fragment, Match, Stmts}; use fragment::{Fragment, Match, Stmts};
use internals::ast::{Data, Container, Field, Style, Variant}; use internals::ast::{Container, Data, Field, Style, Variant};
use internals::{attr, Ctxt}; use internals::{attr, Ctxt};
use std::u32; use std::u32;
@@ -27,7 +27,7 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, Strin
let ident = &cont.ident; let ident = &cont.ident;
let params = Parameters::new(&cont); let params = Parameters::new(&cont);
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
let dummy_const = Ident::new(&format!("_IMPL_SERIALIZE_FOR_{}", ident), Span::def_site()); let dummy_const = Ident::new(&format!("_IMPL_SERIALIZE_FOR_{}", ident), Span::call_site());
let body = Stmts(serialize_body(&cont, &params)); let body = Stmts(serialize_body(&cont, &params));
let impl_block = if let Some(remote) = cont.attrs.remote() { let impl_block = if let Some(remote) = cont.attrs.remote() {
@@ -98,9 +98,9 @@ impl Parameters {
fn new(cont: &Container) -> Self { fn new(cont: &Container) -> Self {
let is_remote = cont.attrs.remote().is_some(); let is_remote = cont.attrs.remote().is_some();
let self_var = if is_remote { let self_var = if is_remote {
Ident::new("__self", Span::def_site()) Ident::new("__self", Span::call_site())
} else { } else {
Ident::new("self", Span::def_site()) Ident::new("self", Span::call_site())
}; };
let this = match cont.attrs.remote() { let this = match cont.attrs.remote() {
@@ -204,15 +204,19 @@ fn serialize_newtype_struct(
) -> Fragment { ) -> Fragment {
let type_name = cattrs.name().serialize_name(); let type_name = cattrs.name().serialize_name();
let mut field_expr = get_member(params, field, &Member::Unnamed(Index { let mut field_expr = get_member(
index: 0, params,
span: Span::call_site(), field,
})); &Member::Unnamed(Index {
index: 0,
span: Span::call_site(),
}),
);
if let Some(path) = field.attrs.serialize_with() { if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
} }
let span = Span::def_site().located_at(field.original.span()); let span = field.original.span();
let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_struct); let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_struct);
quote_expr! { quote_expr! {
#func(__serializer, #type_name, #field_expr) #func(__serializer, #type_name, #field_expr)
@@ -224,12 +228,8 @@ fn serialize_tuple_struct(
fields: &[Field], fields: &[Field],
cattrs: &attr::Container, cattrs: &attr::Container,
) -> Fragment { ) -> Fragment {
let serialize_stmts = serialize_tuple_struct_visitor( let serialize_stmts =
fields, serialize_tuple_struct_visitor(fields, params, false, &TupleTrait::SerializeTupleStruct);
params,
false,
&TupleTrait::SerializeTupleStruct,
);
let type_name = cattrs.name().serialize_name(); let type_name = cattrs.name().serialize_name();
let len = serialize_stmts.len(); let len = serialize_stmts.len();
@@ -252,13 +252,13 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
} }
} }
fn serialize_struct_as_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment { fn serialize_struct_as_struct(
let serialize_fields = serialize_struct_visitor( params: &Parameters,
fields, fields: &[Field],
params, cattrs: &attr::Container,
false, ) -> Fragment {
&StructTrait::SerializeStruct, let serialize_fields =
); serialize_struct_visitor(fields, params, false, &StructTrait::SerializeStruct);
let type_name = cattrs.name().serialize_name(); let type_name = cattrs.name().serialize_name();
@@ -287,13 +287,13 @@ fn serialize_struct_as_struct(params: &Parameters, fields: &[Field], cattrs: &at
} }
} }
fn serialize_struct_as_map(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment { fn serialize_struct_as_map(
let serialize_fields = serialize_struct_visitor( params: &Parameters,
fields, fields: &[Field],
params, cattrs: &attr::Container,
false, ) -> Fragment {
&StructTrait::SerializeMap, let serialize_fields =
); serialize_struct_visitor(fields, params, false, &StructTrait::SerializeMap);
let mut serialized_fields = fields let mut serialized_fields = fields
.iter() .iter()
@@ -385,8 +385,8 @@ fn serialize_variant(
} }
} }
Style::Tuple => { Style::Tuple => {
let field_names = let field_names = (0..variant.fields.len())
(0..variant.fields.len()).map(|i| Ident::new(&format!("__field{}", i), Span::def_site())); .map(|i| Ident::new(&format!("__field{}", i), Span::call_site()));
quote! { quote! {
#this::#variant_ident(#(ref #field_names),*) #this::#variant_ident(#(ref #field_names),*)
} }
@@ -619,9 +619,9 @@ fn serialize_adjacently_tagged_variant(
unreachable!() unreachable!()
} }
} }
Style::Newtype => vec![Ident::new("__field0", Span::def_site())], Style::Newtype => vec![Ident::new("__field0", Span::call_site())],
Style::Tuple => (0..variant.fields.len()) Style::Tuple => (0..variant.fields.len())
.map(|i| Ident::new(&format!("__field{}", i), Span::def_site())) .map(|i| Ident::new(&format!("__field{}", i), Span::call_site()))
.collect(), .collect(),
Style::Struct => variant Style::Struct => variant
.fields .fields
@@ -776,12 +776,10 @@ fn serialize_struct_variant<'a>(
name: &str, name: &str,
) -> Fragment { ) -> Fragment {
let struct_trait = match context { let struct_trait = match context {
StructVariant::ExternallyTagged { .. } => ( StructVariant::ExternallyTagged { .. } => (StructTrait::SerializeStructVariant),
StructTrait::SerializeStructVariant StructVariant::InternallyTagged { .. } | StructVariant::Untagged => {
), (StructTrait::SerializeStruct)
StructVariant::InternallyTagged { .. } | StructVariant::Untagged => ( }
StructTrait::SerializeStruct
),
}; };
let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait); let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait);
@@ -862,13 +860,17 @@ fn serialize_tuple_struct_visitor(
.enumerate() .enumerate()
.map(|(i, field)| { .map(|(i, field)| {
let mut field_expr = if is_enum { let mut field_expr = if is_enum {
let id = Ident::new(&format!("__field{}", i), Span::def_site()); let id = Ident::new(&format!("__field{}", i), Span::call_site());
quote!(#id) quote!(#id)
} else { } else {
get_member(params, field, &Member::Unnamed(Index { get_member(
index: i as u32, params,
span: Span::call_site(), field,
})) &Member::Unnamed(Index {
index: i as u32,
span: Span::call_site(),
}),
)
}; };
let skip = field let skip = field
@@ -880,7 +882,7 @@ fn serialize_tuple_struct_visitor(
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
} }
let span = Span::def_site().located_at(field.original.span()); let span = field.original.span();
let func = tuple_trait.serialize_element(span); let func = tuple_trait.serialize_element(span);
let ser = quote! { let ser = quote! {
try!(#func(&mut __serde_state, #field_expr)); try!(#func(&mut __serde_state, #field_expr));
@@ -923,7 +925,7 @@ fn serialize_struct_visitor(
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
} }
let span = Span::def_site().located_at(field.original.span()); let span = field.original.span();
let ser = if field.attrs.flatten() { let ser = if field.attrs.flatten() {
quote! { quote! {
try!(_serde::Serialize::serialize(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state))); try!(_serde::Serialize::serialize(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state)));
@@ -981,7 +983,7 @@ fn wrap_serialize_variant_with(
.map(|(i, field)| { .map(|(i, field)| {
let id = field let id = field
.ident .ident
.unwrap_or_else(|| Ident::new(&format!("__field{}", i), Span::def_site())); .unwrap_or_else(|| Ident::new(&format!("__field{}", i), Span::call_site()));
quote!(#id) quote!(#id)
}) })
.collect(); .collect();
@@ -1009,10 +1011,12 @@ fn wrap_serialize_with(
}; };
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
let field_access = (0..field_exprs.len()).map(|n| Member::Unnamed(Index { let field_access = (0..field_exprs.len()).map(|n| {
index: n as u32, Member::Unnamed(Index {
span: Span::call_site(), index: n as u32,
})); span: Span::call_site(),
})
});
quote!({ quote!({
struct __SerializeWith #wrapper_impl_generics #where_clause { struct __SerializeWith #wrapper_impl_generics #where_clause {
@@ -1052,9 +1056,7 @@ fn mut_if(is_mut: bool) -> Option<Tokens> {
fn get_member(params: &Parameters, field: &Field, member: &Member) -> Tokens { fn get_member(params: &Parameters, field: &Field, member: &Member) -> Tokens {
let self_var = &params.self_var; let self_var = &params.self_var;
match (params.is_remote, field.attrs.getter()) { match (params.is_remote, field.attrs.getter()) {
(false, None) => { (false, None) => quote_spanned!(Span::call_site()=> &#self_var.#member),
quote_spanned!(Span::call_site()=> &#self_var.#member)
}
(true, None) => { (true, None) => {
let inner = quote_spanned!(Span::call_site()=> &#self_var.#member); let inner = quote_spanned!(Span::call_site()=> &#self_var.#member);
let ty = field.ty; let ty = field.ty;
@@ -1094,12 +1096,12 @@ impl StructTrait {
fn skip_field(&self, span: Span) -> Option<Tokens> { fn skip_field(&self, span: Span) -> Option<Tokens> {
match *self { match *self {
StructTrait::SerializeMap => None, StructTrait::SerializeMap => None,
StructTrait::SerializeStruct => Some({ StructTrait::SerializeStruct => {
quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field) Some(quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field))
}), }
StructTrait::SerializeStructVariant => Some({ StructTrait::SerializeStructVariant => {
quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field) Some(quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field))
}) }
} }
} }
} }
+3 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive_internals" name = "serde_derive_internals"
version = "0.22.2" # remember to update html_root_url version = "0.23.1" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "AST representation used by Serde derive macros. Unstable." description = "AST representation used by Serde derive macros. Unstable."
@@ -12,8 +12,8 @@ readme = "README.md"
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
[dependencies] [dependencies]
proc-macro2 = "0.2" proc-macro2 = "0.3"
syn = { version = "0.12", default-features = false, features = ["derive", "parsing", "clone-impls"] } syn = { version = "0.13", default-features = false, features = ["derive", "parsing", "clone-impls"] }
[badges] [badges]
travis-ci = { repository = "serde-rs/serde" } travis-ci = { repository = "serde-rs/serde" }
+5 -2
View File
@@ -6,11 +6,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use syn;
use attr; use attr;
use check; use check;
use Ctxt; use syn;
use syn::punctuated::Punctuated; use syn::punctuated::Punctuated;
use Ctxt;
pub struct Container<'a> { pub struct Container<'a> {
pub ident: syn::Ident, pub ident: syn::Ident,
@@ -68,6 +68,9 @@ impl<'a> Container<'a> {
Data::Enum(ref mut variants) => for variant in variants { Data::Enum(ref mut variants) => for variant in variants {
variant.attrs.rename_by_rule(attrs.rename_all()); variant.attrs.rename_by_rule(attrs.rename_all());
for field in &mut variant.fields { for field in &mut variant.fields {
if field.attrs.flatten() {
has_flatten = true;
}
field.attrs.rename_by_rule(variant.attrs.rename_all()); field.attrs.rename_by_rule(variant.attrs.rename_all());
} }
}, },
+88 -60
View File
@@ -6,16 +6,16 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use Ctxt; use proc_macro2::{Group, Span, TokenStream, TokenTree};
use std::collections::BTreeSet;
use std::str::FromStr;
use syn; use syn;
use syn::punctuated::Punctuated;
use syn::synom::{ParseError, Synom};
use syn::Ident; use syn::Ident;
use syn::Meta::{List, NameValue, Word}; use syn::Meta::{List, NameValue, Word};
use syn::NestedMeta::{Literal, Meta}; use syn::NestedMeta::{Literal, Meta};
use syn::punctuated::Punctuated; use Ctxt;
use syn::synom::{Synom, ParseError};
use std::collections::BTreeSet;
use std::str::FromStr;
use proc_macro2::{Span, TokenStream, TokenNode, TokenTree};
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints // This module handles parsing of `#[serde(...)]` attributes. The entrypoints
// are `attr::Container::from_ast`, `attr::Variant::from_ast`, and // are `attr::Container::from_ast`, `attr::Variant::from_ast`, and
@@ -234,7 +234,10 @@ impl Container {
// Parse `#[serde(default)]` // Parse `#[serde(default)]`
Meta(Word(word)) if word == "default" => match item.data { Meta(Word(word)) if word == "default" => match item.data {
syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(_), .. }) => { syn::Data::Struct(syn::DataStruct {
fields: syn::Fields::Named(_),
..
}) => {
default.set(Default::Default); default.set(Default::Default);
} }
_ => cx.error( _ => cx.error(
@@ -247,7 +250,10 @@ impl Container {
Meta(NameValue(ref m)) if m.ident == "default" => { Meta(NameValue(ref m)) if m.ident == "default" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
match item.data { match item.data {
syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(_), .. }) => { syn::Data::Struct(syn::DataStruct {
fields: syn::Fields::Named(_),
..
}) => {
default.set(Default::Path(path)); default.set(Default::Path(path));
} }
_ => cx.error( _ => cx.error(
@@ -503,13 +509,11 @@ fn decide_identifier(
} }
(&syn::Data::Enum(_), true, false) => Identifier::Field, (&syn::Data::Enum(_), true, false) => Identifier::Field,
(&syn::Data::Enum(_), false, true) => Identifier::Variant, (&syn::Data::Enum(_), false, true) => Identifier::Variant,
(&syn::Data::Struct(_), true, false) (&syn::Data::Struct(_), true, false) | (&syn::Data::Union(_), true, false) => {
| (&syn::Data::Union(_), true, false) => {
cx.error("`field_identifier` can only be used on an enum"); cx.error("`field_identifier` can only be used on an enum");
Identifier::No Identifier::No
} }
(&syn::Data::Struct(_), false, true) (&syn::Data::Struct(_), false, true) | (&syn::Data::Union(_), false, true) => {
| (&syn::Data::Union(_), false, true) => {
cx.error("`variant_identifier` can only be used on an enum"); cx.error("`variant_identifier` can only be used on an enum");
Identifier::No Identifier::No
} }
@@ -594,10 +598,16 @@ impl Variant {
Meta(NameValue(ref m)) if m.ident == "with" => { Meta(NameValue(ref m)) if m.ident == "with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
let mut ser_path = path.clone(); let mut ser_path = path.clone();
ser_path.path.segments.push(Ident::new("serialize", Span::call_site()).into()); ser_path
.path
.segments
.push(Ident::new("serialize", Span::call_site()).into());
serialize_with.set(ser_path); serialize_with.set(ser_path);
let mut de_path = path; let mut de_path = path;
de_path.path.segments.push(Ident::new("deserialize", Span::call_site()).into()); de_path
.path
.segments
.push(Ident::new("deserialize", Span::call_site()).into());
deserialize_with.set(de_path); deserialize_with.set(de_path);
} }
} }
@@ -838,10 +848,16 @@ impl Field {
Meta(NameValue(ref m)) if m.ident == "with" => { Meta(NameValue(ref m)) if m.ident == "with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, m.ident.as_ref(), &m.lit) {
let mut ser_path = path.clone(); let mut ser_path = path.clone();
ser_path.path.segments.push(Ident::new("serialize", Span::call_site()).into()); ser_path
.path
.segments
.push(Ident::new("serialize", Span::call_site()).into());
serialize_with.set(ser_path); serialize_with.set(ser_path);
let mut de_path = path; let mut de_path = path;
de_path.path.segments.push(Ident::new("deserialize", Span::call_site()).into()); de_path
.path
.segments
.push(Ident::new("deserialize", Span::call_site()).into());
deserialize_with.set(de_path); deserialize_with.set(de_path);
} }
} }
@@ -873,7 +889,9 @@ impl Field {
// Parse `#[serde(borrow = "'a + 'b")]` // Parse `#[serde(borrow = "'a + 'b")]`
Meta(NameValue(ref m)) if m.ident == "borrow" => { Meta(NameValue(ref m)) if m.ident == "borrow" => {
if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, m.ident.as_ref(), &m.lit) { if let Ok(lifetimes) =
parse_lit_into_lifetimes(cx, m.ident.as_ref(), &m.lit)
{
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) {
for lifetime in &lifetimes { for lifetime in &lifetimes {
if !borrowable.contains(lifetime) { if !borrowable.contains(lifetime) {
@@ -939,10 +957,14 @@ impl Field {
leading_colon: None, leading_colon: None,
segments: Punctuated::new(), segments: Punctuated::new(),
}; };
path.segments.push(Ident::new("_serde", Span::def_site()).into()); path.segments
path.segments.push(Ident::new("private", Span::def_site()).into()); .push(Ident::new("_serde", Span::call_site()).into());
path.segments.push(Ident::new("de", Span::def_site()).into()); path.segments
path.segments.push(Ident::new("borrow_cow_str", Span::def_site()).into()); .push(Ident::new("private", Span::call_site()).into());
path.segments
.push(Ident::new("de", Span::call_site()).into());
path.segments
.push(Ident::new("borrow_cow_str", Span::call_site()).into());
let expr = syn::ExprPath { let expr = syn::ExprPath {
attrs: Vec::new(), attrs: Vec::new(),
qself: None, qself: None,
@@ -954,10 +976,14 @@ impl Field {
leading_colon: None, leading_colon: None,
segments: Punctuated::new(), segments: Punctuated::new(),
}; };
path.segments.push(Ident::new("_serde", Span::def_site()).into()); path.segments
path.segments.push(Ident::new("private", Span::def_site()).into()); .push(Ident::new("_serde", Span::call_site()).into());
path.segments.push(Ident::new("de", Span::def_site()).into()); path.segments
path.segments.push(Ident::new("borrow_cow_bytes", Span::def_site()).into()); .push(Ident::new("private", Span::call_site()).into());
path.segments
.push(Ident::new("de", Span::call_site()).into());
path.segments
.push(Ident::new("borrow_cow_bytes", Span::call_site()).into());
let expr = syn::ExprPath { let expr = syn::ExprPath {
attrs: Vec::new(), attrs: Vec::new(),
qself: None, qself: None,
@@ -1097,7 +1123,10 @@ where
Ok((ser_meta.get(), de_meta.get())) Ok((ser_meta.get(), de_meta.get()))
} }
fn get_renames<'a>(cx: &Ctxt, items: &'a Punctuated<syn::NestedMeta, Token![,]>) -> Result<SerAndDe<&'a syn::LitStr>, ()> { fn get_renames<'a>(
cx: &Ctxt,
items: &'a Punctuated<syn::NestedMeta, Token![,]>,
) -> Result<SerAndDe<&'a syn::LitStr>, ()> {
get_ser_and_de(cx, "rename", items, get_lit_str) get_ser_and_de(cx, "rename", items, get_lit_str)
} }
@@ -1141,12 +1170,18 @@ fn get_lit_str<'a>(
fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Path, ()> { fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Path, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
parse_lit_str(string).map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value()))) parse_lit_str(string)
.map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value())))
} }
fn parse_lit_into_expr_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::ExprPath, ()> { fn parse_lit_into_expr_path(
cx: &Ctxt,
attr_name: &str,
lit: &syn::Lit,
) -> Result<syn::ExprPath, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
parse_lit_str(string).map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value()))) parse_lit_str(string)
.map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value())))
} }
fn parse_lit_into_where( fn parse_lit_into_where(
@@ -1160,7 +1195,7 @@ fn parse_lit_into_where(
return Ok(Vec::new()); return Ok(Vec::new());
} }
let where_string = syn::LitStr::new(&format!("where {}", string.value()), string.span); let where_string = syn::LitStr::new(&format!("where {}", string.value()), string.span());
parse_lit_str::<syn::WhereClause>(&where_string) parse_lit_str::<syn::WhereClause>(&where_string)
.map(|wh| wh.predicates.into_iter().collect()) .map(|wh| wh.predicates.into_iter().collect())
@@ -1173,7 +1208,8 @@ fn parse_lit_into_ty(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::
parse_lit_str(string).map_err(|_| { parse_lit_str(string).map_err(|_| {
cx.error(format!( cx.error(format!(
"failed to parse type: {} = {:?}", "failed to parse type: {} = {:?}",
attr_name, string.value() attr_name,
string.value()
)) ))
}) })
} }
@@ -1210,7 +1246,10 @@ fn parse_lit_into_lifetimes(
return Ok(set); return Ok(set);
} }
cx.error(format!("failed to parse borrowed lifetimes: {:?}", string.value())); cx.error(format!(
"failed to parse borrowed lifetimes: {:?}",
string.value()
));
Err(()) Err(())
} }
@@ -1255,14 +1294,10 @@ fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
return false; return false;
} }
}; };
seg.ident == "Cow" seg.ident == "Cow" && args.len() == 2 && match (&args[0], &args[1]) {
&& args.len() == 2 (&syn::GenericArgument::Lifetime(_), &syn::GenericArgument::Type(ref arg)) => elem(arg),
&& match (&args[0], &args[1]) { _ => false,
(&syn::GenericArgument::Lifetime(_), &syn::GenericArgument::Type(ref arg)) => { }
elem(arg)
}
_ => false,
}
} }
// Whether the type looks like it might be `&T` where elem="T". This can have // Whether the type looks like it might be `&T` where elem="T". This can have
@@ -1287,9 +1322,7 @@ fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
// } // }
fn is_rptr(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { fn is_rptr(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
match *ty { match *ty {
syn::Type::Reference(ref ty) => { syn::Type::Reference(ref ty) => ty.mutability.is_none() && elem(&ty.elem),
ty.mutability.is_none() && elem(&ty.elem)
}
_ => false, _ => false,
} }
} }
@@ -1307,17 +1340,13 @@ fn is_slice_u8(ty: &syn::Type) -> bool {
fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool { fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool {
match *ty { match *ty {
syn::Type::Path(ref ty) => { syn::Type::Path(ref ty) => ty.qself.is_none() && is_primitive_path(&ty.path, primitive),
ty.qself.is_none() && is_primitive_path(&ty.path, primitive)
}
_ => false, _ => false,
} }
} }
fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool { fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool {
path.leading_colon.is_none() path.leading_colon.is_none() && path.segments.len() == 1 && path.segments[0].ident == primitive
&& path.segments.len() == 1
&& path.segments[0].ident == primitive
&& path.segments[0].arguments.is_empty() && path.segments[0].arguments.is_empty()
} }
@@ -1410,21 +1439,20 @@ where
fn spanned_tokens(s: &syn::LitStr) -> Result<TokenStream, ParseError> { fn spanned_tokens(s: &syn::LitStr) -> Result<TokenStream, ParseError> {
let stream = try!(syn::parse_str(&s.value())); let stream = try!(syn::parse_str(&s.value()));
Ok(respan_token_stream(stream, s.span)) Ok(respan_token_stream(stream, s.span()))
} }
fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream { fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
stream.into_iter().map(|token| respan_token_tree(token, span)).collect() stream
.into_iter()
.map(|token| respan_token_tree(token, span))
.collect()
} }
fn respan_token_tree(token: TokenTree, span: Span) -> TokenTree { fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
TokenTree { if let TokenTree::Group(ref mut g) = token {
span: span, *g = Group::new(g.delimiter(), respan_token_stream(g.stream().clone(), span));
kind: match token.kind {
TokenNode::Group(delimiter, nested) => {
TokenNode::Group(delimiter, respan_token_stream(nested, span))
}
other => other,
},
} }
token.set_span(span);
token
} }
+2 -15
View File
@@ -113,14 +113,7 @@ impl FromStr for RenameRule {
fn rename_variants() { fn rename_variants() {
for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[ for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[
( (
"Outcome", "Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
"outcome",
"OUTCOME",
"outcome",
"outcome",
"OUTCOME",
"outcome",
"OUTCOME",
), ),
( (
"VeryTasty", "VeryTasty",
@@ -154,13 +147,7 @@ fn rename_variants() {
fn rename_fields() { fn rename_fields() {
for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[ for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[
( (
"outcome", "outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
"OUTCOME",
"Outcome",
"outcome",
"OUTCOME",
"outcome",
"OUTCOME",
), ),
( (
"very_tasty", "very_tasty",
+26 -18
View File
@@ -6,8 +6,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use ast::{Data, Container, Style}; use ast::{Container, Data, Style};
use attr::{Identifier, EnumTag}; use attr::{EnumTag, Identifier};
use Ctxt; use Ctxt;
/// Cross-cutting checks that require looking at more than a single attrs /// Cross-cutting checks that require looking at more than a single attrs
@@ -45,27 +45,38 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
fn check_flatten(cx: &Ctxt, cont: &Container) { fn check_flatten(cx: &Ctxt, cont: &Container) {
match cont.data { match cont.data {
Data::Enum(_) => { Data::Enum(_) => {
assert!(!cont.attrs.has_flatten()); if cont.attrs.has_flatten() {
cx.error("#[serde(flatten)] cannot be used within enums");
}
} }
Data::Struct(_, _) => { Data::Struct(style, _) => {
for field in cont.data.all_fields() { for field in cont.data.all_fields() {
if !field.attrs.flatten() { if !field.attrs.flatten() {
continue; continue;
} }
match style {
Style::Tuple => {
cx.error("#[serde(flatten)] cannot be used on tuple structs");
}
Style::Newtype => {
cx.error("#[serde(flatten)] cannot be used on newtype structs");
}
_ => {}
}
if field.attrs.skip_serializing() { if field.attrs.skip_serializing() {
cx.error( cx.error(
"#[serde(flatten] can not be combined with \ "#[serde(flatten] can not be combined with \
#[serde(skip_serializing)]" #[serde(skip_serializing)]",
); );
} else if field.attrs.skip_serializing_if().is_some() { } else if field.attrs.skip_serializing_if().is_some() {
cx.error( cx.error(
"#[serde(flatten] can not be combined with \ "#[serde(flatten] can not be combined with \
#[serde(skip_serializing_if = \"...\")]" #[serde(skip_serializing_if = \"...\")]",
); );
} else if field.attrs.skip_deserializing() { } else if field.attrs.skip_deserializing() {
cx.error( cx.error(
"#[serde(flatten] can not be combined with \ "#[serde(flatten] can not be combined with \
#[serde(skip_deserializing)]" #[serde(skip_deserializing)]",
); );
} }
} }
@@ -209,10 +220,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
/// the same as either one of its fields, as this would result in /// the same as either one of its fields, as this would result in
/// duplicate keys in the serialized output and/or ambiguity in /// duplicate keys in the serialized output and/or ambiguity in
/// the to-be-deserialized input. /// the to-be-deserialized input.
fn check_internal_tag_field_name_conflict( fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
cx: &Ctxt,
cont: &Container,
) {
let variants = match cont.data { let variants = match cont.data {
Data::Enum(ref variants) => variants, Data::Enum(ref variants) => variants,
Data::Struct(_, _) => return, Data::Struct(_, _) => return,
@@ -224,10 +232,7 @@ fn check_internal_tag_field_name_conflict(
}; };
let diagnose_conflict = || { let diagnose_conflict = || {
let message = format!( let message = format!("variant field name `{}` conflicts with internal tag", tag);
"variant field name `{}` conflicts with internal tag",
tag
);
cx.error(message); cx.error(message);
}; };
@@ -246,8 +251,8 @@ fn check_internal_tag_field_name_conflict(
return; return;
} }
} }
}, }
Style::Unit | Style::Newtype | Style::Tuple => {}, Style::Unit | Style::Newtype | Style::Tuple => {}
} }
} }
} }
@@ -256,7 +261,10 @@ fn check_internal_tag_field_name_conflict(
/// contents tag must differ, for the same reason. /// contents tag must differ, for the same reason.
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
let (type_tag, content_tag) = match *cont.attrs.tag() { let (type_tag, content_tag) = match *cont.attrs.tag() {
EnumTag::Adjacent { ref tag, ref content } => (tag, content), EnumTag::Adjacent {
ref tag,
ref content,
} => (tag, content),
EnumTag::Internal { .. } | EnumTag::External | EnumTag::None => return, EnumTag::Internal { .. } | EnumTag::External | EnumTag::None => return,
}; };
+1 -1
View File
@@ -6,8 +6,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::fmt::Display;
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt::Display;
use std::thread; use std::thread;
#[derive(Default)] #[derive(Default)]
+5 -3
View File
@@ -6,9 +6,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.22.2")] #![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.23.1")]
#![cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity, doc_markdown, match_same_arms, #![cfg_attr(
redundant_field_names))] feature = "cargo-clippy",
allow(cyclomatic_complexity, doc_markdown, match_same_arms, redundant_field_names)
)]
#[macro_use] #[macro_use]
extern crate syn; extern crate syn;
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_test" name = "serde_test"
version = "1.0.36" # remember to update html_root_url version = "1.0.41" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations" description = "Token De/Serializer for testing De/Serialize implementations"
File diff suppressed because it is too large Load Diff
+12 -12
View File
@@ -6,9 +6,9 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
use serde::de::{self, Deserialize, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, use serde::de::{self, Deserialize, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess,
SeqAccess, VariantAccess, Visitor}; SeqAccess, VariantAccess, Visitor};
use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
use error::Error; use error::Error;
use token::Token; use token::Token;
@@ -22,28 +22,28 @@ macro_rules! assert_next_token {
($de:expr, $expected:expr) => { ($de:expr, $expected:expr) => {
match $de.next_token_opt() { match $de.next_token_opt() {
Some(token) if token == $expected => {} Some(token) if token == $expected => {}
Some(other) => { Some(other) => panic!(
panic!("expected Token::{} but deserialization wants Token::{}", "expected Token::{} but deserialization wants Token::{}",
other, $expected) other, $expected
} ),
None => { None => panic!(
panic!("end of tokens but deserialization wants Token::{}", "end of tokens but deserialization wants Token::{}",
$expected) $expected
} ),
} }
} };
} }
macro_rules! unexpected { macro_rules! unexpected {
($token:expr) => { ($token:expr) => {
panic!("deserialization did not expect this token: {}", $token) panic!("deserialization did not expect this token: {}", $token)
} };
} }
macro_rules! end_of_tokens { macro_rules! end_of_tokens {
() => { () => {
panic!("ran out of tokens to deserialize") panic!("ran out of tokens to deserialize")
} };
} }
impl<'de> Deserializer<'de> { impl<'de> Deserializer<'de> {
+11 -7
View File
@@ -155,29 +155,33 @@
//! # } //! # }
//! ``` //! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.36")] #![doc(html_root_url = "https://docs.rs/serde_test/1.0.41")]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints // Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))] #![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
// Whitelisted clippy_pedantic lints // Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", #![cfg_attr(
allow(empty_line_after_outer_attr, missing_docs_in_private_items, feature = "cargo-clippy",
redundant_field_names, stutter, use_debug, use_self))] allow(
empty_line_after_outer_attr, missing_docs_in_private_items, redundant_field_names, stutter,
use_debug, use_self
)
)]
#[macro_use] #[macro_use]
extern crate serde; extern crate serde;
mod ser;
mod de; mod de;
mod error; mod error;
mod ser;
mod assert;
mod configure; mod configure;
mod token; mod token;
mod assert;
pub use token::Token;
pub use assert::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, pub use assert::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens,
assert_ser_tokens_error, assert_tokens}; assert_ser_tokens_error, assert_tokens};
pub use token::Token;
pub use configure::{Compact, Configure, Readable}; pub use configure::{Compact, Configure, Readable};
+3 -3
View File
@@ -45,7 +45,7 @@ macro_rules! assert_next_token {
($ser:expr, $expected:ident($v:expr)) => { ($ser:expr, $expected:ident($v:expr)) => {
assert_next_token!( assert_next_token!(
$ser, $ser,
format_args!("{}({:?})", stringify!($expected), $v), format_args!(concat!(stringify!($expected), "({:?})"), $v),
Token::$expected(v), Token::$expected(v),
v == $v v == $v
); );
@@ -56,13 +56,13 @@ macro_rules! assert_next_token {
use std::fmt::Write; use std::fmt::Write;
let mut buffer = String::new(); let mut buffer = String::new();
$( $(
write!(&mut buffer, "{}: {:?}, ", stringify!($k), $k).unwrap(); write!(&mut buffer, concat!(stringify!($k), ": {:?}, "), $k).unwrap();
)* )*
buffer buffer
}; };
assert_next_token!( assert_next_token!(
$ser, $ser,
format_args!("{} {{ {}}}", stringify!($expected), field_format()), format_args!(concat!(stringify!($expected), " {{ {}}}"), field_format()),
Token::$expected { $($k),* }, Token::$expected { $($k),* },
($($k,)*) == compare ($($k,)*) == compare
); );
+1 -1
View File
@@ -9,7 +9,7 @@ unstable = ["serde/unstable", "compiletest_rs"]
[dev-dependencies] [dev-dependencies]
fnv = "1.0" fnv = "1.0"
proc-macro2 = "0.2" proc-macro2 = "0.3"
rustc-serialize = "0.3.16" rustc-serialize = "0.3.16"
serde = { path = "../serde", features = ["rc"] } serde = { path = "../serde", features = ["rc"] }
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] } serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
+11 -12
View File
@@ -6,11 +6,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![feature(lang_items, start, compiler_builtins_lib)] #![feature(lang_items, start)]
#![no_std] #![no_std]
extern crate libc; extern crate libc;
extern crate compiler_builtins;
#[start] #[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize { fn start(_argc: isize, _argv: *const *const u8) -> isize {
@@ -19,19 +18,17 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
#[lang = "eh_personality"] #[lang = "eh_personality"]
#[no_mangle] #[no_mangle]
pub extern fn rust_eh_personality() {} pub extern "C" fn rust_eh_personality() {}
#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern fn rust_eh_unwind_resume() {}
#[lang = "panic_fmt"] #[lang = "panic_fmt"]
#[no_mangle] #[no_mangle]
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, pub extern "C" fn rust_begin_panic(
_file: &'static str, _msg: core::fmt::Arguments,
_line: u32) -> ! { _file: &'static str,
_line: u32,
) -> ! {
unsafe { unsafe {
libc::abort() libc::abort();
} }
} }
@@ -50,7 +47,9 @@ struct Newtype(u8);
struct Tuple(u8, u8); struct Tuple(u8, u8);
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Struct { f: u8 } struct Struct {
f: u8,
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum Enum { enum Enum {
+52
View File
@@ -0,0 +1,52 @@
use serde::de::{Deserializer, Visitor, SeqAccess, Error};
use std::fmt;
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where D: Deserializer<'de>
{
deserializer.deserialize_byte_buf(ByteBufVisitor)
}
struct ByteBufVisitor;
impl<'de> Visitor<'de> for ByteBufVisitor {
type Value = Vec<u8>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("byte array")
}
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where V: SeqAccess<'de>
{
let mut values = Vec::new();
while let Some(value) = try!(visitor.next_element()) {
values.push(value);
}
Ok(values)
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where E: Error
{
Ok(v.to_vec())
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where E: Error
{
Ok(v)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: Error
{
Ok(v.as_bytes().to_vec())
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where E: Error
{
Ok(v.into_bytes())
}
}
@@ -0,0 +1,16 @@
// Copyright 2018 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: #[serde(flatten)] cannot be used on newtype structs
struct Foo(#[serde(flatten)] HashMap<String, String>);
fn main() {}
@@ -0,0 +1,16 @@
// Copyright 2018 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: #[serde(flatten)] cannot be used on tuple structs
struct Foo(u32, #[serde(flatten)] HashMap<String, String>);
fn main() {}
@@ -0,0 +1,21 @@
// Copyright 2018 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: #[serde(flatten)] cannot be used within enums
enum Foo {
A {
#[serde(flatten)]
fields: HashMap<String, String>,
}
}
fn main() {}
+44 -12
View File
@@ -391,9 +391,6 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum ExternallyTaggedVariantWith { enum ExternallyTaggedVariantWith {
#[allow(dead_code)]
Normal { f1: String },
#[serde(serialize_with = "ser_x")] #[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")] #[serde(deserialize_with = "de_x")]
#[allow(dead_code)] #[allow(dead_code)]
@@ -404,6 +401,11 @@ fn test_gen() {
#[allow(dead_code)] #[allow(dead_code)]
Tuple(String, u8), Tuple(String, u8),
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
#[allow(dead_code)]
Struct1 { x: X },
#[serde(serialize_with = "serialize_some_other_variant")] #[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)] #[allow(dead_code)]
@@ -419,14 +421,16 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(tag = "t")] #[serde(tag = "t")]
enum InternallyTaggedVariantWith { enum InternallyTaggedVariantWith {
#[allow(dead_code)]
Normal { f1: String },
#[serde(serialize_with = "ser_x")] #[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")] #[serde(deserialize_with = "de_x")]
#[allow(dead_code)] #[allow(dead_code)]
Newtype(X), Newtype(X),
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
#[allow(dead_code)]
Struct1 { x: X },
#[serde(serialize_with = "serialize_some_other_variant")] #[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)] #[allow(dead_code)]
@@ -442,9 +446,6 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(tag = "t", content = "c")] #[serde(tag = "t", content = "c")]
enum AdjacentlyTaggedVariantWith { enum AdjacentlyTaggedVariantWith {
#[allow(dead_code)]
Normal { f1: String },
#[serde(serialize_with = "ser_x")] #[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")] #[serde(deserialize_with = "de_x")]
#[allow(dead_code)] #[allow(dead_code)]
@@ -455,6 +456,11 @@ fn test_gen() {
#[allow(dead_code)] #[allow(dead_code)]
Tuple(String, u8), Tuple(String, u8),
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
#[allow(dead_code)]
Struct1 { x: X },
#[serde(serialize_with = "serialize_some_other_variant")] #[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)] #[allow(dead_code)]
@@ -470,9 +476,6 @@ fn test_gen() {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
enum UntaggedVariantWith { enum UntaggedVariantWith {
#[allow(dead_code)]
Normal { f1: String },
#[serde(serialize_with = "ser_x")] #[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")] #[serde(deserialize_with = "de_x")]
#[allow(dead_code)] #[allow(dead_code)]
@@ -483,6 +486,11 @@ fn test_gen() {
#[allow(dead_code)] #[allow(dead_code)]
Tuple(String, u8), Tuple(String, u8),
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
#[allow(dead_code)]
Struct1 { x: X },
#[serde(serialize_with = "serialize_some_other_variant")] #[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")] #[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)] #[allow(dead_code)]
@@ -539,6 +547,30 @@ fn test_gen() {
array: [u8; 256], array: [u8; 256],
} }
assert_ser::<BigArray>(); assert_ser::<BigArray>();
trait AssocSerde {
type Assoc;
}
struct NoSerdeImpl;
impl AssocSerde for NoSerdeImpl {
type Assoc = u32;
}
#[derive(Serialize, Deserialize)]
struct AssocDerive<T: AssocSerde> {
assoc: T::Assoc
}
assert::<AssocDerive<NoSerdeImpl>>();
#[derive(Serialize, Deserialize)]
struct AssocDeriveMulti<S, T: AssocSerde> {
s: S,
assoc: T::Assoc,
}
assert::<AssocDeriveMulti<i32, NoSerdeImpl>>();
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
+290
View File
@@ -13,7 +13,11 @@
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
extern crate serde;
extern crate serde_test; extern crate serde_test;
mod bytes;
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens, use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens,
Token}; Token};
@@ -779,6 +783,158 @@ fn test_internally_tagged_enum() {
); );
} }
#[test]
fn test_internally_tagged_bytes() {
#[derive(Debug, PartialEq, Deserialize)]
#[serde(tag = "type")]
enum InternallyTagged {
String {
string: String,
},
Bytes {
#[serde(with = "bytes")]
bytes: Vec<u8>,
},
}
assert_de_tokens(
&InternallyTagged::String { string: "\0".to_owned() },
&[
Token::Struct {
name: "String",
len: 2,
},
Token::Str("type"),
Token::Str("String"),
Token::Str("string"),
Token::Str("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&InternallyTagged::String { string: "\0".to_owned() },
&[
Token::Struct {
name: "String",
len: 2,
},
Token::Str("type"),
Token::Str("String"),
Token::Str("string"),
Token::String("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&InternallyTagged::String { string: "\0".to_owned() },
&[
Token::Struct {
name: "String",
len: 2,
},
Token::Str("type"),
Token::Str("String"),
Token::Str("string"),
Token::Bytes(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&InternallyTagged::String { string: "\0".to_owned() },
&[
Token::Struct {
name: "String",
len: 2,
},
Token::Str("type"),
Token::Str("String"),
Token::Str("string"),
Token::ByteBuf(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&InternallyTagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Bytes",
len: 2,
},
Token::Str("type"),
Token::Str("Bytes"),
Token::Str("bytes"),
Token::Str("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&InternallyTagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Bytes",
len: 2,
},
Token::Str("type"),
Token::Str("Bytes"),
Token::Str("bytes"),
Token::String("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&InternallyTagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Bytes",
len: 2,
},
Token::Str("type"),
Token::Str("Bytes"),
Token::Str("bytes"),
Token::Bytes(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&InternallyTagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Bytes",
len: 2,
},
Token::Str("type"),
Token::Str("Bytes"),
Token::Str("bytes"),
Token::ByteBuf(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&InternallyTagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Bytes",
len: 2,
},
Token::Str("type"),
Token::Str("Bytes"),
Token::Str("bytes"),
Token::Seq { len: Some(1) },
Token::U8(0),
Token::SeqEnd,
Token::StructEnd,
],
);
}
#[test] #[test]
fn test_internally_tagged_struct_variant_containing_unit_variant() { fn test_internally_tagged_struct_variant_containing_unit_variant() {
#[derive(Debug, PartialEq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Serialize, Deserialize)]
@@ -1246,6 +1402,140 @@ fn test_enum_in_untagged_enum() {
); );
} }
#[test]
fn test_untagged_bytes() {
#[derive(Debug, PartialEq, Deserialize)]
#[serde(untagged)]
enum Untagged {
String {
string: String,
},
Bytes {
#[serde(with = "bytes")]
bytes: Vec<u8>,
},
}
assert_de_tokens(
&Untagged::String { string: "\0".to_owned() },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("string"),
Token::Str("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::String { string: "\0".to_owned() },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("string"),
Token::String("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::String { string: "\0".to_owned() },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("string"),
Token::Bytes(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::String { string: "\0".to_owned() },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("string"),
Token::ByteBuf(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("bytes"),
Token::Str("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("bytes"),
Token::String("\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("bytes"),
Token::Bytes(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("bytes"),
Token::ByteBuf(b"\0"),
Token::StructEnd,
],
);
assert_de_tokens(
&Untagged::Bytes { bytes: vec![0] },
&[
Token::Struct {
name: "Untagged",
len: 1,
},
Token::Str("bytes"),
Token::Seq { len: Some(1) },
Token::U8(0),
Token::SeqEnd,
Token::StructEnd,
],
);
}
#[test] #[test]
fn test_rename_all() { fn test_rename_all() {
#[derive(Serialize, Deserialize, Debug, PartialEq)] #[derive(Serialize, Deserialize, Debug, PartialEq)]