Compare commits

...

44 Commits

Author SHA1 Message Date
David Tolnay 83537c95e1 Release 1.0.10 2017-07-11 21:19:24 -07:00
David Tolnay fa9057fa31 Merge pull request #949 from WiSaGaN/feature/support-system-time
Support std::time::SystemTime
2017-07-11 21:17:56 -07:00
Wangshan Lu 0084d82a50 Add tests for SystemTime 2017-07-12 12:01:40 +08:00
Wangshan Lu b504b08782 Fix SystemTime serde name 2017-07-12 12:01:29 +08:00
David Tolnay 775e8154e7 Fix libc dependency in no_std test 2017-07-09 10:19:19 -07:00
David Tolnay 9c679d9082 Test for serializing BTreeSet 2017-07-09 10:16:49 -07:00
David Tolnay b0f9d2a0ba Exclude macros file from being tested by itself 2017-07-09 09:24:29 -07:00
David Tolnay f39b1db96a Additional errors for some reason 2017-07-09 09:22:20 -07:00
David Tolnay 9ecb0839de Release 1.0.9 2017-06-29 20:21:29 -07:00
David Tolnay 8a4c116812 Merge pull request #971 from serde-rs/remotede
Fix deserializer bounds on remote derive
2017-06-29 20:19:36 -07:00
David Tolnay 1d3e921ba6 Fix deserializer bounds on remote derive 2017-06-29 20:12:44 -07:00
David Tolnay 4fdba725fe Revert "Support deserialization of struct keys from integers"
This is not as useful as expected because the Serializer does not know the real
index of each struct field being serialized. The best it can do is keep a
counter, which goes wrong if fields are conditionally skipped.

This reverts commit eec7101894.
2017-06-18 09:11:21 -07:00
David Tolnay 75eed8cdde Merge pull request #958 from serde-rs/unused
Fix unused seq and map macros
2017-06-17 19:14:39 -07:00
David Tolnay 6801a13650 Fix unused seq and map macros 2017-06-17 19:01:12 -07:00
David Tolnay 25ab84d4b9 Merge pull request #957 from serde-rs/alloc
Merge crate `collections` into `alloc`
2017-06-17 18:59:43 -07:00
David Tolnay e43d3f3e4f Merge crate collections into alloc 2017-06-17 18:35:56 -07:00
David Tolnay b37d47c987 Merge pull request #956 from sfackler/int-field
Support deserialization of struct keys from integers
2017-06-17 18:26:45 -07:00
Steven Fackler eec7101894 Support deserialization of struct keys from integers
serde-cbor supports a "packed" serialization flag which causes keys to
be serialized as their indices, but the deserializer currently has to
hardcode support for this format. We can simply support deserialization
of struct keys from integers as we already do for enum variants.
2017-06-17 18:12:07 -07:00
Wangshan Lu 5dd327fb02 Support std::time::SystemTime 2017-06-04 16:39:03 +08:00
David Tolnay fd3d1396d3 Release 1.0.8 2017-05-24 00:17:27 -07:00
David Tolnay c47b4c8e0b Release 1.0.7 2017-05-19 17:00:31 -07:00
David Tolnay 2d793b82f6 Merge pull request #940 from BurntSushi/ag-deser-borrowed
add borrowed value deserializers
2017-05-19 16:59:55 -07:00
Andrew Gallant 237be46e29 add borrowed value deserializers
This adds two new types to the `de::value` module,
`BorrowedStrDeserializer` and `BorrowedBytesDeserializer`. A
`BorrowedStrDeserializer` is just like `StrDeserializer`, except the
lifetime of the string is tied to the lifetime of the deserializer. This
can be useful when, for example, deserializing into a
`HashMap<&str, &str>` when the keys/values are tied to the deserializer
itself.

