Compare commits

...

19 Commits

Author SHA1 Message Date
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
David Tolnay c7901e532e Release 1.0.1 2017-04-23 16:40:56 -07:00
David Tolnay 2af0701be6 Merge tag 'v0.9.15' into 'origin/master' 2017-04-23 16:39:32 -07:00
David Tolnay ae79451b7a Release 0.9.15 2017-04-23 16:37:43 -07:00
David Tolnay b220f264a5 Merge pull request #898 from SimonSapin/z-is-dead
Remove usage of unstable core::num::Zero, which was removed upstream.
2017-04-23 16:35:57 -07:00
David Tolnay 1a2b3815ef Merge pull request #899 from SimonSapin/z-is-dead-in-0.9-too
Remove usage of unstable core::num::Zero, which was removed upstream.
2017-04-23 16:34:06 -07:00
Simon Sapin 6fbf40b83c Remove usage of unstable core::num::Zero, which was removed upstream.
https://github.com/rust-lang/rust/pull/41437
2017-04-24 08:29:38 +09:00
Simon Sapin 1d6ecf3c2c Remove usage of unstable core::num::Zero, which was removed upstream.
https://github.com/rust-lang/rust/pull/41437

Backport of https://github.com/serde-rs/serde/pull/898 to 0.9.x
2017-04-24 08:25:08 +09:00
14 changed files with 271 additions and 38 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.0" # remember to update html_root_url
version = "1.0.3" # 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"
+47 -7
View File
@@ -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;
@@ -1471,22 +1509,24 @@ where
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")]
#[allow(deprecated)] // num::Zero is deprecated but there is no replacement
impl<'de, T> Deserialize<'de> for NonZero<T>
where
T: Deserialize<'de> + PartialEq + Zeroable + Zero,
T: Deserialize<'de> + Zeroable,
{
fn deserialize<D>(deserializer: D) -> Result<NonZero<T>, D::Error>
where
D: Deserializer<'de>,
{
let value = try!(Deserialize::deserialize(deserializer));
if value == Zero::zero() {
return Err(Error::custom("expected a non-zero value"));
unsafe {
let ptr = &value as *const T as *const u8;
if slice::from_raw_parts(ptr, mem::size_of::<T>()).iter().all(|&b| b == 0) {
return Err(Error::custom("expected a non-zero value"));
}
// Waiting for a safe way to construct NonZero<T>:
// https://github.com/rust-lang/rust/issues/27730#issuecomment-269726075
Ok(NonZero::new(value))
}
// Waiting for a safe way to construct NonZero<T>:
// https://github.com/rust-lang/rust/issues/27730#issuecomment-269726075
unsafe { Ok(NonZero::new(value)) }
}
}
+3 -6
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.0")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.3")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
@@ -88,7 +88,7 @@
// discussion of these features please refer to this issue:
//
// https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(nonzero, specialization, zero_one))]
#![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))]
@@ -124,7 +124,7 @@ mod lib {
pub use core::*;
}
pub use self::core::{cmp, iter, mem, ops, str};
pub use self::core::{cmp, iter, mem, ops, slice, str};
pub use self::core::{i8, i16, i32, i64, isize};
pub use self::core::{u8, u16, u32, u64, usize};
pub use self::core::{f32, f64};
@@ -193,9 +193,6 @@ mod lib {
#[cfg(feature = "unstable")]
pub use core::nonzero::{NonZero, Zeroable};
#[cfg(feature = "unstable")]
#[allow(deprecated)] // required for impl Deserialize for NonZero<T>
pub use core::num::Zero;
}
////////////////////////////////////////////////////////////////////////////////
+49
View File
@@ -16,6 +16,7 @@ use de::Unexpected;
#[cfg(any(feature = "std", feature = "collections"))]
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`,
@@ -863,6 +864,54 @@ 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,
+13 -3
View File
@@ -346,11 +346,21 @@ deref_impl!(<T> Serialize for Arc<T> where T: Serialize);
#[cfg(any(feature = "std", feature = "collections"))]
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,
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.0" # remember to update html_root_url
version = "1.0.3" # 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)]"
+59 -12
View File
@@ -795,9 +795,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 +854,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 +942,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 +962,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 +974,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 +983,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.0")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.3")]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
+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 {
+3 -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 {
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "1.0.0" # remember to update html_root_url
version = "1.0.3" # 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.0")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.3")]
#[macro_use]
extern crate serde;
+6 -1
View File
@@ -13,7 +13,7 @@ extern crate serde_derive;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::net;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::time::Duration;
use std::default::Default;
use std::ffi::{CString, OsString};
@@ -710,6 +710,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"),
+85
View File
@@ -751,6 +751,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 +885,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)]