mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-19 18:01:05 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c3eced410f | |||
| 8a630fea7c | |||
| 2e597ed3f0 | |||
| 0963121beb | |||
| 15b2714058 | |||
| 9ce107de25 | |||
| e47284c0e0 | |||
| 800620e2aa | |||
| ba260b0e5f | |||
| 8452e313cc | |||
| deca49315a | |||
| 95407a4ca5 | |||
| 2fe9a860cd | |||
| e67d941b78 | |||
| 552971196d | |||
| 9fc180e62f | |||
| 5b815b7001 | |||
| 8e8694261b |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.12" # remember to update html_root_url
|
version = "1.0.13" # 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"
|
||||||
|
|||||||
+1
-1
@@ -1120,7 +1120,7 @@ pub trait Visitor<'de>: Sized {
|
|||||||
self.visit_i64(v as i64)
|
self.visit_i64(v as i64)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The input contains an `i32`.
|
/// The input contains an `i64`.
|
||||||
///
|
///
|
||||||
/// The default implementation fails with a type error.
|
/// The default implementation fails with a type error.
|
||||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||||
|
|||||||
+1
-1
@@ -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.12")]
|
#![doc(html_root_url = "https://docs.rs/serde/1.0.13")]
|
||||||
|
|
||||||
// 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)]
|
||||||
|
|||||||
@@ -1727,6 +1727,13 @@ pub trait SerializeStruct {
|
|||||||
where
|
where
|
||||||
T: Serialize;
|
T: Serialize;
|
||||||
|
|
||||||
|
/// Indicate that a struct field has been skipped.
|
||||||
|
#[inline]
|
||||||
|
fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
|
||||||
|
let _ = key;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Finish serializing a struct.
|
/// Finish serializing a struct.
|
||||||
fn end(self) -> Result<Self::Ok, Self::Error>;
|
fn end(self) -> Result<Self::Ok, Self::Error>;
|
||||||
}
|
}
|
||||||
@@ -1772,6 +1779,13 @@ pub trait SerializeStructVariant {
|
|||||||
where
|
where
|
||||||
T: Serialize;
|
T: Serialize;
|
||||||
|
|
||||||
|
/// Indicate that a struct variant field has been skipped.
|
||||||
|
#[inline]
|
||||||
|
fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
|
||||||
|
let _ = key;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Finish serializing a struct variant.
|
/// Finish serializing a struct variant.
|
||||||
fn end(self) -> Result<Self::Ok, Self::Error>;
|
fn end(self) -> Result<Self::Ok, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.12" # remember to update html_root_url
|
version = "1.0.13" # 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)]"
|
||||||
@@ -20,5 +20,5 @@ proc-macro = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quote = "0.3.8"
|
quote = "0.3.8"
|
||||||
serde_derive_internals = { version = "=0.15.1", default-features = false, path = "../serde_derive_internals" }
|
serde_derive_internals = { version = "=0.16.0", default-features = false, path = "../serde_derive_internals" }
|
||||||
syn = { version = "0.11", features = ["visit"] }
|
syn = { version = "0.11", features = ["visit"] }
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use std::collections::HashSet;
|
|||||||
|
|
||||||
use syn::{self, visit};
|
use syn::{self, visit};
|
||||||
|
|
||||||
use internals::ast::Container;
|
use internals::ast::{Body, Container};
|
||||||
use internals::attr;
|
use internals::attr;
|
||||||
|
|
||||||
macro_rules! path {
|
macro_rules! path {
|
||||||
@@ -88,7 +88,7 @@ pub fn with_bound<F>(
|
|||||||
bound: &syn::Path,
|
bound: &syn::Path,
|
||||||
) -> syn::Generics
|
) -> syn::Generics
|
||||||
where
|
where
|
||||||
F: Fn(&attr::Field) -> bool,
|
F: Fn(&attr::Field, Option<&attr::Variant>) -> bool,
|
||||||
{
|
{
|
||||||
struct FindTyParams {
|
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
|
||||||
@@ -124,17 +124,27 @@ where
|
|||||||
.map(|ty_param| ty_param.ident.clone())
|
.map(|ty_param| ty_param.ident.clone())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let relevant_tys = cont.body
|
|
||||||
.all_fields()
|
|
||||||
.filter(|&field| filter(&field.attrs))
|
|
||||||
.map(|field| &field.ty);
|
|
||||||
|
|
||||||
let mut visitor = FindTyParams {
|
let mut visitor = FindTyParams {
|
||||||
all_ty_params: all_ty_params,
|
all_ty_params: all_ty_params,
|
||||||
relevant_ty_params: HashSet::new(),
|
relevant_ty_params: HashSet::new(),
|
||||||
};
|
};
|
||||||
for ty in relevant_tys {
|
match cont.body {
|
||||||
visit::walk_ty(&mut visitor, ty);
|
Body::Enum(ref variants) => {
|
||||||
|
for variant in variants.iter() {
|
||||||
|
let relevant_fields = variant
|
||||||
|
.fields
|
||||||
|
.iter()
|
||||||
|
.filter(|field| filter(&field.attrs, Some(&variant.attrs)));
|
||||||
|
for field in relevant_fields {
|
||||||
|
visit::walk_ty(&mut visitor, field.ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Body::Struct(_, ref fields) => {
|
||||||
|
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
|
||||||
|
visit::walk_ty(&mut visitor, field.ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_predicates = generics
|
let new_predicates = generics
|
||||||
|
|||||||
+120
-30
@@ -157,14 +157,17 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
|||||||
// deserialized by us so we do not generate a bound. Fields with a `bound`
|
// deserialized by us so we do not generate a bound. Fields with a `bound`
|
||||||
// attribute specify their own bound so we do not generate one. All other fields
|
// attribute specify their own bound so we do not generate one. All other fields
|
||||||
// may need a `T: Deserialize` bound where T is the type of the field.
|
// may need a `T: Deserialize` bound where T is the type of the field.
|
||||||
fn needs_deserialize_bound(attrs: &attr::Field) -> bool {
|
fn needs_deserialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
|
||||||
!attrs.skip_deserializing() && attrs.deserialize_with().is_none() && attrs.de_bound().is_none()
|
!field.skip_deserializing() &&
|
||||||
|
field.deserialize_with().is_none() &&
|
||||||
|
field.de_bound().is_none() &&
|
||||||
|
variant.map_or(true, |variant| variant.deserialize_with().is_none())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fields with a `default` attribute (not `default=...`), and fields with a
|
// Fields with a `default` attribute (not `default=...`), and fields with a
|
||||||
// `skip_deserializing` attribute that do not also have `default=...`.
|
// `skip_deserializing` attribute that do not also have `default=...`.
|
||||||
fn requires_default(attrs: &attr::Field) -> bool {
|
fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bool {
|
||||||
attrs.default() == &attr::Default::Default
|
field.default() == &attr::Default::Default
|
||||||
}
|
}
|
||||||
|
|
||||||
// The union of lifetimes borrowed by each field of the container.
|
// The union of lifetimes borrowed by each field of the container.
|
||||||
@@ -372,7 +375,7 @@ fn deserialize_seq(
|
|||||||
quote!(try!(_serde::de::SeqAccess::next_element::<#field_ty>(&mut __seq)))
|
quote!(try!(_serde::de::SeqAccess::next_element::<#field_ty>(&mut __seq)))
|
||||||
}
|
}
|
||||||
Some(path) => {
|
Some(path) => {
|
||||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(
|
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(
|
||||||
params, field.ty, path);
|
params, field.ty, path);
|
||||||
quote!({
|
quote!({
|
||||||
#wrapper
|
#wrapper
|
||||||
@@ -428,7 +431,7 @@ fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &F
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(path) => {
|
Some(path) => {
|
||||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
|
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||||
quote!({
|
quote!({
|
||||||
#wrapper
|
#wrapper
|
||||||
try!(<#wrapper_ty as _serde::Deserialize>::deserialize(__e)).value
|
try!(<#wrapper_ty as _serde::Deserialize>::deserialize(__e)).value
|
||||||
@@ -1084,6 +1087,16 @@ fn deserialize_externally_tagged_variant(
|
|||||||
variant: &Variant,
|
variant: &Variant,
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
|
if let Some(path) = variant.attrs.deserialize_with() {
|
||||||
|
let (wrapper, wrapper_ty, unwrap_fn) =
|
||||||
|
wrap_deserialize_variant_with(params, &variant, path);
|
||||||
|
return quote_block! {
|
||||||
|
#wrapper
|
||||||
|
_serde::export::Result::map(
|
||||||
|
_serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let variant_ident = &variant.ident;
|
let variant_ident = &variant.ident;
|
||||||
|
|
||||||
match variant.style {
|
match variant.style {
|
||||||
@@ -1112,6 +1125,10 @@ fn deserialize_internally_tagged_variant(
|
|||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
deserializer: Tokens,
|
deserializer: Tokens,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
|
if variant.attrs.deserialize_with().is_some() {
|
||||||
|
return deserialize_untagged_variant(params, variant, cattrs, deserializer);
|
||||||
|
}
|
||||||
|
|
||||||
let variant_ident = &variant.ident;
|
let variant_ident = &variant.ident;
|
||||||
|
|
||||||
match variant.style {
|
match variant.style {
|
||||||
@@ -1137,6 +1154,16 @@ fn deserialize_untagged_variant(
|
|||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
deserializer: Tokens,
|
deserializer: Tokens,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
|
if let Some(path) = variant.attrs.deserialize_with() {
|
||||||
|
let (wrapper, wrapper_ty, unwrap_fn) =
|
||||||
|
wrap_deserialize_variant_with(params, &variant, path);
|
||||||
|
return quote_block! {
|
||||||
|
#wrapper
|
||||||
|
_serde::export::Result::map(
|
||||||
|
<#wrapper_ty as _serde::Deserialize>::deserialize(#deserializer), #unwrap_fn)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let variant_ident = &variant.ident;
|
let variant_ident = &variant.ident;
|
||||||
|
|
||||||
match variant.style {
|
match variant.style {
|
||||||
@@ -1198,7 +1225,7 @@ fn deserialize_externally_tagged_newtype_variant(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(path) => {
|
Some(path) => {
|
||||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
|
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||||
quote_block! {
|
quote_block! {
|
||||||
#wrapper
|
#wrapper
|
||||||
_serde::export::Result::map(
|
_serde::export::Result::map(
|
||||||
@@ -1226,7 +1253,7 @@ fn deserialize_untagged_newtype_variant(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(path) => {
|
Some(path) => {
|
||||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
|
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||||
quote_block! {
|
quote_block! {
|
||||||
#wrapper
|
#wrapper
|
||||||
_serde::export::Result::map(
|
_serde::export::Result::map(
|
||||||
@@ -1384,26 +1411,27 @@ fn deserialize_identifier(
|
|||||||
"field identifier"
|
"field identifier"
|
||||||
};
|
};
|
||||||
|
|
||||||
let visit_index = if is_variant {
|
let index_expecting = if is_variant {
|
||||||
let variant_indices = 0u32..;
|
"variant"
|
||||||
let fallthrough_msg = format!("variant index 0 <= i < {}", fields.len());
|
|
||||||
let visit_index = quote! {
|
|
||||||
fn visit_u32<__E>(self, __value: u32) -> _serde::export::Result<Self::Value, __E>
|
|
||||||
where __E: _serde::de::Error
|
|
||||||
{
|
|
||||||
match __value {
|
|
||||||
#(
|
|
||||||
#variant_indices => _serde::export::Ok(#constructors),
|
|
||||||
)*
|
|
||||||
_ => _serde::export::Err(_serde::de::Error::invalid_value(
|
|
||||||
_serde::de::Unexpected::Unsigned(__value as u64),
|
|
||||||
&#fallthrough_msg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Some(visit_index)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
"field"
|
||||||
|
};
|
||||||
|
|
||||||
|
let variant_indices = 0u64..;
|
||||||
|
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
|
||||||
|
let visit_index = quote! {
|
||||||
|
fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
|
||||||
|
where __E: _serde::de::Error
|
||||||
|
{
|
||||||
|
match __value {
|
||||||
|
#(
|
||||||
|
#variant_indices => _serde::export::Ok(#constructors),
|
||||||
|
)*
|
||||||
|
_ => _serde::export::Err(_serde::de::Error::invalid_value(
|
||||||
|
_serde::de::Unexpected::Unsigned(__value as u64),
|
||||||
|
&#fallthrough_msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let bytes_to_str = if fallthrough.is_some() {
|
let bytes_to_str = if fallthrough.is_some() {
|
||||||
@@ -1528,7 +1556,7 @@ fn deserialize_map(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(path) => {
|
Some(path) => {
|
||||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(
|
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(
|
||||||
params, field.ty, path);
|
params, field.ty, path);
|
||||||
quote!({
|
quote!({
|
||||||
#wrapper
|
#wrapper
|
||||||
@@ -1661,7 +1689,7 @@ fn field_i(i: usize) -> Ident {
|
|||||||
/// in a trait to prevent it from accessing the internal `Deserialize` state.
|
/// in a trait to prevent it from accessing the internal `Deserialize` state.
|
||||||
fn wrap_deserialize_with(
|
fn wrap_deserialize_with(
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
field_ty: &syn::Ty,
|
value_ty: Tokens,
|
||||||
deserialize_with: &syn::Path,
|
deserialize_with: &syn::Path,
|
||||||
) -> (Tokens, Tokens) {
|
) -> (Tokens, Tokens) {
|
||||||
let this = ¶ms.this;
|
let this = ¶ms.this;
|
||||||
@@ -1669,7 +1697,7 @@ fn wrap_deserialize_with(
|
|||||||
|
|
||||||
let wrapper = quote! {
|
let wrapper = quote! {
|
||||||
struct __DeserializeWith #de_impl_generics #where_clause {
|
struct __DeserializeWith #de_impl_generics #where_clause {
|
||||||
value: #field_ty,
|
value: #value_ty,
|
||||||
phantom: _serde::export::PhantomData<#this #ty_generics>,
|
phantom: _serde::export::PhantomData<#this #ty_generics>,
|
||||||
lifetime: _serde::export::PhantomData<&'de ()>,
|
lifetime: _serde::export::PhantomData<&'de ()>,
|
||||||
}
|
}
|
||||||
@@ -1692,6 +1720,68 @@ fn wrap_deserialize_with(
|
|||||||
(wrapper, wrapper_ty)
|
(wrapper, wrapper_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wrap_deserialize_field_with(
|
||||||
|
params: &Parameters,
|
||||||
|
field_ty: &syn::Ty,
|
||||||
|
deserialize_with: &syn::Path,
|
||||||
|
) -> (Tokens, Tokens) {
|
||||||
|
wrap_deserialize_with(params, quote!(#field_ty), deserialize_with)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_deserialize_variant_with(
|
||||||
|
params: &Parameters,
|
||||||
|
variant: &Variant,
|
||||||
|
deserialize_with: &syn::Path,
|
||||||
|
) -> (Tokens, Tokens, Tokens) {
|
||||||
|
let this = ¶ms.this;
|
||||||
|
let variant_ident = &variant.ident;
|
||||||
|
|
||||||
|
let field_tys = variant.fields.iter().map(|field| field.ty);
|
||||||
|
let (wrapper, wrapper_ty) =
|
||||||
|
wrap_deserialize_with(params, quote!((#(#field_tys),*)), deserialize_with);
|
||||||
|
|
||||||
|
let field_access = (0..variant.fields.len()).map(|n| Ident::new(format!("{}", n)));
|
||||||
|
let unwrap_fn = match variant.style {
|
||||||
|
Style::Struct => {
|
||||||
|
let field_idents = variant.fields.iter().map(|field| field.ident.as_ref().unwrap());
|
||||||
|
quote! {
|
||||||
|
{
|
||||||
|
|__wrap| {
|
||||||
|
#this::#variant_ident { #(#field_idents: __wrap.value.#field_access),* }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Style::Tuple => {
|
||||||
|
quote! {
|
||||||
|
{
|
||||||
|
|__wrap| {
|
||||||
|
#this::#variant_ident(#(__wrap.value.#field_access),*)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Style::Newtype => {
|
||||||
|
quote! {
|
||||||
|
{
|
||||||
|
|__wrap| {
|
||||||
|
#this::#variant_ident(__wrap.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Style::Unit => {
|
||||||
|
quote! {
|
||||||
|
{
|
||||||
|
|__wrap| { #this::#variant_ident }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(wrapper, wrapper_ty, unwrap_fn)
|
||||||
|
}
|
||||||
|
|
||||||
fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
|
fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
|
||||||
match *field.attrs.default() {
|
match *field.attrs.default() {
|
||||||
attr::Default::Default => {
|
attr::Default::Default => {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
//!
|
//!
|
||||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.12")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.13")]
|
||||||
|
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
|
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
|
||||||
|
|||||||
+160
-52
@@ -143,12 +143,16 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fields with a `skip_serializing` or `serialize_with` attribute are not
|
// Fields with a `skip_serializing` or `serialize_with` attribute, or which
|
||||||
// serialized by us so we do not generate a bound. Fields with a `bound`
|
// belong to a variant with a `serialize_with` attribute, are not serialized by
|
||||||
// attribute specify their own bound so we do not generate one. All other fields
|
// us so we do not generate a bound. Fields with a `bound` attribute specify
|
||||||
// may need a `T: Serialize` bound where T is the type of the field.
|
// their own bound so we do not generate one. All other fields may need a `T:
|
||||||
fn needs_serialize_bound(attrs: &attr::Field) -> bool {
|
// Serialize` bound where T is the type of the field.
|
||||||
!attrs.skip_serializing() && attrs.serialize_with().is_none() && attrs.ser_bound().is_none()
|
fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
|
||||||
|
!field.skip_serializing() &&
|
||||||
|
field.serialize_with().is_none() &&
|
||||||
|
field.ser_bound().is_none() &&
|
||||||
|
variant.map_or(true, |variant| variant.serialize_with().is_none())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
||||||
@@ -203,7 +207,7 @@ fn serialize_newtype_struct(
|
|||||||
|
|
||||||
let mut field_expr = get_field(params, field, 0);
|
let mut field_expr = get_field(params, field, 0);
|
||||||
if let Some(path) = field.attrs.serialize_with() {
|
if let Some(path) = field.attrs.serialize_with() {
|
||||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
quote_expr! {
|
quote_expr! {
|
||||||
@@ -242,6 +246,7 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
|
|||||||
params,
|
params,
|
||||||
false,
|
false,
|
||||||
quote!(_serde::ser::SerializeStruct::serialize_field),
|
quote!(_serde::ser::SerializeStruct::serialize_field),
|
||||||
|
quote!(_serde::ser::SerializeStruct::skip_field),
|
||||||
);
|
);
|
||||||
|
|
||||||
let type_name = cattrs.name().serialize_name();
|
let type_name = cattrs.name().serialize_name();
|
||||||
@@ -395,6 +400,19 @@ fn serialize_externally_tagged_variant(
|
|||||||
let type_name = cattrs.name().serialize_name();
|
let type_name = cattrs.name().serialize_name();
|
||||||
let variant_name = variant.attrs.name().serialize_name();
|
let variant_name = variant.attrs.name().serialize_name();
|
||||||
|
|
||||||
|
if let Some(path) = variant.attrs.serialize_with() {
|
||||||
|
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||||
|
return quote_expr! {
|
||||||
|
_serde::Serializer::serialize_newtype_variant(
|
||||||
|
__serializer,
|
||||||
|
#type_name,
|
||||||
|
#variant_index,
|
||||||
|
#variant_name,
|
||||||
|
#ser,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
match variant.style {
|
match variant.style {
|
||||||
Style::Unit => {
|
Style::Unit => {
|
||||||
quote_expr! {
|
quote_expr! {
|
||||||
@@ -410,7 +428,7 @@ fn serialize_externally_tagged_variant(
|
|||||||
let field = &variant.fields[0];
|
let field = &variant.fields[0];
|
||||||
let mut field_expr = quote!(__field0);
|
let mut field_expr = quote!(__field0);
|
||||||
if let Some(path) = field.attrs.serialize_with() {
|
if let Some(path) = field.attrs.serialize_with() {
|
||||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
quote_expr! {
|
quote_expr! {
|
||||||
@@ -460,6 +478,20 @@ fn serialize_internally_tagged_variant(
|
|||||||
let enum_ident_str = params.type_name();
|
let enum_ident_str = params.type_name();
|
||||||
let variant_ident_str = variant.ident.as_ref();
|
let variant_ident_str = variant.ident.as_ref();
|
||||||
|
|
||||||
|
if let Some(path) = variant.attrs.serialize_with() {
|
||||||
|
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||||
|
return quote_expr! {
|
||||||
|
_serde::private::ser::serialize_tagged_newtype(
|
||||||
|
__serializer,
|
||||||
|
#enum_ident_str,
|
||||||
|
#variant_ident_str,
|
||||||
|
#tag,
|
||||||
|
#variant_name,
|
||||||
|
#ser,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
match variant.style {
|
match variant.style {
|
||||||
Style::Unit => {
|
Style::Unit => {
|
||||||
quote_block! {
|
quote_block! {
|
||||||
@@ -474,7 +506,7 @@ fn serialize_internally_tagged_variant(
|
|||||||
let field = &variant.fields[0];
|
let field = &variant.fields[0];
|
||||||
let mut field_expr = quote!(__field0);
|
let mut field_expr = quote!(__field0);
|
||||||
if let Some(path) = field.attrs.serialize_with() {
|
if let Some(path) = field.attrs.serialize_with() {
|
||||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
quote_expr! {
|
quote_expr! {
|
||||||
@@ -515,44 +547,57 @@ fn serialize_adjacently_tagged_variant(
|
|||||||
let variant_name = variant.attrs.name().serialize_name();
|
let variant_name = variant.attrs.name().serialize_name();
|
||||||
|
|
||||||
let inner = Stmts(
|
let inner = Stmts(
|
||||||
match variant.style {
|
if let Some(path) = variant.attrs.serialize_with() {
|
||||||
Style::Unit => {
|
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||||
return quote_block! {
|
quote_expr! {
|
||||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
_serde::Serialize::serialize(#ser, __serializer)
|
||||||
__serializer, #type_name, 1));
|
|
||||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
|
||||||
&mut __struct, #tag, #variant_name));
|
|
||||||
_serde::ser::SerializeStruct::end(__struct)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
Style::Newtype => {
|
} else {
|
||||||
let field = &variant.fields[0];
|
match variant.style {
|
||||||
let mut field_expr = quote!(__field0);
|
Style::Unit => {
|
||||||
if let Some(path) = field.attrs.serialize_with() {
|
return quote_block! {
|
||||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
||||||
|
__serializer, #type_name, 1));
|
||||||
|
try!(_serde::ser::SerializeStruct::serialize_field(
|
||||||
|
&mut __struct, #tag, #variant_name));
|
||||||
|
_serde::ser::SerializeStruct::end(__struct)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
Style::Newtype => {
|
||||||
|
let field = &variant.fields[0];
|
||||||
|
let mut field_expr = quote!(__field0);
|
||||||
|
if let Some(path) = field.attrs.serialize_with() {
|
||||||
|
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||||
|
}
|
||||||
|
|
||||||
quote_expr! {
|
quote_expr! {
|
||||||
_serde::Serialize::serialize(#field_expr, __serializer)
|
_serde::Serialize::serialize(#field_expr, __serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Style::Tuple => {
|
||||||
|
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
|
||||||
|
}
|
||||||
|
Style::Struct => {
|
||||||
|
serialize_struct_variant(
|
||||||
|
StructVariant::Untagged,
|
||||||
|
params,
|
||||||
|
&variant.fields,
|
||||||
|
&variant_name,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Style::Tuple => {
|
|
||||||
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
|
|
||||||
}
|
|
||||||
Style::Struct => {
|
|
||||||
serialize_struct_variant(
|
|
||||||
StructVariant::Untagged,
|
|
||||||
params,
|
|
||||||
&variant.fields,
|
|
||||||
&variant_name,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let fields_ty = variant.fields.iter().map(|f| &f.ty);
|
let fields_ty = variant.fields.iter().map(|f| &f.ty);
|
||||||
let ref fields_ident: Vec<_> = match variant.style {
|
let ref fields_ident: Vec<_> = match variant.style {
|
||||||
Style::Unit => unreachable!(),
|
Style::Unit => {
|
||||||
|
if variant.attrs.serialize_with().is_some() {
|
||||||
|
vec![]
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
Style::Newtype => vec![Ident::new("__field0")],
|
Style::Newtype => vec![Ident::new("__field0")],
|
||||||
Style::Tuple => {
|
Style::Tuple => {
|
||||||
(0..variant.fields.len())
|
(0..variant.fields.len())
|
||||||
@@ -576,7 +621,11 @@ fn serialize_adjacently_tagged_variant(
|
|||||||
|
|
||||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||||
|
|
||||||
let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a");
|
let wrapper_generics = if let Style::Unit = variant.style {
|
||||||
|
params.generics.clone()
|
||||||
|
} else {
|
||||||
|
bound::with_lifetime_bound(¶ms.generics, "'__a")
|
||||||
|
};
|
||||||
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
@@ -612,6 +661,13 @@ fn serialize_untagged_variant(
|
|||||||
variant: &Variant,
|
variant: &Variant,
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
|
if let Some(path) = variant.attrs.serialize_with() {
|
||||||
|
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||||
|
return quote_expr! {
|
||||||
|
_serde::Serialize::serialize(#ser, __serializer)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
match variant.style {
|
match variant.style {
|
||||||
Style::Unit => {
|
Style::Unit => {
|
||||||
quote_expr! {
|
quote_expr! {
|
||||||
@@ -622,7 +678,7 @@ fn serialize_untagged_variant(
|
|||||||
let field = &variant.fields[0];
|
let field = &variant.fields[0];
|
||||||
let mut field_expr = quote!(__field0);
|
let mut field_expr = quote!(__field0);
|
||||||
if let Some(path) = field.attrs.serialize_with() {
|
if let Some(path) = field.attrs.serialize_with() {
|
||||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
quote_expr! {
|
quote_expr! {
|
||||||
@@ -707,15 +763,23 @@ fn serialize_struct_variant<'a>(
|
|||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let method = match context {
|
let (method, skip_method) = match context {
|
||||||
StructVariant::ExternallyTagged { .. } => {
|
StructVariant::ExternallyTagged { .. } => {
|
||||||
quote!(_serde::ser::SerializeStructVariant::serialize_field)
|
(
|
||||||
|
quote!(_serde::ser::SerializeStructVariant::serialize_field),
|
||||||
|
quote!(_serde::ser::SerializeStructVariant::skip_field),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
StructVariant::InternallyTagged { .. } |
|
StructVariant::InternallyTagged { .. } |
|
||||||
StructVariant::Untagged => quote!(_serde::ser::SerializeStruct::serialize_field),
|
StructVariant::Untagged => {
|
||||||
|
(
|
||||||
|
quote!(_serde::ser::SerializeStruct::serialize_field),
|
||||||
|
quote!(_serde::ser::SerializeStruct::skip_field),
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let serialize_fields = serialize_struct_visitor(fields, params, true, method);
|
let serialize_fields = serialize_struct_visitor(fields, params, true, method, skip_method);
|
||||||
|
|
||||||
let mut serialized_fields = fields
|
let mut serialized_fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
@@ -808,7 +872,7 @@ fn serialize_tuple_struct_visitor(
|
|||||||
.map(|path| quote!(#path(#field_expr)));
|
.map(|path| quote!(#path(#field_expr)));
|
||||||
|
|
||||||
if let Some(path) = field.attrs.serialize_with() {
|
if let Some(path) = field.attrs.serialize_with() {
|
||||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ser = quote! {
|
let ser = quote! {
|
||||||
@@ -829,6 +893,7 @@ fn serialize_struct_visitor(
|
|||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
is_enum: bool,
|
is_enum: bool,
|
||||||
func: Tokens,
|
func: Tokens,
|
||||||
|
skip_func: Tokens,
|
||||||
) -> Vec<Tokens> {
|
) -> Vec<Tokens> {
|
||||||
fields
|
fields
|
||||||
.iter()
|
.iter()
|
||||||
@@ -850,7 +915,7 @@ fn serialize_struct_visitor(
|
|||||||
.map(|path| quote!(#path(#field_expr)));
|
.map(|path| quote!(#path(#field_expr)));
|
||||||
|
|
||||||
if let Some(path) = field.attrs.serialize_with() {
|
if let Some(path) = field.attrs.serialize_with() {
|
||||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr)
|
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ser = quote! {
|
let ser = quote! {
|
||||||
@@ -859,28 +924,71 @@ fn serialize_struct_visitor(
|
|||||||
|
|
||||||
match skip {
|
match skip {
|
||||||
None => ser,
|
None => ser,
|
||||||
Some(skip) => quote!(if !#skip { #ser }),
|
Some(skip) => {
|
||||||
|
quote! {
|
||||||
|
if !#skip {
|
||||||
|
#ser
|
||||||
|
} else {
|
||||||
|
try!(#skip_func(&mut __serde_state, #key_expr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_serialize_with(
|
fn wrap_serialize_field_with(
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
field_ty: &syn::Ty,
|
field_ty: &syn::Ty,
|
||||||
serialize_with: &syn::Path,
|
serialize_with: &syn::Path,
|
||||||
value: Tokens,
|
field_expr: Tokens,
|
||||||
|
) -> Tokens {
|
||||||
|
wrap_serialize_with(params,
|
||||||
|
serialize_with,
|
||||||
|
&[field_ty],
|
||||||
|
&[quote!(#field_expr)])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_serialize_variant_with(
|
||||||
|
params: &Parameters,
|
||||||
|
serialize_with: &syn::Path,
|
||||||
|
variant: &Variant,
|
||||||
|
) -> Tokens {
|
||||||
|
let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect();
|
||||||
|
let field_exprs: Vec<_> = variant.fields.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, field)| {
|
||||||
|
let id = field.ident.as_ref().map_or_else(|| Ident::new(format!("__field{}", i)),
|
||||||
|
|id| id.clone());
|
||||||
|
quote!(#id)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
wrap_serialize_with(params, serialize_with, field_tys.as_slice(), field_exprs.as_slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap_serialize_with(
|
||||||
|
params: &Parameters,
|
||||||
|
serialize_with: &syn::Path,
|
||||||
|
field_tys: &[&syn::Ty],
|
||||||
|
field_exprs: &[Tokens],
|
||||||
) -> Tokens {
|
) -> Tokens {
|
||||||
let this = ¶ms.this;
|
let this = ¶ms.this;
|
||||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||||
|
|
||||||
let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a");
|
let wrapper_generics = if field_exprs.len() == 0 {
|
||||||
|
params.generics.clone()
|
||||||
|
} else {
|
||||||
|
bound::with_lifetime_bound(¶ms.generics, "'__a")
|
||||||
|
};
|
||||||
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
||||||
|
|
||||||
|
let field_access = (0..field_exprs.len()).map(|n| Ident::new(format!("{}", n)));
|
||||||
|
|
||||||
quote!({
|
quote!({
|
||||||
struct __SerializeWith #wrapper_impl_generics #where_clause {
|
struct __SerializeWith #wrapper_impl_generics #where_clause {
|
||||||
value: &'__a #field_ty,
|
values: (#(&'__a #field_tys, )*),
|
||||||
phantom: _serde::export::PhantomData<#this #ty_generics>,
|
phantom: _serde::export::PhantomData<#this #ty_generics>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -888,12 +996,12 @@ fn wrap_serialize_with(
|
|||||||
fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||||
where __S: _serde::Serializer
|
where __S: _serde::Serializer
|
||||||
{
|
{
|
||||||
#serialize_with(self.value, __s)
|
#serialize_with(#(self.values.#field_access, )* __s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__SerializeWith {
|
&__SerializeWith {
|
||||||
value: #value,
|
values: (#(#field_exprs, )*),
|
||||||
phantom: _serde::export::PhantomData::<#this #ty_generics>,
|
phantom: _serde::export::PhantomData::<#this #ty_generics>,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive_internals"
|
name = "serde_derive_internals"
|
||||||
version = "0.15.1" # remember to update html_root_url
|
version = "0.16.0" # remember to update html_root_url
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
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."
|
||||||
|
|||||||
@@ -510,6 +510,8 @@ pub struct Variant {
|
|||||||
skip_deserializing: bool,
|
skip_deserializing: bool,
|
||||||
skip_serializing: bool,
|
skip_serializing: bool,
|
||||||
other: bool,
|
other: bool,
|
||||||
|
serialize_with: Option<syn::Path>,
|
||||||
|
deserialize_with: Option<syn::Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Variant {
|
impl Variant {
|
||||||
@@ -520,6 +522,8 @@ impl Variant {
|
|||||||
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
||||||
let mut rename_all = Attr::none(cx, "rename_all");
|
let mut rename_all = Attr::none(cx, "rename_all");
|
||||||
let mut other = BoolAttr::none(cx, "other");
|
let mut other = BoolAttr::none(cx, "other");
|
||||||
|
let mut serialize_with = Attr::none(cx, "serialize_with");
|
||||||
|
let mut deserialize_with = Attr::none(cx, "deserialize_with");
|
||||||
|
|
||||||
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
|
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
|
||||||
for meta_item in meta_items {
|
for meta_item in meta_items {
|
||||||
@@ -569,6 +573,32 @@ impl Variant {
|
|||||||
other.set_true();
|
other.set_true();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(with = "...")]`
|
||||||
|
MetaItem(NameValue(ref name, ref lit)) if name == "with" => {
|
||||||
|
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||||
|
let mut ser_path = path.clone();
|
||||||
|
ser_path.segments.push("serialize".into());
|
||||||
|
serialize_with.set(ser_path);
|
||||||
|
let mut de_path = path;
|
||||||
|
de_path.segments.push("deserialize".into());
|
||||||
|
deserialize_with.set(de_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(serialize_with = "...")]`
|
||||||
|
MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => {
|
||||||
|
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||||
|
serialize_with.set(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(deserialize_with = "...")]`
|
||||||
|
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => {
|
||||||
|
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||||
|
deserialize_with.set(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MetaItem(ref meta_item) => {
|
MetaItem(ref meta_item) => {
|
||||||
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
|
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
|
||||||
}
|
}
|
||||||
@@ -595,6 +625,8 @@ impl Variant {
|
|||||||
skip_deserializing: skip_deserializing.get(),
|
skip_deserializing: skip_deserializing.get(),
|
||||||
skip_serializing: skip_serializing.get(),
|
skip_serializing: skip_serializing.get(),
|
||||||
other: other.get(),
|
other: other.get(),
|
||||||
|
serialize_with: serialize_with.get(),
|
||||||
|
deserialize_with: deserialize_with.get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -626,6 +658,14 @@ impl Variant {
|
|||||||
pub fn other(&self) -> bool {
|
pub fn other(&self) -> bool {
|
||||||
self.other
|
self.other
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serialize_with(&self) -> Option<&syn::Path> {
|
||||||
|
self.serialize_with.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_with(&self) -> Option<&syn::Path> {
|
||||||
|
self.deserialize_with.as_ref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents field attribute information
|
/// Represents field attribute information
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ pub enum RenameRule {
|
|||||||
ScreamingSnakeCase,
|
ScreamingSnakeCase,
|
||||||
/// Rename direct children to "kebab-case" style.
|
/// Rename direct children to "kebab-case" style.
|
||||||
KebabCase,
|
KebabCase,
|
||||||
|
/// Rename direct children to "SCREAMING-KEBAB-CASE" style.
|
||||||
|
ScreamingKebabCase
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenameRule {
|
impl RenameRule {
|
||||||
@@ -47,6 +49,7 @@ impl RenameRule {
|
|||||||
}
|
}
|
||||||
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
|
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
|
||||||
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
|
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
|
||||||
|
ScreamingKebabCase => ScreamingSnakeCase.apply_to_variant(variant).replace('_', "-")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +77,7 @@ impl RenameRule {
|
|||||||
}
|
}
|
||||||
ScreamingSnakeCase => field.to_ascii_uppercase(),
|
ScreamingSnakeCase => field.to_ascii_uppercase(),
|
||||||
KebabCase => field.replace('_', "-"),
|
KebabCase => field.replace('_', "-"),
|
||||||
|
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,6 +93,7 @@ impl FromStr for RenameRule {
|
|||||||
"snake_case" => Ok(SnakeCase),
|
"snake_case" => Ok(SnakeCase),
|
||||||
"SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
|
"SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
|
||||||
"kebab-case" => Ok(KebabCase),
|
"kebab-case" => Ok(KebabCase),
|
||||||
|
"SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase),
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,12 +101,12 @@ impl FromStr for RenameRule {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rename_variants() {
|
fn rename_variants() {
|
||||||
for &(original, lower, camel, snake, screaming, kebab) in
|
for &(original, lower, camel, snake, screaming, kebab, screaming_kebab) in
|
||||||
&[
|
&[
|
||||||
("Outcome", "outcome", "outcome", "outcome", "OUTCOME", "outcome"),
|
("Outcome", "outcome", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"),
|
||||||
("VeryTasty", "verytasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty"),
|
("VeryTasty", "verytasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"),
|
||||||
("A", "a", "a", "a", "A", "a"),
|
("A", "a", "a", "a", "A", "a", "A"),
|
||||||
("Z42", "z42", "z42", "z42", "Z42", "z42"),
|
("Z42", "z42", "z42", "z42", "Z42", "z42", "Z42"),
|
||||||
] {
|
] {
|
||||||
assert_eq!(None.apply_to_variant(original), original);
|
assert_eq!(None.apply_to_variant(original), original);
|
||||||
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
||||||
@@ -110,17 +115,18 @@ fn rename_variants() {
|
|||||||
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
||||||
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
|
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
|
||||||
assert_eq!(KebabCase.apply_to_variant(original), kebab);
|
assert_eq!(KebabCase.apply_to_variant(original), kebab);
|
||||||
|
assert_eq!(ScreamingKebabCase.apply_to_variant(original), screaming_kebab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rename_fields() {
|
fn rename_fields() {
|
||||||
for &(original, pascal, camel, screaming, kebab) in
|
for &(original, pascal, camel, screaming, kebab, screaming_kebab) in
|
||||||
&[
|
&[
|
||||||
("outcome", "Outcome", "outcome", "OUTCOME", "outcome"),
|
("outcome", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"),
|
||||||
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty"),
|
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"),
|
||||||
("a", "A", "a", "A", "a"),
|
("a", "A", "a", "A", "a", "A"),
|
||||||
("z42", "Z42", "z42", "Z42", "z42"),
|
("z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
||||||
] {
|
] {
|
||||||
assert_eq!(None.apply_to_field(original), original);
|
assert_eq!(None.apply_to_field(original), original);
|
||||||
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
||||||
@@ -128,5 +134,6 @@ fn rename_fields() {
|
|||||||
assert_eq!(SnakeCase.apply_to_field(original), original);
|
assert_eq!(SnakeCase.apply_to_field(original), original);
|
||||||
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
|
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
|
||||||
assert_eq!(KebabCase.apply_to_field(original), kebab);
|
assert_eq!(KebabCase.apply_to_field(original), kebab);
|
||||||
|
assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use Ctxt;
|
|||||||
pub fn check(cx: &Ctxt, cont: &Container) {
|
pub fn check(cx: &Ctxt, cont: &Container) {
|
||||||
check_getter(cx, cont);
|
check_getter(cx, cont);
|
||||||
check_identifier(cx, cont);
|
check_identifier(cx, cont);
|
||||||
|
check_variant_skip_attrs(cx, cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Getters are only allowed inside structs (not enums) with the `remote`
|
/// Getters are only allowed inside structs (not enums) with the `remote`
|
||||||
@@ -94,3 +95,58 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Skip-(de)serializing attributes are not allowed on variants marked
|
||||||
|
/// (de)serialize_with.
|
||||||
|
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
||||||
|
let variants = match cont.body {
|
||||||
|
Body::Enum(ref variants) => variants,
|
||||||
|
Body::Struct(_, _) => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for variant in variants.iter() {
|
||||||
|
if variant.attrs.serialize_with().is_some() {
|
||||||
|
if variant.attrs.skip_serializing() {
|
||||||
|
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||||
|
#[serde(skip_serializing)]", variant.ident));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, field) in variant.fields.iter().enumerate() {
|
||||||
|
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i),
|
||||||
|
|ident| format!("`{}`", ident));
|
||||||
|
|
||||||
|
if field.attrs.skip_serializing() {
|
||||||
|
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||||
|
a field {} marked with #[serde(skip_serializing)]",
|
||||||
|
variant.ident, ident));
|
||||||
|
}
|
||||||
|
|
||||||
|
if field.attrs.skip_serializing_if().is_some() {
|
||||||
|
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||||
|
a field {} marked with #[serde(skip_serializing_if)]",
|
||||||
|
variant.ident, ident));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if variant.attrs.deserialize_with().is_some() {
|
||||||
|
if variant.attrs.skip_deserializing() {
|
||||||
|
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] and \
|
||||||
|
#[serde(skip_deserializing)]", variant.ident));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, field) in variant.fields.iter().enumerate() {
|
||||||
|
if field.attrs.skip_deserializing() {
|
||||||
|
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i),
|
||||||
|
|ident| format!("`{}`", ident));
|
||||||
|
|
||||||
|
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] \
|
||||||
|
and a field {} marked with #[serde(skip_deserializing)]",
|
||||||
|
variant.ident, ident));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// 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.15.1")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.16.0")]
|
||||||
|
|
||||||
extern crate syn;
|
extern crate syn;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_test"
|
name = "serde_test"
|
||||||
version = "1.0.12" # remember to update html_root_url
|
version = "1.0.13" # 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"
|
||||||
|
|||||||
@@ -155,7 +155,7 @@
|
|||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.12")]
|
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.13")]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: variant `Newtype` cannot have both #[serde(deserialize_with)] and a field 0 marked with #[serde(skip_deserializing)]
|
||||||
|
enum Enum {
|
||||||
|
#[serde(deserialize_with = "deserialize_some_newtype_variant")]
|
||||||
|
Newtype(#[serde(skip_deserializing)] String),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: variant `Struct` cannot have both #[serde(deserialize_with)] and a field `f1` marked with #[serde(skip_deserializing)]
|
||||||
|
enum Enum {
|
||||||
|
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||||
|
Struct {
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
f1: String,
|
||||||
|
f2: u8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: variant `Tuple` cannot have both #[serde(deserialize_with)] and a field 0 marked with #[serde(skip_deserializing)]
|
||||||
|
enum Enum {
|
||||||
|
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||||
|
Tuple(#[serde(skip_deserializing)] String, u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: variant `Unit` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]
|
||||||
|
enum Enum {
|
||||||
|
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
Unit,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: variant `Newtype` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing)]
|
||||||
|
enum Enum {
|
||||||
|
#[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||||
|
Newtype(#[serde(skip_serializing)] String),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: variant `Newtype` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing_if)]
|
||||||
|
enum Enum {
|
||||||
|
#[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||||
|
Newtype(#[serde(skip_serializing_if = "always")] String),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing)]
|
||||||
|
enum Enum {
|
||||||
|
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
|
Struct {
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
f1: String,
|
||||||
|
f2: u8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing_if)]
|
||||||
|
enum Enum {
|
||||||
|
#[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||||
|
Struct {
|
||||||
|
#[serde(skip_serializing_if = "always")]
|
||||||
|
f1: String,
|
||||||
|
f2: u8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: variant `Tuple` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing)]
|
||||||
|
enum Enum {
|
||||||
|
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
|
Tuple(#[serde(skip_serializing)] String, u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: variant `Tuple` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing_if)]
|
||||||
|
enum Enum {
|
||||||
|
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
|
Tuple(#[serde(skip_serializing_if = "always")] String, u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2017 Serde Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||||
|
//~^ HELP: variant `Unit` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]
|
||||||
|
enum Enum {
|
||||||
|
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
Unit,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
||||||
@@ -6,11 +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.
|
||||||
|
|
||||||
|
#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
use self::serde::{Serialize, Serializer, Deserialize, Deserializer};
|
use self::serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||||
|
use self::serde::de::{self, Unexpected};
|
||||||
|
|
||||||
extern crate serde_test;
|
extern crate serde_test;
|
||||||
use self::serde_test::{Token, assert_tokens, assert_ser_tokens, assert_de_tokens,
|
use self::serde_test::{Token, assert_tokens, assert_ser_tokens, assert_de_tokens,
|
||||||
@@ -811,6 +814,145 @@ fn test_serialize_with_enum() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
enum WithVariant {
|
||||||
|
#[serde(serialize_with="serialize_unit_variant_as_i8")]
|
||||||
|
#[serde(deserialize_with="deserialize_i8_as_unit_variant")]
|
||||||
|
Unit,
|
||||||
|
|
||||||
|
#[serde(serialize_with="SerializeWith::serialize_with")]
|
||||||
|
#[serde(deserialize_with="DeserializeWith::deserialize_with")]
|
||||||
|
Newtype(i32),
|
||||||
|
|
||||||
|
#[serde(serialize_with="serialize_variant_as_string")]
|
||||||
|
#[serde(deserialize_with="deserialize_string_as_variant")]
|
||||||
|
Tuple(String, u8),
|
||||||
|
|
||||||
|
#[serde(serialize_with="serialize_variant_as_string")]
|
||||||
|
#[serde(deserialize_with="deserialize_string_as_variant")]
|
||||||
|
Struct {
|
||||||
|
f1: String,
|
||||||
|
f2: u8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit_variant_as_i8<S>(serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_i8(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_i8_as_unit_variant<'de, D>(deserializer: D) -> Result<(), D::Error>
|
||||||
|
where D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let n = i8::deserialize(deserializer)?;
|
||||||
|
match n {
|
||||||
|
0 => Ok(()),
|
||||||
|
_ => Err(de::Error::invalid_value(Unexpected::Signed(n as i64), &"0")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_variant_as_string<S>(f1: &str,
|
||||||
|
f2: &u8,
|
||||||
|
serializer: S)
|
||||||
|
-> Result<S::Ok, S::Error>
|
||||||
|
where S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(format!("{};{:?}", f1, f2).as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_string_as_variant<'de, D>(deserializer: D) -> Result<(String, u8), D::Error>
|
||||||
|
where D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let s = String::deserialize(deserializer)?;
|
||||||
|
let mut pieces = s.split(';');
|
||||||
|
let f1 = match pieces.next() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => return Err(de::Error::invalid_length(0, &"2")),
|
||||||
|
};
|
||||||
|
let f2 = match pieces.next() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => return Err(de::Error::invalid_length(1, &"2")),
|
||||||
|
};
|
||||||
|
let f2 = match f2.parse() {
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(de::Error::invalid_value(Unexpected::Str(f2), &"an 8-bit signed integer"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok((f1.into(), f2))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize_with_variant() {
|
||||||
|
assert_ser_tokens(
|
||||||
|
&WithVariant::Unit,
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant { name: "WithVariant", variant: "Unit" },
|
||||||
|
Token::I8(0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_ser_tokens(
|
||||||
|
&WithVariant::Newtype(123),
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant { name: "WithVariant", variant: "Newtype" },
|
||||||
|
Token::Bool(true),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_ser_tokens(
|
||||||
|
&WithVariant::Tuple("hello".into(), 0),
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant { name: "WithVariant", variant: "Tuple" },
|
||||||
|
Token::Str("hello;0"),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_ser_tokens(
|
||||||
|
&WithVariant::Struct { f1: "world".into(), f2: 1 },
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant { name: "WithVariant", variant: "Struct" },
|
||||||
|
Token::Str("world;1"),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialize_with_variant() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&WithVariant::Unit,
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant { name: "WithVariant", variant: "Unit" },
|
||||||
|
Token::I8(0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&WithVariant::Newtype(123),
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant { name: "WithVariant", variant: "Newtype" },
|
||||||
|
Token::Bool(true),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&WithVariant::Tuple("hello".into(), 0),
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant { name: "WithVariant", variant: "Tuple" },
|
||||||
|
Token::Str("hello;0"),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&WithVariant::Struct { f1: "world".into(), f2: 1 },
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant { name: "WithVariant", variant: "Struct" },
|
||||||
|
Token::Str("world;1"),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Deserialize)]
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
struct DeserializeWithStruct<B>
|
struct DeserializeWithStruct<B>
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -521,6 +521,15 @@ declare_tests! {
|
|||||||
Token::I32(2),
|
Token::I32(2),
|
||||||
Token::MapEnd,
|
Token::MapEnd,
|
||||||
],
|
],
|
||||||
|
Struct { a: 1, b: 2, c: 0 } => &[
|
||||||
|
Token::Map { len: Some(3) },
|
||||||
|
Token::U32(0),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::U32(1),
|
||||||
|
Token::I32(2),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
Struct { a: 1, b: 2, c: 0 } => &[
|
Struct { a: 1, b: 2, c: 0 } => &[
|
||||||
Token::Struct { name: "Struct", len: 3 },
|
Token::Struct { name: "Struct", len: 3 },
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
|
|||||||
@@ -373,6 +373,124 @@ fn test_gen() {
|
|||||||
#[serde(with = "vis::SDef")]
|
#[serde(with = "vis::SDef")]
|
||||||
s: vis::S,
|
s: vis::S,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
enum ExternallyTaggedVariantWith {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Normal { f1: String },
|
||||||
|
|
||||||
|
#[serde(serialize_with = "ser_x")]
|
||||||
|
#[serde(deserialize_with = "de_x")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Newtype(X),
|
||||||
|
|
||||||
|
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
|
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Tuple(String, u8),
|
||||||
|
|
||||||
|
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
|
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Struct {
|
||||||
|
f1: String,
|
||||||
|
f2: u8,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||||
|
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Unit,
|
||||||
|
}
|
||||||
|
assert_ser::<ExternallyTaggedVariantWith>();
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(tag = "t")]
|
||||||
|
enum InternallyTaggedVariantWith {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Normal { f1: String },
|
||||||
|
|
||||||
|
#[serde(serialize_with = "ser_x")]
|
||||||
|
#[serde(deserialize_with = "de_x")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Newtype(X),
|
||||||
|
|
||||||
|
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
|
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Struct {
|
||||||
|
f1: String,
|
||||||
|
f2: u8,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||||
|
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Unit,
|
||||||
|
}
|
||||||
|
assert_ser::<InternallyTaggedVariantWith>();
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(tag = "t", content = "c")]
|
||||||
|
enum AdjacentlyTaggedVariantWith {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Normal { f1: String },
|
||||||
|
|
||||||
|
#[serde(serialize_with = "ser_x")]
|
||||||
|
#[serde(deserialize_with = "de_x")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Newtype(X),
|
||||||
|
|
||||||
|
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
|
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Tuple(String, u8),
|
||||||
|
|
||||||
|
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
|
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Struct {
|
||||||
|
f1: String,
|
||||||
|
f2: u8,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||||
|
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Unit,
|
||||||
|
}
|
||||||
|
assert_ser::<AdjacentlyTaggedVariantWith>();
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum UntaggedVariantWith {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Normal { f1: String },
|
||||||
|
|
||||||
|
#[serde(serialize_with = "ser_x")]
|
||||||
|
#[serde(deserialize_with = "de_x")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Newtype(X),
|
||||||
|
|
||||||
|
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
|
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Tuple(String, u8),
|
||||||
|
|
||||||
|
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
|
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Struct {
|
||||||
|
f1: String,
|
||||||
|
f2: u8,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||||
|
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Unit,
|
||||||
|
}
|
||||||
|
assert_ser::<UntaggedVariantWith>();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@@ -414,3 +532,29 @@ impl DeserializeWith for X {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serialize_some_unit_variant<S>(_: S) -> StdResult<S::Ok, S::Error>
|
||||||
|
where S: Serializer,
|
||||||
|
{
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_some_unit_variant<'de, D>(_: D) -> StdResult<(), D::Error>
|
||||||
|
where D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize_some_other_variant<S>(_: &str, _: &u8, _: S) -> StdResult<S::Ok, S::Error>
|
||||||
|
where S: Serializer,
|
||||||
|
{
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_some_other_variant<'de, D>(_: D) -> StdResult<(String, u8), D::Error>
|
||||||
|
where D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_zero(n: &u8) -> bool { *n == 0 }
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ fn test_variant_identifier() {
|
|||||||
Bbb,
|
Bbb,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert_de_tokens(&V::Aaa, &[Token::U8(0)]);
|
||||||
|
assert_de_tokens(&V::Aaa, &[Token::U16(0)]);
|
||||||
assert_de_tokens(&V::Aaa, &[Token::U32(0)]);
|
assert_de_tokens(&V::Aaa, &[Token::U32(0)]);
|
||||||
|
assert_de_tokens(&V::Aaa, &[Token::U64(0)]);
|
||||||
assert_de_tokens(&V::Aaa, &[Token::Str("Aaa")]);
|
assert_de_tokens(&V::Aaa, &[Token::Str("Aaa")]);
|
||||||
assert_de_tokens(&V::Aaa, &[Token::Bytes(b"Aaa")]);
|
assert_de_tokens(&V::Aaa, &[Token::Bytes(b"Aaa")]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1149,7 +1149,7 @@ fn test_rename_all() {
|
|||||||
SerializeMap {
|
SerializeMap {
|
||||||
serialize: bool,
|
serialize: bool,
|
||||||
serialize_seq: bool,
|
serialize_seq: bool,
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
@@ -1159,6 +1159,13 @@ fn test_rename_all() {
|
|||||||
serialize_seq: bool,
|
serialize_seq: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
|
#[serde(rename_all = "SCREAMING-KEBAB-CASE")]
|
||||||
|
struct ScreamingKebab {
|
||||||
|
serialize: bool,
|
||||||
|
serialize_seq: bool,
|
||||||
|
}
|
||||||
|
|
||||||
assert_tokens(
|
assert_tokens(
|
||||||
&E::Serialize {
|
&E::Serialize {
|
||||||
serialize: true,
|
serialize: true,
|
||||||
@@ -1218,4 +1225,19 @@ fn test_rename_all() {
|
|||||||
Token::StructEnd,
|
Token::StructEnd,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&ScreamingKebab {
|
||||||
|
serialize: true,
|
||||||
|
serialize_seq: true,
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Struct { name: "ScreamingKebab", len: 2 },
|
||||||
|
Token::Str("SERIALIZE"),
|
||||||
|
Token::Bool(true),
|
||||||
|
Token::Str("SERIALIZE-SEQ"),
|
||||||
|
Token::Bool(true),
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user