The `BorrowedBytesDeserializer` has no analog, but it's the same as
`BorrowedStrDeserialize` except for `&[u8]` instead of `&str`.
2017-05-19 19:55:34 -04:00
David Tolnay 3d7aad1e7b Release 1.0.6 2017-05-17 08:20:54 -07:00
David Tolnay e792874369 Merge pull request #935 from spikefoo/combined-skip
Add a combined skip attribute
2017-05-16 09:13:49 -07:00
spikefoo 1669c69714 Add a combined #serde[(skip)] field attribute 2017-05-16 12:33:26 +03:00
David Tolnay 4d5e450054 Release 1.0.5 2017-05-14 12:53:48 -07:00
David Tolnay 26b22e647d Merge pull request #933 from serde-rs/contentstr
Fix internally tagged struct variant containing unit variant containing borrowed string
2017-05-14 12:53:07 -07:00
David Tolnay cda1fc46b0 Fix internally tagged struct variant containing unit variant containing borrowed string 2017-05-14 12:39:42 -07:00
David Tolnay c68b959696 Release 1.0.4 2017-05-10 20:05:22 -07:00
David Tolnay eab80172e4 Merge pull request #926 from serde-rs/borrow
Support borrowing within internally tagged enum
2017-05-10 20:04:36 -07:00
David Tolnay c1259fbc87 Support borrowing within internally tagged enum 2017-05-10 19:56:05 -07:00
David Tolnay 58e30eaee4 Release 1.0.3 2017-05-10 10:15:39 -07:00
David Tolnay bafa941004 Merge pull request #924 from pshc/deserialize-borrowed-path
impl Deserialize for &'a Path
2017-05-10 10:14:25 -07:00
Paul Collier f347b2d363 impl Deserialize for &'a Path 2017-05-10 13:03:03 -04:00
David Tolnay 3f9fc49cca Merge pull request #922 from serde-rs/nonzero
Removed Deref impl for NonZero
2017-05-09 19:58:17 -07:00
David Tolnay c913527944 Removed Deref impl for NonZero 2017-05-09 19:48:54 -07:00
David Tolnay 8fafc7420c Release 1.0.2 2017-04-27 12:32:30 -07:00
David Tolnay bea1c5b0f5 Remove trailing whitespace 2017-04-27 12:31:13 -07:00
David Tolnay aa37caf216 Merge pull request #905 from TedDriggs/adjacent_tag_enums
Fix #816 - adjacently-tagged enums honor deny_unknown_fields
2017-04-27 12:27:31 -07:00
Ted Driggs 2440b59aae Address feedback on PR #905
* Added error test when deny_unknown_fields enabled
* Fixed next_relevant_key to use absolute paths
2017-04-27 12:21:32 -07:00
Ted Driggs 873cfbe9ab Fix #816 - adjacently-tagged enums honor deny_unknown_fields 2017-04-27 11:24:09 -07:00
David Tolnay c96efcb87a Merge pull request #900 from SuperFluffy/macro_to_derive_input
Replace deprecated MacroInput; completes c52e131
2017-04-25 08:10:26 -07:00
Richard Janis Goldschmidt b53026a21b Replace deprecated MacroInput; completes c52e13 2017-04-25 11:08:56 +02:00
29 changed files with 944 additions and 246 deletions
+4 -11
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.1" # remember to update html_root_url
version = "1.0.10" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"
@@ -48,22 +48,15 @@ std = []
# https://github.com/serde-rs/serde/issues/812
unstable = []
# Provide impls for types that require memory allocation like Box<T> and Rc<T>.
# This is a subset of std but may be enabled without depending on all of std.
# Provide impls for types in the Rust core allocation and collections library
# including String, Box<T>, Vec<T>, and Cow<T>. This is a subset of std but may
# be enabled without depending on all of std.
#
# Requires a dependency on the unstable core allocation library:
#
# https://doc.rust-lang.org/alloc/
alloc = ["unstable"]
# Provide impls for collection types like String and Cow<T>. This is a subset of
# std but may be enabled without depending on all of std.
#
# Requires a dependency on the unstable collections library:
#
# https://doc.rust-lang.org/collections/
collections = ["alloc"]
# Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types
# does not preserve identity and may result in multiple copies of the same data.
# Be sure that this is what you want before enabling this feature.
+180 -16
View File
@@ -11,12 +11,12 @@ use lib::*;
use de::{Deserialize, Deserializer, EnumAccess, Error, SeqAccess, Unexpected, VariantAccess,
Visitor};
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
use de::MapAccess;
use de::from_primitive::FromPrimitive;
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
use private::de::size_hint;
////////////////////////////////////////////////////////////////////////////////
@@ -208,10 +208,10 @@ impl<'de> Deserialize<'de> for char {
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
struct StringVisitor;
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Visitor<'de> for StringVisitor {
type Value = String;
@@ -254,7 +254,7 @@ impl<'de> Visitor<'de> for StringVisitor {
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Deserialize<'de> for String {
fn deserialize<D>(deserializer: D) -> Result<String, D::Error>
where
@@ -497,7 +497,7 @@ impl<'de, T> Deserialize<'de> for PhantomData<T> {
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
macro_rules! seq_impl {
(
$ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >,
@@ -552,7 +552,7 @@ macro_rules! seq_impl {
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
BinaryHeap<T: Ord>,
seq,
@@ -560,7 +560,7 @@ seq_impl!(
BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())),
BinaryHeap::push);
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
BTreeSet<T: Eq + Ord>,
seq,
@@ -568,7 +568,7 @@ seq_impl!(
BTreeSet::new(),
BTreeSet::insert);
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
LinkedList<T>,
seq,
@@ -584,7 +584,7 @@ seq_impl!(
HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()),
HashSet::insert);
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
Vec<T>,
seq,
@@ -592,7 +592,7 @@ seq_impl!(
Vec::with_capacity(size_hint::cautious(seq.size_hint())),
Vec::push);
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
VecDeque<T>,
seq,
@@ -790,7 +790,7 @@ tuple_impls! {
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
macro_rules! map_impl {
(
$ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >,
@@ -846,7 +846,7 @@ macro_rules! map_impl {
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
map_impl!(
BTreeMap<K: Ord, V>,
map,
@@ -897,6 +897,44 @@ parse_impl!(net::SocketAddrV6);
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
struct PathVisitor;
#[cfg(feature = "std")]
impl<'a> Visitor<'a> for PathVisitor {
type Value = &'a Path;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a borrowed path")
}
fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v.as_ref())
}
fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E>
where
E: Error,
{
str::from_utf8(v)
.map(AsRef::as_ref)
.map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self))
}
}
#[cfg(feature = "std")]
impl<'de: 'a, 'a> Deserialize<'de> for &'a Path {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(PathVisitor)
}
}
#[cfg(feature = "std")]
struct PathBufVisitor;
@@ -1072,7 +1110,7 @@ where
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, T> Deserialize<'de> for Box<[T]>
where
T: Deserialize<'de>,
@@ -1085,7 +1123,7 @@ where
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Deserialize<'de> for Box<str> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -1121,7 +1159,7 @@ where
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T>
where
T: ToOwned,
@@ -1326,6 +1364,132 @@ impl<'de> Deserialize<'de> for Duration {
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for SystemTime {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
// Reuse duration
enum Field {
Secs,
Nanos,
};
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`secs_since_epoch` or `nanos_since_epoch`")
}
fn visit_str<E>(self, value: &str) -> Result<Field, E>
where
E: Error,
{
match value {
"secs_since_epoch" => Ok(Field::Secs),
"nanos_since_epoch" => Ok(Field::Nanos),
_ => Err(Error::unknown_field(value, FIELDS)),
}
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Field, E>
where
E: Error,
{
match value {
b"secs_since_epoch" => Ok(Field::Secs),
b"nanos_since_epoch" => Ok(Field::Nanos),
_ => {
let value = String::from_utf8_lossy(value);
Err(Error::unknown_field(&value, FIELDS))
}
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct DurationVisitor;
impl<'de> Visitor<'de> for DurationVisitor {
type Value = Duration;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct SystemTime")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Duration, A::Error>
where
A: SeqAccess<'de>,
{
let secs: u64 = match try!(seq.next_element()) {
Some(value) => value,
None => {
return Err(Error::invalid_length(0, &self));
}
};
let nanos: u32 = match try!(seq.next_element()) {
Some(value) => value,
None => {
return Err(Error::invalid_length(1, &self));
}
};
Ok(Duration::new(secs, nanos))
}
fn visit_map<A>(self, mut map: A) -> Result<Duration, A::Error>
where
A: MapAccess<'de>,
{
let mut secs: Option<u64> = None;
let mut nanos: Option<u32> = None;
while let Some(key) = try!(map.next_key()) {
match key {
Field::Secs => {
if secs.is_some() {
return Err(<A::Error as Error>::duplicate_field("secs_since_epoch"));
}
secs = Some(try!(map.next_value()));
}
Field::Nanos => {
if nanos.is_some() {
return Err(<A::Error as Error>::duplicate_field("nanos_since_epoch"));
}
nanos = Some(try!(map.next_value()));
}
}
}
let secs = match secs {
Some(secs) => secs,
None => return Err(<A::Error as Error>::missing_field("secs_since_epoch")),
};
let nanos = match nanos {
Some(nanos) => nanos,
None => return Err(<A::Error as Error>::missing_field("nanos_since_epoch")),
};
Ok(Duration::new(secs, nanos))
}
}
const FIELDS: &'static [&'static str] = &["secs_since_epoch", "nanos_since_epoch"];
let duration = try!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor));
Ok(UNIX_EPOCH + duration)
}
}
////////////////////////////////////////////////////////////////////////////////
// Similar to:
//
// #[derive(Deserialize)]
+3 -2
View File
@@ -94,6 +94,7 @@
//! - OsString
//! - **Miscellaneous standard library types**:
//! - Duration
//! - SystemTime
//! - Path
//! - PathBuf
//! - Range\<T\>
@@ -1262,7 +1263,7 @@ pub trait Visitor<'de>: Sized {
/// The default implementation forwards to `visit_str` and then drops the
/// `String`.
#[inline]
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: Error,
@@ -1321,7 +1322,7 @@ pub trait Visitor<'de>: Sized {
///
/// The default implementation forwards to `visit_bytes` and then drops the
/// `Vec<u8>`.
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: Error,
+126 -17
View File
@@ -51,13 +51,13 @@ pub struct Error {
err: ErrorImpl,
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
type ErrorImpl = Box<str>;
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
type ErrorImpl = ();
impl de::Error for Error {
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
fn custom<T>(msg: T) -> Self
where
T: Display,
@@ -65,7 +65,7 @@ impl de::Error for Error {
Error { err: msg.to_string().into_boxed_str() }
}
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
fn custom<T>(msg: T) -> Self
where
T: Display,
@@ -85,12 +85,12 @@ impl ser::Error for Error {
}
impl Display for Error {
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
formatter.write_str(&self.err)
}
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
formatter.write_str("Serde deserialization error")
}
@@ -355,15 +355,84 @@ where
////////////////////////////////////////////////////////////////////////////////
/// A deserializer holding a `&str` with a lifetime tied to another
/// deserializer.
#[derive(Clone, Debug)]
pub struct BorrowedStrDeserializer<'de, E> {
value: &'de str,
marker: PhantomData<E>,
}
impl<'de, E> BorrowedStrDeserializer<'de, E> {
/// Create a new borrowed deserializer from the given string.
pub fn new(value: &'de str) -> BorrowedStrDeserializer<'de, E> {
BorrowedStrDeserializer {
value: value,
marker: PhantomData,
}
}
}
impl<'de, E> de::Deserializer<'de> for BorrowedStrDeserializer<'de, E>
where
E: de::Error,
{
type Error = E;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_borrowed_str(self.value)
}
fn deserialize_enum<V>(
self,
name: &str,
variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
let _ = name;
let _ = variants;
visitor.visit_enum(self)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
map struct identifier ignored_any
}
}
impl<'de, E> de::EnumAccess<'de> for BorrowedStrDeserializer<'de, E>
where
E: de::Error,
{
type Error = E;
type Variant = private::UnitOnly<E>;
fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error>
where
T: de::DeserializeSeed<'de>,
{
seed.deserialize(self).map(private::unit_only)
}
}
////////////////////////////////////////////////////////////////////////////////
/// A deserializer holding a `String`.
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
#[derive(Clone, Debug)]
pub struct StringDeserializer<E> {
value: String,
marker: PhantomData<E>,
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, E> IntoDeserializer<'de, E> for String
where
E: de::Error,
@@ -378,7 +447,7 @@ where
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, E> de::Deserializer<'de> for StringDeserializer<E>
where
E: de::Error,
@@ -413,7 +482,7 @@ where
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, 'a, E> de::EnumAccess<'de> for StringDeserializer<E>
where
E: de::Error,
@@ -432,14 +501,14 @@ where
////////////////////////////////////////////////////////////////////////////////
/// A deserializer holding a `Cow<str>`.
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
#[derive(Clone, Debug)]
pub struct CowStrDeserializer<'a, E> {
value: Cow<'a, str>,
marker: PhantomData<E>,
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str>
where
E: de::Error,
@@ -454,7 +523,7 @@ where
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, 'a, E> de::Deserializer<'de> for CowStrDeserializer<'a, E>
where
E: de::Error,
@@ -492,7 +561,7 @@ where
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E>
where
E: de::Error,
@@ -510,6 +579,46 @@ where
////////////////////////////////////////////////////////////////////////////////
/// A deserializer holding a `&[u8]` with a lifetime tied to another
/// deserializer.
#[derive(Clone, Debug)]
pub struct BorrowedBytesDeserializer<'de, E> {
value: &'de [u8],
marker: PhantomData<E>,
}
impl<'de, E> BorrowedBytesDeserializer<'de, E> {
/// Create a new borrowed deserializer from the given byte slice.
pub fn new(value: &'de [u8]) -> BorrowedBytesDeserializer<'de, E> {
BorrowedBytesDeserializer {
value: value,
marker: PhantomData,
}
}
}
impl<'de, E> de::Deserializer<'de> for BorrowedBytesDeserializer<'de, E>
where
E: de::Error,
{
type Error = E;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_borrowed_bytes(self.value)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
map struct identifier ignored_any enum
}
}
////////////////////////////////////////////////////////////////////////////////
/// A deserializer that iterates over a sequence.
#[derive(Clone, Debug)]
pub struct SeqDeserializer<I, E> {
@@ -618,7 +727,7 @@ impl Expected for ExpectedInSeq {
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, T, E> IntoDeserializer<'de, E> for Vec<T>
where
T: IntoDeserializer<'de, E>,
@@ -631,7 +740,7 @@ where
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, T, E> IntoDeserializer<'de, E> for BTreeSet<T>
where
T: IntoDeserializer<'de, E> + Eq + Ord,
@@ -1036,7 +1145,7 @@ impl Expected for ExpectedInMap {
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, K, V, E> IntoDeserializer<'de, E> for BTreeMap<K, V>
where
K: IntoDeserializer<'de, E> + Eq + Ord,
+2 -2
View File
@@ -19,7 +19,7 @@ pub use self::string::from_utf8_lossy;
mod string {
use lib::*;
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<str> {
String::from_utf8_lossy(bytes)
}
@@ -31,7 +31,7 @@ mod string {
//
// so it is okay for the return type to be different from the std case as long
// as the above works.
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
// Three unicode replacement characters if it fails. They look like a
// white-on-black question mark. The user will recognize it as invalid
+13 -17
View File
@@ -79,7 +79,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.1")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.10")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
@@ -91,7 +91,6 @@
#![cfg_attr(feature = "unstable", feature(nonzero, specialization))]
#![cfg_attr(all(feature = "std", feature = "unstable"), feature(into_boxed_c_str))]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(feature = "collections", feature(collections))]
// Whitelisted clippy lints.
#![cfg_attr(feature = "cargo-clippy", allow(doc_markdown))]
@@ -104,18 +103,15 @@
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "collections")]
extern crate collections;
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(all(feature = "unstable", feature = "std"))]
extern crate core;
/// A facade around all the types we need from the `std`, `core`, `alloc`, and
/// `collections` crates. This avoids elaborate import wrangling having to
/// happen in every module.
/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
mod core {
#[cfg(feature = "std")]
@@ -140,18 +136,18 @@ mod lib {
#[cfg(feature = "std")]
pub use std::borrow::{Cow, ToOwned};
#[cfg(all(feature = "collections", not(feature = "std")))]
pub use collections::borrow::{Cow, ToOwned};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::borrow::{Cow, ToOwned};
#[cfg(feature = "std")]
pub use std::string::String;
#[cfg(all(feature = "collections", not(feature = "std")))]
pub use collections::string::{String, ToString};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::string::{String, ToString};
#[cfg(feature = "std")]
pub use std::vec::Vec;
#[cfg(all(feature = "collections", not(feature = "std")))]
pub use collections::vec::Vec;
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::vec::Vec;
#[cfg(feature = "std")]
pub use std::boxed::Box;
@@ -170,8 +166,8 @@ mod lib {
#[cfg(feature = "std")]
pub use std::collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
#[cfg(all(feature = "collections", not(feature = "std")))]
pub use collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
#[cfg(feature = "std")]
pub use std::{error, net};
@@ -187,7 +183,7 @@ mod lib {
#[cfg(feature = "std")]
pub use std::path::{Path, PathBuf};
#[cfg(feature = "std")]
pub use std::time::Duration;
pub use std::time::{Duration, SystemTime, UNIX_EPOCH};
#[cfg(feature = "std")]
pub use std::sync::{Mutex, RwLock};
+227 -120
View File
@@ -10,12 +10,13 @@ use lib::*;
use de::{Deserialize, Deserializer, IntoDeserializer, Error, Visitor};
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
use de::Unexpected;
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
pub use self::content::{Content, ContentRefDeserializer, ContentDeserializer,
TaggedContentVisitor, TagOrContentField, TagOrContentFieldVisitor,
TagContentOtherField, TagContentOtherFieldVisitor,
InternallyTaggedUnitVisitor, UntaggedUnitVisitor};
/// If the missing field is of type `Option<T>` then treat is as `None`,
@@ -58,7 +59,7 @@ where
Deserialize::deserialize(deserializer)
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn borrow_cow_str<'de: 'a, 'a, D>(deserializer: D) -> Result<Cow<'a, str>, D::Error>
where
D: Deserializer<'de>,
@@ -127,7 +128,7 @@ where
deserializer.deserialize_str(CowStrVisitor)
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn borrow_cow_bytes<'de: 'a, 'a, D>(deserializer: D) -> Result<Cow<'a, [u8]>, D::Error>
where
D: Deserializer<'de>,
@@ -209,7 +210,7 @@ pub mod size_hint {
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
mod content {
// This module is private and nothing here should be used outside of
// generated code.
@@ -232,7 +233,7 @@ mod content {
///
/// Not public API. Use serde-value instead.
#[derive(Debug)]
pub enum Content {
pub enum Content<'de> {
Bool(bool),
U8(u8),
@@ -250,18 +251,20 @@ mod content {
Char(char),
String(String),
Bytes(Vec<u8>),
Str(&'de str),
ByteBuf(Vec<u8>),
Bytes(&'de [u8]),
None,
Some(Box<Content>),
Some(Box<Content<'de>>),
Unit,
Newtype(Box<Content>),
Seq(Vec<Content>),
Map(Vec<(Content, Content)>),
Newtype(Box<Content<'de>>),
Seq(Vec<Content<'de>>),
Map(Vec<(Content<'de>, Content<'de>)>),
}
impl Content {
impl<'de> Content<'de> {
fn unexpected(&self) -> Unexpected {
match *self {
Content::Bool(b) => Unexpected::Bool(b),
@@ -277,7 +280,9 @@ mod content {
Content::F64(f) => Unexpected::Float(f),
Content::Char(c) => Unexpected::Char(c),
Content::String(ref s) => Unexpected::Str(s),
Content::Bytes(ref b) => Unexpected::Bytes(b),
Content::Str(s) => Unexpected::Str(s),
Content::ByteBuf(ref b) => Unexpected::Bytes(b),
Content::Bytes(b) => Unexpected::Bytes(b),
Content::None | Content::Some(_) => Unexpected::Option,
Content::Unit => Unexpected::Unit,
Content::Newtype(_) => Unexpected::NewtypeStruct,
@@ -287,21 +292,30 @@ mod content {
}
}
impl<'de> Deserialize<'de> for Content {
impl<'de> Deserialize<'de> for Content<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
// Untagged and internally tagged enums are only supported in
// self-describing formats.
deserializer.deserialize_any(ContentVisitor)
let visitor = ContentVisitor { value: PhantomData };
deserializer.deserialize_any(visitor)
}
}
struct ContentVisitor;
struct ContentVisitor<'de> {
value: PhantomData<Content<'de>>,
}
impl<'de> Visitor<'de> for ContentVisitor {
type Value = Content;
impl<'de> ContentVisitor<'de> {
fn new() -> Self {
ContentVisitor { value: PhantomData }
}
}
impl<'de> Visitor<'de> for ContentVisitor<'de> {
type Value = Content<'de>;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("any value")
@@ -398,6 +412,13 @@ mod content {
Ok(Content::String(value.into()))
}
fn visit_borrowed_str<F>(self, value: &'de str) -> Result<Self::Value, F>
where
F: de::Error,
{
Ok(Content::Str(value))
}
fn visit_string<F>(self, value: String) -> Result<Self::Value, F>
where
F: de::Error,
@@ -409,14 +430,21 @@ mod content {
where
F: de::Error,
{
Ok(Content::Bytes(value.into()))
Ok(Content::ByteBuf(value.into()))
}
fn visit_borrowed_bytes<F>(self, value: &'de [u8]) -> Result<Self::Value, F>
where
F: de::Error,
{
Ok(Content::Bytes(value))
}
fn visit_byte_buf<F>(self, value: Vec<u8>) -> Result<Self::Value, F>
where
F: de::Error,
{
Ok(Content::Bytes(value))
Ok(Content::ByteBuf(value))
}
fn visit_unit<F>(self) -> Result<Self::Value, F>
@@ -480,23 +508,24 @@ mod content {
/// This is the type of the map keys in an internally tagged enum.
///
/// Not public API.
pub enum TagOrContent {
pub enum TagOrContent<'de> {
Tag,
Content(Content),
Content(Content<'de>),
}
struct TagOrContentVisitor {
struct TagOrContentVisitor<'de> {
name: &'static str,
value: PhantomData<TagOrContent<'de>>,
}
impl TagOrContentVisitor {
impl<'de> TagOrContentVisitor<'de> {
fn new(name: &'static str) -> Self {
TagOrContentVisitor { name: name }
TagOrContentVisitor { name: name, value: PhantomData }
}
}
impl<'de> DeserializeSeed<'de> for TagOrContentVisitor {
type Value = TagOrContent;
impl<'de> DeserializeSeed<'de> for TagOrContentVisitor<'de> {
type Value = TagOrContent<'de>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
@@ -508,8 +537,8 @@ mod content {
}
}
impl<'de> Visitor<'de> for TagOrContentVisitor {
type Value = TagOrContent;
impl<'de> Visitor<'de> for TagOrContentVisitor<'de> {
type Value = TagOrContent<'de>;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "a type tag `{}` or any other value", self.name)
@@ -519,7 +548,7 @@ mod content {
where
F: de::Error,
{
ContentVisitor
ContentVisitor::new()
.visit_bool(value)
.map(TagOrContent::Content)
}
@@ -528,14 +557,14 @@ mod content {
where
F: de::Error,
{
ContentVisitor.visit_i8(value).map(TagOrContent::Content)
ContentVisitor::new().visit_i8(value).map(TagOrContent::Content)
}
fn visit_i16<F>(self, value: i16) -> Result<Self::Value, F>
where
F: de::Error,
{
ContentVisitor
ContentVisitor::new()
.visit_i16(value)
.map(TagOrContent::Content)
}
@@ -544,7 +573,7 @@ mod content {
where
F: de::Error,
{
ContentVisitor
ContentVisitor::new()
.visit_i32(value)
.map(TagOrContent::Content)
}
@@ -553,7 +582,7 @@ mod content {
where
F: de::Error,
{
ContentVisitor
ContentVisitor::new()
.visit_i64(value)
.map(TagOrContent::Content)
}
@@ -562,14 +591,14 @@ mod content {
where
F: de::Error,
{
ContentVisitor.visit_u8(value).map(TagOrContent::Content)
ContentVisitor::new().visit_u8(value).map(TagOrContent::Content)
}
fn visit_u16<F>(self, value: u16) -> Result<Self::Value, F>
where
F: de::Error,
{
ContentVisitor
ContentVisitor::new()
.visit_u16(value)
.map(TagOrContent::Content)
}
@@ -578,7 +607,7 @@ mod content {
where
F: de::Error,
{
ContentVisitor
ContentVisitor::new()
.visit_u32(value)
.map(TagOrContent::Content)
}
@@ -587,7 +616,7 @@ mod content {
where
F: de::Error,
{
ContentVisitor
ContentVisitor::new()
.visit_u64(value)
.map(TagOrContent::Content)
}
@@ -596,7 +625,7 @@ mod content {
where
F: de::Error,
{
ContentVisitor
ContentVisitor::new()
.visit_f32(value)
.map(TagOrContent::Content)
}
@@ -605,7 +634,7 @@ mod content {
where
F: de::Error,
{
ContentVisitor
ContentVisitor::new()
.visit_f64(value)
.map(TagOrContent::Content)
}
@@ -614,7 +643,7 @@ mod content {
where
F: de::Error,
{
ContentVisitor
ContentVisitor::new()
.visit_char(value)
.map(TagOrContent::Content)
}
@@ -626,12 +655,25 @@ mod content {
if value == self.name {
Ok(TagOrContent::Tag)
} else {
ContentVisitor
ContentVisitor::new()
.visit_str(value)
.map(TagOrContent::Content)
}
}
fn visit_borrowed_str<F>(self, value: &'de str) -> Result<Self::Value, F>
where
F: de::Error,
{
if value == self.name {
Ok(TagOrContent::Tag)
} else {
ContentVisitor::new()
.visit_borrowed_str(value)
.map(TagOrContent::Content)
}
}
fn visit_string<F>(self, value: String) -> Result<Self::Value, F>
where
F: de::Error,
@@ -639,7 +681,7 @@ mod content {
if value == self.name {
Ok(TagOrContent::Tag)
} else {
ContentVisitor
ContentVisitor::new()
.visit_string(value)
.map(TagOrContent::Content)
}
@@ -652,12 +694,25 @@ mod content {
if value == self.name.as_bytes() {
Ok(TagOrContent::Tag)
} else {
ContentVisitor
ContentVisitor::new()
.visit_bytes(value)
.map(TagOrContent::Content)
}
}
fn visit_borrowed_bytes<F>(self, value: &'de [u8]) -> Result<Self::Value, F>
where
F: de::Error,
{
if value == self.name.as_bytes() {
Ok(TagOrContent::Tag)
} else {
ContentVisitor::new()
.visit_borrowed_bytes(value)
.map(TagOrContent::Content)
}
}
fn visit_byte_buf<F>(self, value: Vec<u8>) -> Result<Self::Value, F>
where
F: de::Error,
@@ -665,7 +720,7 @@ mod content {
if value == self.name.as_bytes() {
Ok(TagOrContent::Tag)
} else {
ContentVisitor
ContentVisitor::new()
.visit_byte_buf(value)
.map(TagOrContent::Content)
}
@@ -675,21 +730,21 @@ mod content {
where
F: de::Error,
{
ContentVisitor.visit_unit().map(TagOrContent::Content)
ContentVisitor::new().visit_unit().map(TagOrContent::Content)
}
fn visit_none<F>(self) -> Result<Self::Value, F>
where
F: de::Error,
{
ContentVisitor.visit_none().map(TagOrContent::Content)
ContentVisitor::new().visit_none().map(TagOrContent::Content)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
ContentVisitor
ContentVisitor::new()
.visit_some(deserializer)
.map(TagOrContent::Content)
}
@@ -698,7 +753,7 @@ mod content {
where
D: Deserializer<'de>,
{
ContentVisitor
ContentVisitor::new()
.visit_newtype_struct(deserializer)
.map(TagOrContent::Content)
}
@@ -707,7 +762,7 @@ mod content {
where
V: SeqAccess<'de>,
{
ContentVisitor
ContentVisitor::new()
.visit_seq(visitor)
.map(TagOrContent::Content)
}
@@ -716,7 +771,7 @@ mod content {
where
V: MapAccess<'de>,
{
ContentVisitor
ContentVisitor::new()
.visit_map(visitor)
.map(TagOrContent::Content)
}
@@ -725,7 +780,7 @@ mod content {
where
V: EnumAccess<'de>,
{
ContentVisitor
ContentVisitor::new()
.visit_enum(visitor)
.map(TagOrContent::Content)
}
@@ -734,33 +789,33 @@ mod content {
/// Used by generated code to deserialize an internally tagged enum.
///
/// Not public API.
pub struct TaggedContent<T> {
pub struct TaggedContent<'de, T> {
pub tag: T,
pub content: Content,
pub content: Content<'de>,
}
/// Not public API.
pub struct TaggedContentVisitor<T> {
pub struct TaggedContentVisitor<'de, T> {
tag_name: &'static str,
tag: PhantomData<T>,
value: PhantomData<TaggedContent<'de, T>>,
}
impl<T> TaggedContentVisitor<T> {
impl<'de, T> TaggedContentVisitor<'de, T> {
/// Visitor for the content of an internally tagged enum with the given tag
/// name.
pub fn new(name: &'static str) -> Self {
TaggedContentVisitor {
tag_name: name,
tag: PhantomData,
value: PhantomData,
}
}
}
impl<'de, T> DeserializeSeed<'de> for TaggedContentVisitor<T>
impl<'de, T> DeserializeSeed<'de> for TaggedContentVisitor<'de, T>
where
T: Deserialize<'de>,
{
type Value = TaggedContent<T>;
type Value = TaggedContent<'de, T>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
@@ -772,11 +827,11 @@ mod content {
}
}
impl<'de, T> Visitor<'de> for TaggedContentVisitor<T>
impl<'de, T> Visitor<'de> for TaggedContentVisitor<'de, T>
where
T: Deserialize<'de>,
{
type Value = TaggedContent<T>;
type Value = TaggedContent<'de, T>;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("any value")
@@ -863,15 +918,63 @@ mod content {
}
}
/// Used by generated code to deserialize an adjacently tagged enum when
/// ignoring unrelated fields is allowed.
///
/// Not public API.
pub enum TagContentOtherField {
Tag,
Content,
Other,
}
/// Not public API.
pub struct TagContentOtherFieldVisitor {
pub tag: &'static str,
pub content: &'static str,
}
impl<'de> DeserializeSeed<'de> for TagContentOtherFieldVisitor {
type Value = TagContentOtherField;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(self)
}
}
impl<'de> Visitor<'de> for TagContentOtherFieldVisitor {
type Value = TagContentOtherField;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{:?}, {:?}, or other ignored fields", self.tag, self.content)
}
fn visit_str<E>(self, field: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
if field == self.tag {
Ok(TagContentOtherField::Tag)
} else if field == self.content {
Ok(TagContentOtherField::Content)
} else {
Ok(TagContentOtherField::Other)
}
}
}
/// Not public API
pub struct ContentDeserializer<E> {
content: Content,
pub struct ContentDeserializer<'de, E> {
content: Content<'de>,
err: PhantomData<E>,
}
/// Used when deserializing an internally tagged enum because the content will
/// be used exactly once.
impl<'de, E> Deserializer<'de> for ContentDeserializer<E>
impl<'de, E> Deserializer<'de> for ContentDeserializer<'de, E>
where
E: de::Error,
{
@@ -895,6 +998,9 @@ mod content {
Content::F64(v) => visitor.visit_f64(v),
Content::Char(v) => visitor.visit_char(v),
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::Unit => visitor.visit_unit(),
Content::None => visitor.visit_none(),
Content::Some(v) => visitor.visit_some(ContentDeserializer::new(*v)),
@@ -916,7 +1022,6 @@ mod content {
try!(map_visitor.end());
Ok(value)
}
Content::Bytes(v) => visitor.visit_byte_buf(v),
}
}
@@ -977,7 +1082,7 @@ mod content {
}
(variant, Some(value))
}
Content::String(variant) => (Content::String(variant), None),
s @ Content::String(_) | s @ Content::Str(_) => (s, None),
other => {
return Err(de::Error::invalid_type(other.unexpected(), &"string or map"),);
}
@@ -999,9 +1104,9 @@ mod content {
}
}
impl<E> ContentDeserializer<E> {
impl<'de, E> ContentDeserializer<'de, E> {
/// private API, don't use
pub fn new(content: Content) -> Self {
pub fn new(content: Content<'de>) -> Self {
ContentDeserializer {
content: content,
err: PhantomData,
@@ -1009,21 +1114,21 @@ mod content {
}
}
struct EnumDeserializer<E>
struct EnumDeserializer<'de, E>
where
E: de::Error,
{
variant: Content,
value: Option<Content>,
variant: Content<'de>,
value: Option<Content<'de>>,
err: PhantomData<E>,
}
impl<'de, E> de::EnumAccess<'de> for EnumDeserializer<E>
impl<'de, E> de::EnumAccess<'de> for EnumDeserializer<'de, E>
where
E: de::Error,
{
type Error = E;
type Variant = VariantDeserializer<Self::Error>;
type Variant = VariantDeserializer<'de, Self::Error>;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), E>
where
@@ -1038,15 +1143,15 @@ mod content {
}
}
struct VariantDeserializer<E>
struct VariantDeserializer<'de, E>
where
E: de::Error,
{
value: Option<Content>,
value: Option<Content<'de>>,
err: PhantomData<E>,
}
impl<'de, E> de::VariantAccess<'de> for VariantDeserializer<E>
impl<'de, E> de::VariantAccess<'de> for VariantDeserializer<'de, E>
where
E: de::Error,
{
@@ -1102,19 +1207,19 @@ mod content {
}
}
struct SeqDeserializer<E>
struct SeqDeserializer<'de, E>
where
E: de::Error,
{
iter: <Vec<Content> as IntoIterator>::IntoIter,
iter: <Vec<Content<'de>> as IntoIterator>::IntoIter,
err: PhantomData<E>,
}
impl<E> SeqDeserializer<E>
impl<'de, E> SeqDeserializer<'de, E>
where
E: de::Error,
{
fn new(vec: Vec<Content>) -> Self {
fn new(vec: Vec<Content<'de>>) -> Self {
SeqDeserializer {
iter: vec.into_iter(),
err: PhantomData,
@@ -1122,7 +1227,7 @@ mod content {
}
}
impl<'de, E> de::Deserializer<'de> for SeqDeserializer<E>
impl<'de, E> de::Deserializer<'de> for SeqDeserializer<'de, E>
where
E: de::Error,
{
@@ -1154,7 +1259,7 @@ mod content {
}
}
impl<'de, E> de::SeqAccess<'de> for SeqDeserializer<E>
impl<'de, E> de::SeqAccess<'de> for SeqDeserializer<'de, E>
where
E: de::Error,
{
@@ -1178,20 +1283,20 @@ mod content {
}
}
struct MapDeserializer<E>
struct MapDeserializer<'de, E>
where
E: de::Error,
{
iter: <Vec<(Content, Content)> as IntoIterator>::IntoIter,
value: Option<Content>,
iter: <Vec<(Content<'de>, Content<'de>)> as IntoIterator>::IntoIter,
value: Option<Content<'de>>,
err: PhantomData<E>,
}
impl<E> MapDeserializer<E>
impl<'de, E> MapDeserializer<'de, E>
where
E: de::Error,
{
fn new(map: Vec<(Content, Content)>) -> Self {
fn new(map: Vec<(Content<'de>, Content<'de>)>) -> Self {
MapDeserializer {
iter: map.into_iter(),
value: None,
@@ -1200,7 +1305,7 @@ mod content {
}
}
impl<'de, E> de::MapAccess<'de> for MapDeserializer<E>
impl<'de, E> de::MapAccess<'de> for MapDeserializer<'de, E>
where
E: de::Error,
{
@@ -1234,7 +1339,7 @@ mod content {
}
}
impl<'de, E> de::Deserializer<'de> for MapDeserializer<E>
impl<'de, E> de::Deserializer<'de> for MapDeserializer<'de, E>
where
E: de::Error,
{
@@ -1256,14 +1361,14 @@ mod content {
}
/// Not public API.
pub struct ContentRefDeserializer<'a, E> {
content: &'a Content,
pub struct ContentRefDeserializer<'a, 'de: 'a, E> {
content: &'a Content<'de>,
err: PhantomData<E>,
}
/// Used when deserializing an untagged enum because the content may need to be
/// used more than once.
impl<'de, 'a, E> Deserializer<'de> for ContentRefDeserializer<'a, E>
impl<'de, 'a, E> Deserializer<'de> for ContentRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
@@ -1287,6 +1392,9 @@ mod content {
Content::F64(v) => visitor.visit_f64(v),
Content::Char(v) => visitor.visit_char(v),
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::Unit => visitor.visit_unit(),
Content::None => visitor.visit_none(),
Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)),
@@ -1312,7 +1420,6 @@ mod content {
try!(map_visitor.end());
Ok(value)
}
Content::Bytes(ref v) => visitor.visit_bytes(v),
}
}
@@ -1369,7 +1476,7 @@ mod content {
}
(variant, Some(value))
}
ref s @ Content::String(_) => (s, None),
ref s @ Content::String(_) | ref s @ Content::Str(_) => (s, None),
ref other => {
return Err(de::Error::invalid_type(other.unexpected(), &"string or map"),);
}
@@ -1391,9 +1498,9 @@ mod content {
}
}
impl<'a, E> ContentRefDeserializer<'a, E> {
impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E> {
/// private API, don't use
pub fn new(content: &'a Content) -> Self {
pub fn new(content: &'a Content<'de>) -> Self {
ContentRefDeserializer {
content: content,
err: PhantomData,
@@ -1401,21 +1508,21 @@ mod content {
}
}
struct EnumRefDeserializer<'a, E>
struct EnumRefDeserializer<'a, 'de: 'a, E>
where
E: de::Error,
{
variant: &'a Content,
value: Option<&'a Content>,
variant: &'a Content<'de>,
value: Option<&'a Content<'de>>,
err: PhantomData<E>,
}
impl<'de, 'a, E> de::EnumAccess<'de> for EnumRefDeserializer<'a, E>
impl<'de, 'a, E> de::EnumAccess<'de> for EnumRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
type Error = E;
type Variant = VariantRefDeserializer<'a, Self::Error>;
type Variant = VariantRefDeserializer<'a, 'de, Self::Error>;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
@@ -1430,15 +1537,15 @@ mod content {
}
}
struct VariantRefDeserializer<'a, E>
struct VariantRefDeserializer<'a, 'de: 'a, E>
where
E: de::Error,
{
value: Option<&'a Content>,
value: Option<&'a Content<'de>>,
err: PhantomData<E>,
}
impl<'de, 'a, E> de::VariantAccess<'de> for VariantRefDeserializer<'a, E>
impl<'de, 'a, E> de::VariantAccess<'de> for VariantRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
@@ -1494,19 +1601,19 @@ mod content {
}
}
struct SeqRefDeserializer<'a, E>
struct SeqRefDeserializer<'a, 'de: 'a, E>
where
E: de::Error,
{
iter: <&'a [Content] as IntoIterator>::IntoIter,
iter: <&'a [Content<'de>] as IntoIterator>::IntoIter,
err: PhantomData<E>,
}
impl<'a, E> SeqRefDeserializer<'a, E>
impl<'a, 'de, E> SeqRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
fn new(vec: &'a [Content]) -> Self {
fn new(vec: &'a [Content<'de>]) -> Self {
SeqRefDeserializer {
iter: vec.into_iter(),
err: PhantomData,
@@ -1514,7 +1621,7 @@ mod content {
}
}
impl<'de, 'a, E> de::Deserializer<'de> for SeqRefDeserializer<'a, E>
impl<'de, 'a, E> de::Deserializer<'de> for SeqRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
@@ -1546,7 +1653,7 @@ mod content {
}
}
impl<'de, 'a, E> de::SeqAccess<'de> for SeqRefDeserializer<'a, E>
impl<'de, 'a, E> de::SeqAccess<'de> for SeqRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
@@ -1570,20 +1677,20 @@ mod content {
}
}
struct MapRefDeserializer<'a, E>
struct MapRefDeserializer<'a, 'de: 'a, E>
where
E: de::Error,
{
iter: <&'a [(Content, Content)] as IntoIterator>::IntoIter,
value: Option<&'a Content>,
iter: <&'a [(Content<'de>, Content<'de>)] as IntoIterator>::IntoIter,
value: Option<&'a Content<'de>>,
err: PhantomData<E>,
}
impl<'a, E> MapRefDeserializer<'a, E>
impl<'a, 'de, E> MapRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
fn new(map: &'a [(Content, Content)]) -> Self {
fn new(map: &'a [(Content<'de>, Content<'de>)]) -> Self {
MapRefDeserializer {
iter: map.into_iter(),
value: None,
@@ -1592,7 +1699,7 @@ mod content {
}
}
impl<'de, 'a, E> de::MapAccess<'de> for MapRefDeserializer<'a, E>
impl<'de, 'a, E> de::MapAccess<'de> for MapRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
@@ -1627,7 +1734,7 @@ mod content {
}
}
impl<'de, 'a, E> de::Deserializer<'de> for MapRefDeserializer<'a, E>
impl<'de, 'a, E> de::Deserializer<'de> for MapRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
@@ -1648,7 +1755,7 @@ mod content {
}
}
impl<'de, E> de::IntoDeserializer<'de, E> for ContentDeserializer<E>
impl<'de, E> de::IntoDeserializer<'de, E> for ContentDeserializer<'de, E>
where
E: de::Error,
{
@@ -1659,7 +1766,7 @@ mod content {
}
}
impl<'de, 'a, E> de::IntoDeserializer<'de, E> for ContentRefDeserializer<'a, E>
impl<'de, 'a, E> de::IntoDeserializer<'de, E> for ContentRefDeserializer<'a, 'de, E>
where
E: de::Error,
{
+13 -13
View File
@@ -10,7 +10,7 @@ use lib::*;
use ser::{self, Serialize, Serializer, SerializeMap, SerializeStruct, Impossible};
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
use self::content::{SerializeTupleVariantAsMapValue, SerializeStructVariantAsMapValue};
/// Used to check that serde(getter) attributes return the expected type.
@@ -64,7 +64,7 @@ enum Unsupported {
Sequence,
Tuple,
TupleStruct,
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
Enum,
}
@@ -83,7 +83,7 @@ impl Display for Unsupported {
Unsupported::Sequence => formatter.write_str("a sequence"),
Unsupported::Tuple => formatter.write_str("a tuple"),
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
Unsupported::Enum => formatter.write_str("an enum"),
}
}
@@ -117,14 +117,14 @@ where
type SerializeMap = S::SerializeMap;
type SerializeStruct = S::SerializeStruct;
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
type SerializeTupleVariant = Impossible<S::Ok, S::Error>;
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
type SerializeTupleVariant = SerializeTupleVariantAsMapValue<S::SerializeMap>;
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
type SerializeStructVariant = Impossible<S::Ok, S::Error>;
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
type SerializeStructVariant = SerializeStructVariantAsMapValue<S::SerializeMap>;
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
@@ -257,7 +257,7 @@ where
Err(self.bad_type(Unsupported::TupleStruct))
}
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
fn serialize_tuple_variant(
self,
_: &'static str,
@@ -270,7 +270,7 @@ where
Err(self.bad_type(Unsupported::Enum))
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
fn serialize_tuple_variant(
self,
_: &'static str,
@@ -300,7 +300,7 @@ where
Ok(state)
}
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
fn serialize_struct_variant(
self,
_: &'static str,
@@ -313,7 +313,7 @@ where
Err(self.bad_type(Unsupported::Enum))
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
fn serialize_struct_variant(
self,
_: &'static str,
@@ -327,7 +327,7 @@ where
Ok(SerializeStructVariantAsMapValue::new(map, inner_variant, len),)
}
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
fn collect_str<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
where
T: Display,
@@ -363,7 +363,7 @@ impl Display for Error {
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
mod content {
use lib::*;
+40 -11
View File
@@ -56,7 +56,7 @@ impl Serialize for str {
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
impl Serialize for String {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -177,6 +177,7 @@ where
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
macro_rules! seq_impl {
($ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident)* >) => {
impl<T $(, $typaram)*> Serialize for $ty<T $(, $typaram)*>
@@ -195,22 +196,22 @@ macro_rules! seq_impl {
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(BinaryHeap<T: Ord>);
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(BTreeSet<T: Ord>);
#[cfg(feature = "std")]
seq_impl!(HashSet<T: Eq + Hash, H: BuildHasher>);
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(LinkedList<T>);
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(Vec<T>);
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(VecDeque<T>);
////////////////////////////////////////////////////////////////////////////////
@@ -290,6 +291,7 @@ tuple_impls! {
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "alloc"))]
macro_rules! map_impl {
($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)* >) => {
impl<K, V $(, $typaram)*> Serialize for $ty<K, V $(, $typaram)*>
@@ -309,7 +311,7 @@ macro_rules! map_impl {
}
}
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
map_impl!(BTreeMap<K: Ord, V>);
#[cfg(feature = "std")]
@@ -343,14 +345,24 @@ deref_impl!(<T> Serialize for Rc<T> where T: Serialize);
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
deref_impl!(<T> Serialize for Arc<T> where T: Serialize);
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned);
#[cfg(feature = "unstable")]
deref_impl!(<T> Serialize for NonZero<T> where T: Serialize + Zeroable);
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")]
impl<T> Serialize for NonZero<T>
where
T: Serialize + Zeroable + Clone,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.clone().get().serialize(serializer)
}
}
impl<T> Serialize for Cell<T>
where
T: Serialize + Copy,
@@ -445,6 +457,23 @@ impl Serialize for Duration {
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "std")]
impl Serialize for SystemTime {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use super::SerializeStruct;
let duration_since_epoch = self.duration_since(UNIX_EPOCH).expect("SystemTime must be later than UNIX_EPOCH");
let mut state = try!(serializer.serialize_struct("SystemTime", 2));
try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs()));
try!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos()));
state.end()
}
}
////////////////////////////////////////////////////////////////////////////////
/// Serialize a value that implements `Display` as a string, when that string is
/// statically known to never have more than a constant `MAX_LEN` bytes.
///
+3 -2
View File
@@ -89,6 +89,7 @@
//! - OsString
//! - **Miscellaneous standard library types**:
//! - Duration
//! - SystemTime
//! - Path
//! - PathBuf
//! - Range\<T\>
@@ -1321,7 +1322,7 @@ pub trait Serializer: Sized {
///
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
/// [`serialize_str`]: #tymethod.serialize_str
#[cfg(any(feature = "std", feature = "collections"))]
#[cfg(any(feature = "std", feature = "alloc"))]
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: Display,
@@ -1358,7 +1359,7 @@ pub trait Serializer: Sized {
/// }
/// }
/// ```
#[cfg(not(any(feature = "std", feature = "collections")))]
#[cfg(not(any(feature = "std", feature = "alloc")))]
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: Display;
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.1" # remember to update html_root_url
version = "1.0.10" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -20,5 +20,5 @@ proc-macro = true
[dependencies]
quote = "0.3.8"
serde_derive_internals = { version = "=0.15.0", default-features = false, path = "../serde_derive_internals" }
serde_derive_internals = { version = "=0.15.1", default-features = false, path = "../serde_derive_internals" }
syn = { version = "0.11", features = ["visit"] }
+62 -17
View File
@@ -23,15 +23,14 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
let ident = &cont.ident;
let params = Parameters::new(&cont);
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(&params);
let dummy_const = Ident::new(format!("_IMPL_DESERIALIZE_FOR_{}", ident));
let body = Stmts(deserialize_body(&cont, &params));
let impl_block = if let Some(remote) = cont.attrs.remote() {
let (impl_generics, ty_generics, where_clause) = cont.generics.split_for_impl();
let de_lifetime = params.de_lifetime_def();
quote! {
impl #impl_generics #ident #ty_generics #where_clause {
fn deserialize<#de_lifetime, __D>(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error>
impl #de_impl_generics #ident #ty_generics #where_clause {
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error>
where __D: _serde::Deserializer<'de>
{
#body
@@ -39,7 +38,6 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
}
}
} else {
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(&params);
quote! {
#[automatically_derived]
impl #de_impl_generics _serde::Deserialize<'de> for #ident #ty_generics #where_clause {
@@ -795,9 +793,19 @@ fn deserialize_adjacently_tagged_enum(
let expecting = format!("adjacently tagged enum {}", params.type_name());
let type_name = cattrs.name().deserialize_name();
let deny_unknown_fields = cattrs.deny_unknown_fields();
/// If unknown fields are allowed, we pick the visitor that can
/// step over those. Otherwise we pick the visitor that fails on
/// unknown keys.
let field_visitor_ty = if deny_unknown_fields {
quote! { _serde::private::de::TagOrContentFieldVisitor }
} else {
quote! { _serde::private::de::TagContentOtherFieldVisitor }
};
let tag_or_content = quote! {
_serde::private::de::TagOrContentFieldVisitor {
#field_visitor_ty {
tag: #tag,
content: #content,
}
@@ -844,9 +852,46 @@ fn deserialize_adjacently_tagged_enum(
};
}
let visit_third_key = quote! {
// Visit the third key in the map, hopefully there isn't one.
match try!(_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content)) {
/// Advance the map by one key, returning early in case of error.
let next_key = quote! {
try!(_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content))
};
/// When allowing unknown fields, we want to transparently step through keys we don't care
/// about until we find `tag`, `content`, or run out of keys.
let next_relevant_key = if deny_unknown_fields {
next_key
} else {
quote! {
{
let mut __rk : _serde::export::Option<_serde::private::de::TagOrContentField> = _serde::export::None;
while let _serde::export::Some(__k) = #next_key {
match __k {
_serde::private::de::TagContentOtherField::Other => {
try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map));
continue;
},
_serde::private::de::TagContentOtherField::Tag => {
__rk = _serde::export::Some(_serde::private::de::TagOrContentField::Tag);
break;
}
_serde::private::de::TagContentOtherField::Content => {
__rk = _serde::export::Some(_serde::private::de::TagOrContentField::Content);
break;
}
}
}
__rk
}
}
};
/// Step through remaining keys, looking for duplicates of previously-seen keys.
/// When unknown fields are denied, any key that isn't a duplicate will at this
/// point immediately produce an error.
let visit_remaining_keys = quote! {
match #next_relevant_key {
_serde::export::Some(_serde::private::de::TagOrContentField::Tag) => {
_serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag))
}
@@ -895,14 +940,14 @@ fn deserialize_adjacently_tagged_enum(
fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::MapAccess<'de>
{
// Visit the first key.
match try!(_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content)) {
// Visit the first relevant key.
match #next_relevant_key {
// First key is the tag.
_serde::export::Some(_serde::private::de::TagOrContentField::Tag) => {
// Parse the tag.
let __field = try!(_serde::de::MapAccess::next_value(&mut __map));
// Visit the second key.
match try!(_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content)) {
match #next_relevant_key {
// Second key is a duplicate of the tag.
_serde::export::Some(_serde::private::de::TagOrContentField::Tag) => {
_serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag))
@@ -915,8 +960,8 @@ fn deserialize_adjacently_tagged_enum(
marker: _serde::export::PhantomData,
lifetime: _serde::export::PhantomData,
}));
// Visit the third key, hopefully there isn't one.
#visit_third_key
// Visit remaining keys, looking for duplicates.
#visit_remaining_keys
}
// There is no second key; might be okay if the we have a unit variant.
_serde::export::None => #missing_content
@@ -927,7 +972,7 @@ fn deserialize_adjacently_tagged_enum(
// Buffer up the content.
let __content = try!(_serde::de::MapAccess::next_value::<_serde::private::de::Content>(&mut __map));
// Visit the second key.
match try!(_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content)) {
match #next_relevant_key {
// Second key is the tag.
_serde::export::Some(_serde::private::de::TagOrContentField::Tag) => {
let __deserializer = _serde::private::de::ContentDeserializer::<__A::Error>::new(__content);
@@ -936,8 +981,8 @@ fn deserialize_adjacently_tagged_enum(
// Deserialize the buffered content now that we know the variant.
#(#variant_arms)*
});
// Visit the third key, hopefully there isn't one.
#visit_third_key
// Visit remaining keys, looking for duplicates.
#visit_remaining_keys
}
// Second key is a duplicate of the content.
_serde::export::Some(_serde::private::de::TagOrContentField::Content) => {
+1 -1
View File
@@ -16,7 +16,7 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.1")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.10")]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive_internals"
version = "0.15.0" # remember to update html_root_url
version = "0.15.1" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "AST representation used by Serde derive macros. Unstable."
+1 -1
View File
@@ -45,7 +45,7 @@ pub enum Style {
}
impl<'a> Container<'a> {
pub fn from_ast(cx: &Ctxt, item: &'a syn::MacroInput) -> Container<'a> {
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput) -> Container<'a> {
let attrs = attr::Container::from_ast(cx, item);
let mut body = match item.body {
+9 -3
View File
@@ -166,7 +166,7 @@ pub enum Identifier {
impl Container {
/// Extract out the `#[serde(...)]` attributes from an item.
pub fn from_ast(cx: &Ctxt, item: &syn::MacroInput) -> Self {
pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self {
let mut ser_name = Attr::none(cx, "rename");
let mut de_name = Attr::none(cx, "rename");
let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields");
@@ -421,7 +421,7 @@ impl Container {
fn decide_tag(
cx: &Ctxt,
item: &syn::MacroInput,
item: &syn::DeriveInput,
untagged: BoolAttr,
internal_tag: Attr<String>,
content: Attr<String>,
@@ -477,7 +477,7 @@ fn decide_tag(
fn decide_identifier(
cx: &Ctxt,
item: &syn::MacroInput,
item: &syn::DeriveInput,
field_identifier: BoolAttr,
variant_identifier: BoolAttr,
) -> Identifier {
@@ -719,6 +719,12 @@ impl Field {
skip_deserializing.set_true();
}
// Parse `#[serde(skip)]`
MetaItem(Word(ref name)) if name == "skip" => {
skip_serializing.set_true();
skip_deserializing.set_true();
},
// Parse `#[serde(skip_serializing_if = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "skip_serializing_if" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
+1 -1
View File
@@ -6,7 +6,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.15.0")]
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.15.1")]
extern crate syn;
#[macro_use]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "1.0.1" # remember to update html_root_url
version = "1.0.10" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations"
+1 -1
View File
@@ -155,7 +155,7 @@
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.1")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.10")]
#[macro_use]
extern crate serde;
+1
View File
@@ -4,5 +4,6 @@ version = "0.0.0"
publish = false
[dependencies]
libc = { version = "0.2", default-features = false }
serde = { path = "../../serde", default-features = false }
serde_derive = { path = "../../serde_derive" }
+1 -1
View File
@@ -1,4 +1,4 @@
#![feature(lang_items, start, libc, compiler_builtins_lib)]
#![feature(lang_items, start, compiler_builtins_lib)]
#![no_std]
extern crate libc;
@@ -18,7 +18,9 @@ mod remote {
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::S")]
struct S {
b: u8, //~^^^ ERROR: no field `b` on type `&remote::S`
//~^^^ ERROR: struct `remote::S` has no field named `b`
//~^^^^ ERROR: struct `remote::S` has no field named `b`
b: u8, //~^^^^^ ERROR: no field `b` on type `&remote::S`
}
fn main() {}
+35
View File
@@ -580,6 +580,41 @@ fn test_skip_serializing_struct() {
);
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct SkipStruct<B>
{
a: i8,
#[serde(skip)]
b: B,
}
#[test]
fn test_skip_struct() {
assert_ser_tokens(
&SkipStruct { a: 1, b: 2 },
&[
Token::Struct { name: "SkipStruct", len: 1 },
Token::Str("a"),
Token::I8(1),
Token::StructEnd,
],
);
assert_de_tokens(
&SkipStruct { a: 1, b: 0 },
&[
Token::Struct { name: "SkipStruct", len: 1 },
Token::Str("a"),
Token::I8(1),
Token::StructEnd,
],
);
}
#[derive(Debug, PartialEq, Serialize)]
enum SkipSerializingEnum<'a, B, C>
where
+24 -2
View File
@@ -13,8 +13,8 @@ extern crate serde_derive;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::net;
use std::path::PathBuf;
use std::time::Duration;
use std::path::{Path, PathBuf};
use std::time::{Duration, UNIX_EPOCH};
use std::default::Default;
use std::ffi::{CString, OsString};
@@ -682,6 +682,23 @@ declare_tests! {
Token::SeqEnd,
],
}
test_system_time {
UNIX_EPOCH + Duration::new(1, 2) => &[
Token::Struct { name: "SystemTime", len: 2 },
Token::Str("secs_since_epoch"),
Token::U64(1),
Token::Str("nanos_since_epoch"),
Token::U32(2),
Token::StructEnd,
],
UNIX_EPOCH + Duration::new(1, 2) => &[
Token::Seq { len: Some(2) },
Token::I64(1),
Token::I64(2),
Token::SeqEnd,
],
}
test_range {
1u32..2u32 => &[
Token::Struct { name: "Range", len: 2 },
@@ -710,6 +727,11 @@ declare_tests! {
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
}
test_path {
Path::new("/usr/local/lib") => &[
Token::BorrowedStr("/usr/local/lib"),
],
}
test_path_buf {
PathBuf::from("/usr/local/lib") => &[
Token::String("/usr/local/lib"),
+28
View File
@@ -330,6 +330,34 @@ fn test_gen() {
struct EmptyArray {
empty: [X; 0],
}
enum Or<A, B> {
A(A),
B(B),
}
#[derive(Serialize, Deserialize)]
#[serde(untagged, remote = "Or")]
enum OrDef<A, B> {
#[allow(dead_code)]
A(A),
#[allow(dead_code)]
B(B),
}
struct Str<'a>(&'a str);
#[derive(Serialize, Deserialize)]
#[serde(remote = "Str")]
struct StrDef<'a>(&'a str);
#[derive(Serialize, Deserialize)]
struct Remote<'a> {
#[serde(with = "OrDef")]
or: Or<u8, bool>,
#[serde(borrow, with = "StrDef")]
s: Str<'a>,
}
}
//////////////////////////////////////////////////////////////////////////
+138
View File
@@ -695,6 +695,59 @@ fn test_internally_tagged_enum() {
);
}
#[test]
fn test_internally_tagged_struct_variant_containing_unit_variant() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub enum Level {
Info,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "action")]
pub enum Message {
Log { level: Level },
}
assert_de_tokens(
&Message::Log { level: Level::Info },
&[
Token::Struct { name: "Message", len: 2 },
Token::Str("action"),
Token::Str("Log"),
Token::Str("level"),
Token::BorrowedStr("Info"),
Token::StructEnd,
],
);
}
#[test]
fn test_internally_tagged_borrow() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum Input<'a> {
Package { name: &'a str },
}
assert_tokens(
&Input::Package { name: "borrowed" },
&[
Token::Struct { name: "Input", len: 2 },
Token::BorrowedStr("type"),
Token::BorrowedStr("Package"),
Token::BorrowedStr("name"),
Token::BorrowedStr("borrowed"),
Token::StructEnd,
],
);
}
#[test]
fn test_adjacently_tagged_enum() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
@@ -751,6 +804,31 @@ fn test_adjacently_tagged_enum() {
],
);
// unit with excess content (f, g, h)
assert_de_tokens(
&AdjacentlyTagged::Unit::<u8>,
&[
Token::Struct { name: "AdjacentlyTagged", len: 3 },
Token::Str("f"),
Token::Unit,
Token::Str("t"),
Token::Str("Unit"),
Token::Str("g"),
Token::Unit,
Token::Str("c"),
Token::Unit,
Token::Str("h"),
Token::Unit,
Token::StructEnd,
],
);
// newtype with tag first
assert_tokens(
&AdjacentlyTagged::Newtype::<u8>(1),
@@ -860,6 +938,66 @@ fn test_adjacently_tagged_enum() {
);
}
#[test]
fn test_adjacently_tagged_enum_deny_unknown_fields() {
#[derive(Debug, PartialEq, Deserialize)]
#[serde(tag = "t", content = "c", deny_unknown_fields)]
enum AdjacentlyTagged {
Unit,
}
assert_de_tokens(
&AdjacentlyTagged::Unit,
&[
Token::Struct { name: "AdjacentlyTagged", len: 2},
Token::Str("t"),
Token::Str("Unit"),
Token::Str("c"),
Token::Unit,
Token::StructEnd,
],
);
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct { name: "AdjacentlyTagged", len: 3},
Token::Str("t"),
Token::Str("Unit"),
Token::Str("c"),
Token::Unit,
Token::Str("h"),
],
r#"invalid value: string "h", expected "t" or "c""#
);
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct { name: "AdjacentlyTagged", len: 3},
Token::Str("h"),
],
r#"invalid value: string "h", expected "t" or "c""#
);
assert_de_tokens_error::<AdjacentlyTagged>(
&[
Token::Struct { name: "AdjacentlyTagged", len: 3},
Token::Str("c"),
Token::Unit,
Token::Str("h"),
],
r#"invalid value: string "h", expected "t" or "c""#
);
}
#[test]
fn test_enum_in_internally_tagged_enum() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
+24 -2
View File
@@ -9,10 +9,10 @@
#[macro_use]
extern crate serde_derive;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::net;
use std::path::{Path, PathBuf};
use std::time::Duration;
use std::time::{Duration, UNIX_EPOCH};
use std::ffi::CString;
#[cfg(unix)]
@@ -170,6 +170,17 @@ declare_tests! {
Token::SeqEnd,
],
}
test_btreeset {
BTreeSet::<isize>::new() => &[
Token::Seq { len: Some(0) },
Token::SeqEnd,
],
btreeset![1] => &[
Token::Seq { len: Some(1) },
Token::I32(1),
Token::SeqEnd,
],
}
test_hashset {
HashSet::<isize>::new() => &[
Token::Seq { len: Some(0) },
@@ -319,6 +330,17 @@ declare_tests! {
Token::StructEnd,
],
}
test_system_time {
UNIX_EPOCH + Duration::new(1, 2) => &[
Token::Struct { name: "SystemTime", len: 2 },
Token::Str("secs_since_epoch"),
Token::U64(1),
Token::Str("nanos_since_epoch"),
Token::U32(2),
Token::StructEnd,
],
}
test_range {
1u32..2u32 => &[
Token::Struct { name: "Range", len: 2 },
-1
View File
@@ -46,7 +46,6 @@ else
channel build
channel build --no-default-features
channel build --no-default-features --features alloc
channel build --no-default-features --features collections
channel test --features 'rc unstable'
cd "$DIR/test_suite/deps"
channel build