Compare commits

...

23 Commits

Author SHA1 Message Date
David Tolnay 4b00de0e22 Release 1.0.14 2017-09-09 12:50:57 -07:00
David Tolnay 8403fa018e Merge pull request #1052 from serde-rs/static
Special case for 'static fields
2017-09-09 12:50:11 -07:00
David Tolnay 0e9f1b42de Merge pull request #1053 from serde-rs/cast
Fix trivial numeric cast in visit_u64
2017-09-09 12:43:46 -07:00
David Tolnay 0085d05e55 Special case for 'static fields 2017-09-09 12:39:14 -07:00
David Tolnay 2eed855bff Fix trivial numeric cast in visit_u64 2017-09-09 12:37:00 -07:00
David Tolnay c3eced410f Release 1.0.13 2017-09-09 11:40:31 -07:00
David Tolnay 8a630fea7c Suppress cast_lossless lint in test suite 2017-09-09 11:08:19 -07:00
David Tolnay 2e597ed3f0 Remove unused functions in with-variant tests
Macro expansion fails before it would generate code to call any of these.
2017-09-09 10:58:32 -07:00
David Tolnay 0963121beb Support consolidated with attribute for variants 2017-09-09 10:50:40 -07:00
David Tolnay 15b2714058 Merge pull request #1015 from spinda/with-variant
implement (de)serialize_with for variants
2017-09-09 10:49:24 -07:00
David Tolnay 9ce107de25 Merge pull request 963 from sfackler/u64-identifier
Conflicts:
    serde_derive/src/de.rs
2017-09-08 21:35:41 -07:00
David Tolnay e47284c0e0 Merge pull request #1043 from greyblake/screaming-kebab-case
SCREAMING-KEBAB-CASE support
2017-09-08 21:30:01 -07:00
David Tolnay 800620e2aa Merge pull request #1022 from sfackler/skip-field
Inform serializers about skipped fields.
2017-09-08 09:47:43 -07:00
David Tolnay ba260b0e5f Merge pull request #1045 from xfix/patch-1
Fix a type name typo in visit_i64 documentation
2017-09-07 12:07:03 -07:00
Konrad Borowski 8452e313cc Fix a type name typo in visit_i64 documentation 2017-09-07 19:53:07 +02:00
Steven Fackler deca49315a Inline skip_field 2017-09-05 22:36:42 -07:00
Steven Fackler 95407a4ca5 Support field ident deserialization from u32 2017-09-05 21:55:33 -07:00
Steven Fackler 2fe9a860cd Inform serializers about skipped fields.
Closes #960.
2017-09-05 21:55:33 -07:00
Sergey Potapov e67d941b78 Support for SCREAMING-KEBAB-CASE 2017-09-05 22:07:08 +02:00
Michael Smith 552971196d Fix Clippy errors in variant serialize_with tests 2017-08-16 12:04:39 -07:00
Michael Smith 9fc180e62f Implement deserialize_with for variants
Complements variant serialize_with and closes #1013.
2017-08-14 14:41:05 -07:00
Michael Smith 5b815b7001 Implement serialize_with for variants
As discussed in #1013, serialize_with functions attached to variants receive an
argument for each inner value contained within the variant. Internally such a
function is wired up to the serializer as if the variant were a newtype variant.
2017-08-14 11:17:08 -07:00
Steven Fackler 8e8694261b Fix identifier deserialization from non-u32
Closes #962
2017-06-19 20:23:14 -07:00
32 changed files with 1094 additions and 160 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.12" # remember to update html_root_url
version = "1.0.14" # 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"
+1 -1
View File
@@ -1120,7 +1120,7 @@ pub trait Visitor<'de>: Sized {
self.visit_i64(v as i64)
}
/// The input contains an `i32`.
/// The input contains an `i64`.
///
/// The default implementation fails with a type error.
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
+1 -1
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.12")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.14")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
+14
View File
@@ -1727,6 +1727,13 @@ pub trait SerializeStruct {
where
T: Serialize;
/// Indicate that a struct field has been skipped.
#[inline]
fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
let _ = key;
Ok(())
}
/// Finish serializing a struct.
fn end(self) -> Result<Self::Ok, Self::Error>;
}
@@ -1772,6 +1779,13 @@ pub trait SerializeStructVariant {
where
T: Serialize;
/// Indicate that a struct variant field has been skipped.
#[inline]
fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
let _ = key;
Ok(())
}
/// Finish serializing a struct variant.
fn end(self) -> Result<Self::Ok, Self::Error>;
}
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.12" # remember to update html_root_url
version = "1.0.14" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -20,5 +20,5 @@ proc-macro = true
[dependencies]
quote = "0.3.8"
serde_derive_internals = { version = "=0.15.1", default-features = false, path = "../serde_derive_internals" }
serde_derive_internals = { version = "=0.16.0", default-features = false, path = "../serde_derive_internals" }
syn = { version = "0.11", features = ["visit"] }
+20 -10
View File
@@ -10,12 +10,12 @@ use std::collections::HashSet;
use syn::{self, visit};
use internals::ast::Container;
use internals::ast::{Body, Container};
use internals::attr;
macro_rules! path {
($($path:tt)+) => {
syn::parse_path(stringify!($($path)+)).unwrap()
syn::parse_path(quote!($($path)+).as_str()).unwrap()
};
}
@@ -88,7 +88,7 @@ pub fn with_bound<F>(
bound: &syn::Path,
) -> syn::Generics
where
F: Fn(&attr::Field) -> bool,
F: Fn(&attr::Field, Option<&attr::Variant>) -> bool,
{
struct FindTyParams {
// Set of all generic type parameters on the current struct (A, B, C in
@@ -124,17 +124,27 @@ where
.map(|ty_param| ty_param.ident.clone())
.collect();
let relevant_tys = cont.body
.all_fields()
.filter(|&field| filter(&field.attrs))
.map(|field| &field.ty);
let mut visitor = FindTyParams {
all_ty_params: all_ty_params,
relevant_ty_params: HashSet::new(),
};
for ty in relevant_tys {
visit::walk_ty(&mut visitor, ty);
match cont.body {
Body::Enum(ref variants) => {
for variant in variants.iter() {
let relevant_fields = variant
.fields
.iter()
.filter(|field| filter(&field.attrs, Some(&variant.attrs)));
for field in relevant_fields {
visit::walk_ty(&mut visitor, field.ty);
}
}
}
Body::Struct(_, ref fields) => {
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
visit::walk_ty(&mut visitor, field.ty);
}
}
}
let new_predicates = generics
+207 -77
View File
@@ -26,13 +26,14 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(&params);
let dummy_const = Ident::new(format!("_IMPL_DESERIALIZE_FOR_{}", ident));
let body = Stmts(deserialize_body(&cont, &params));
let delife = params.borrowed.de_lifetime();
let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis;
quote! {
impl #de_impl_generics #ident #ty_generics #where_clause {
#vis fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error>
where __D: _serde::Deserializer<'de>
where __D: _serde::Deserializer<#delife>
{
#body
}
@@ -41,9 +42,9 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
} else {
quote! {
#[automatically_derived]
impl #de_impl_generics _serde::Deserialize<'de> for #ident #ty_generics #where_clause {
impl #de_impl_generics _serde::Deserialize<#delife> for #ident #ty_generics #where_clause {
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
where __D: _serde::Deserializer<'de>
where __D: _serde::Deserializer<#delife>
{
#body
}
@@ -75,7 +76,7 @@ struct Parameters {
/// Lifetimes borrowed from the deserializer. These will become bounds on
/// the `'de` lifetime of the deserializer.
borrowed: BTreeSet<syn::Lifetime>,
borrowed: BorrowedLifetimes,
/// At least one field has a serde(getter) attribute, implying that the
/// remote type has a private field.
@@ -89,8 +90,8 @@ impl Parameters {
Some(remote) => remote.clone(),
None => cont.ident.clone().into(),
};
let generics = build_generics(cont);
let borrowed = borrowed_lifetimes(cont);
let generics = build_generics(cont, &borrowed);
let has_getter = cont.body.has_getter();
Parameters {
@@ -107,20 +108,12 @@ impl Parameters {
fn type_name(&self) -> &str {
self.this.segments.last().unwrap().ident.as_ref()
}
fn de_lifetime_def(&self) -> syn::LifetimeDef {
syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de"),
bounds: self.borrowed.iter().cloned().collect(),
}
}
}
// All the generics in the input, plus a bound `T: Deserialize` for each generic
// field type that will be deserialized by us, plus a bound `T: Default` for
// each generic field type that will be set to a default value.
fn build_generics(cont: &Container) -> syn::Generics {
fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generics {
let generics = bound::without_defaults(cont.generics);
let generics = bound::with_where_predicates_from_fields(cont, &generics, attr::Field::de_bound);
@@ -136,11 +129,12 @@ fn build_generics(cont: &Container) -> syn::Generics {
attr::Default::Path(_) => generics,
};
let delife = borrowed.de_lifetime();
let generics = bound::with_bound(
cont,
&generics,
needs_deserialize_bound,
&path!(_serde::Deserialize<'de>),
&path!(_serde::Deserialize<#delife>),
);
bound::with_bound(
@@ -157,14 +151,44 @@ fn build_generics(cont: &Container) -> syn::Generics {
// deserialized by us so we do not generate a bound. Fields with a `bound`
// attribute specify their own bound so we do not generate one. All other fields
// may need a `T: Deserialize` bound where T is the type of the field.
fn needs_deserialize_bound(attrs: &attr::Field) -> bool {
!attrs.skip_deserializing() && attrs.deserialize_with().is_none() && attrs.de_bound().is_none()
fn needs_deserialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
!field.skip_deserializing() &&
field.deserialize_with().is_none() &&
field.de_bound().is_none() &&
variant.map_or(true, |variant| variant.deserialize_with().is_none())
}
// Fields with a `default` attribute (not `default=...`), and fields with a
// `skip_deserializing` attribute that do not also have `default=...`.
fn requires_default(attrs: &attr::Field) -> bool {
attrs.default() == &attr::Default::Default
fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bool {
field.default() == &attr::Default::Default
}
enum BorrowedLifetimes {
Borrowed(BTreeSet<syn::Lifetime>),
Static,
}
impl BorrowedLifetimes {
fn de_lifetime(&self) -> syn::Lifetime {
match *self {
BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new("'de"),
BorrowedLifetimes::Static => syn::Lifetime::new("'static"),
}
}
fn de_lifetime_def(&self) -> Option<syn::LifetimeDef> {
match *self {
BorrowedLifetimes::Borrowed(ref bounds) => {
Some(syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de"),
bounds: bounds.iter().cloned().collect(),
})
}
BorrowedLifetimes::Static => None,
}
}
}
// The union of lifetimes borrowed by each field of the container.
@@ -173,12 +197,19 @@ fn requires_default(attrs: &attr::Field) -> bool {
// lifetimes `'a` and `'b` are borrowed but `'c` is not, the impl is:
//
// impl<'de: 'a + 'b, 'a, 'b, 'c> Deserialize<'de> for S<'a, 'b, 'c>
fn borrowed_lifetimes(cont: &Container) -> BTreeSet<syn::Lifetime> {
//
// If any borrowed lifetime is `'static`, then `'de: 'static` would be redundant
// and we use plain `'static` instead of `'de`.
fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes {
let mut lifetimes = BTreeSet::new();
for field in cont.body.all_fields() {
lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned());
}
lifetimes
if lifetimes.iter().any(|b| b.ident == "'static") {
BorrowedLifetimes::Static
} else {
BorrowedLifetimes::Borrowed(lifetimes)
}
}
fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
@@ -257,6 +288,7 @@ fn deserialize_tuple(
) -> Fragment {
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
// If there are getters (implying private fields), construct the local type
// and use an `Into` conversion to get the remote type. If there are no
@@ -318,10 +350,10 @@ fn deserialize_tuple(
quote_block! {
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
@@ -332,7 +364,7 @@ fn deserialize_tuple(
#[inline]
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de>
where __A: _serde::de::SeqAccess<#delife>
{
#visit_seq
}
@@ -372,7 +404,7 @@ fn deserialize_seq(
quote!(try!(_serde::de::SeqAccess::next_element::<#field_ty>(&mut __seq)))
}
Some(path) => {
let (wrapper, wrapper_ty) = wrap_deserialize_with(
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(
params, field.ty, path);
quote!({
#wrapper
@@ -420,6 +452,8 @@ fn deserialize_seq(
}
fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &Field) -> Tokens {
let delife = params.borrowed.de_lifetime();
let value = match field.attrs.deserialize_with() {
None => {
let field_ty = &field.ty;
@@ -428,7 +462,7 @@ fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &F
}
}
Some(path) => {
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
quote!({
#wrapper
try!(<#wrapper_ty as _serde::Deserialize>::deserialize(__e)).value
@@ -447,7 +481,7 @@ fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &F
quote! {
#[inline]
fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result<Self::Value, __E::Error>
where __E: _serde::Deserializer<'de>
where __E: _serde::Deserializer<#delife>
{
_serde::export::Ok(#result)
}
@@ -466,6 +500,7 @@ fn deserialize_struct(
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
// If there are getters (implying private fields), construct the local type
// and use an `Into` conversion to get the remote type. If there are no
@@ -531,7 +566,7 @@ fn deserialize_struct(
Some(quote! {
#[inline]
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de>
where __A: _serde::de::SeqAccess<#delife>
{
#visit_seq
}
@@ -543,10 +578,10 @@ fn deserialize_struct(
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
@@ -557,7 +592,7 @@ fn deserialize_struct(
#[inline]
fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::MapAccess<'de>
where __A: _serde::de::MapAccess<#delife>
{
#visit_map
}
@@ -594,6 +629,7 @@ fn deserialize_externally_tagged_enum(
) -> Fragment {
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
let type_name = cattrs.name().deserialize_name();
@@ -659,10 +695,10 @@ fn deserialize_externally_tagged_enum(
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
@@ -670,7 +706,7 @@ fn deserialize_externally_tagged_enum(
}
fn visit_enum<__A>(self, __data: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::EnumAccess<'de>
where __A: _serde::de::EnumAccess<#delife>
{
#match_variant
}
@@ -751,6 +787,7 @@ fn deserialize_adjacently_tagged_enum(
) -> Fragment {
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
let variant_names_idents: Vec<_> = variants
.iter()
@@ -910,14 +947,14 @@ fn deserialize_adjacently_tagged_enum(
struct __Seed #de_impl_generics #where_clause {
field: __Field,
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::DeserializeSeed<'de> for __Seed #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Seed #de_ty_generics #where_clause {
type Value = #this #ty_generics;
fn deserialize<__D>(self, __deserializer: __D) -> _serde::export::Result<Self::Value, __D::Error>
where __D: _serde::Deserializer<'de>
where __D: _serde::Deserializer<#delife>
{
match self.field {
#(#variant_arms)*
@@ -927,10 +964,10 @@ fn deserialize_adjacently_tagged_enum(
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::Visitor<'de> for __Visitor #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this #ty_generics;
fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result {
@@ -938,7 +975,7 @@ fn deserialize_adjacently_tagged_enum(
}
fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::MapAccess<'de>
where __A: _serde::de::MapAccess<#delife>
{
// Visit the first relevant key.
match #next_relevant_key {
@@ -1002,7 +1039,7 @@ fn deserialize_adjacently_tagged_enum(
}
fn visit_seq<__A>(self, mut __seq: __A) -> _serde::export::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de>
where __A: _serde::de::SeqAccess<#delife>
{
// Visit the first element - the tag.
match try!(_serde::de::SeqAccess::next_element(&mut __seq)) {
@@ -1084,6 +1121,16 @@ fn deserialize_externally_tagged_variant(
variant: &Variant,
cattrs: &attr::Container,
) -> Fragment {
if let Some(path) = variant.attrs.deserialize_with() {
let (wrapper, wrapper_ty, unwrap_fn) =
wrap_deserialize_variant_with(params, &variant, path);
return quote_block! {
#wrapper
_serde::export::Result::map(
_serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn)
};
}
let variant_ident = &variant.ident;
match variant.style {
@@ -1112,6 +1159,10 @@ fn deserialize_internally_tagged_variant(
cattrs: &attr::Container,
deserializer: Tokens,
) -> Fragment {
if variant.attrs.deserialize_with().is_some() {
return deserialize_untagged_variant(params, variant, cattrs, deserializer);
}
let variant_ident = &variant.ident;
match variant.style {
@@ -1137,6 +1188,16 @@ fn deserialize_untagged_variant(
cattrs: &attr::Container,
deserializer: Tokens,
) -> Fragment {
if let Some(path) = variant.attrs.deserialize_with() {
let (wrapper, wrapper_ty, unwrap_fn) =
wrap_deserialize_variant_with(params, &variant, path);
return quote_block! {
#wrapper
_serde::export::Result::map(
<#wrapper_ty as _serde::Deserialize>::deserialize(#deserializer), #unwrap_fn)
};
}
let variant_ident = &variant.ident;
match variant.style {
@@ -1198,7 +1259,7 @@ fn deserialize_externally_tagged_newtype_variant(
}
}
Some(path) => {
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
quote_block! {
#wrapper
_serde::export::Result::map(
@@ -1226,7 +1287,7 @@ fn deserialize_untagged_newtype_variant(
}
}
Some(path) => {
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
quote_block! {
#wrapper
_serde::export::Result::map(
@@ -1339,6 +1400,7 @@ fn deserialize_custom_identifier(
};
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
let visitor_impl =
Stmts(deserialize_identifier(this.clone(), &names_idents, is_variant, fallthrough),);
@@ -1347,10 +1409,10 @@ fn deserialize_custom_identifier(
struct __FieldVisitor #de_impl_generics #where_clause {
marker: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::de::Visitor<'de> for __FieldVisitor #de_ty_generics #where_clause {
impl #de_impl_generics _serde::de::Visitor<#delife> for __FieldVisitor #de_ty_generics #where_clause {
type Value = #this #ty_generics;
#visitor_impl
@@ -1384,26 +1446,27 @@ fn deserialize_identifier(
"field identifier"
};
let visit_index = if is_variant {
let variant_indices = 0u32..;
let fallthrough_msg = format!("variant index 0 <= i < {}", fields.len());
let visit_index = quote! {
fn visit_u32<__E>(self, __value: u32) -> _serde::export::Result<Self::Value, __E>
where __E: _serde::de::Error
{
match __value {
#(
#variant_indices => _serde::export::Ok(#constructors),
)*
_ => _serde::export::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value as u64),
&#fallthrough_msg))
}
}
};
Some(visit_index)
let index_expecting = if is_variant {
"variant"
} else {
None
"field"
};
let variant_indices = 0u64..;
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
let visit_index = quote! {
fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
where __E: _serde::de::Error
{
match __value {
#(
#variant_indices => _serde::export::Ok(#constructors),
)*
_ => _serde::export::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&#fallthrough_msg))
}
}
};
let bytes_to_str = if fallthrough.is_some() {
@@ -1528,7 +1591,7 @@ fn deserialize_map(
}
}
Some(path) => {
let (wrapper, wrapper_ty) = wrap_deserialize_with(
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(
params, field.ty, path);
quote!({
#wrapper
@@ -1661,22 +1724,23 @@ fn field_i(i: usize) -> Ident {
/// in a trait to prevent it from accessing the internal `Deserialize` state.
fn wrap_deserialize_with(
params: &Parameters,
field_ty: &syn::Ty,
value_ty: Tokens,
deserialize_with: &syn::Path,
) -> (Tokens, Tokens) {
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
let delife = params.borrowed.de_lifetime();
let wrapper = quote! {
struct __DeserializeWith #de_impl_generics #where_clause {
value: #field_ty,
value: #value_ty,
phantom: _serde::export::PhantomData<#this #ty_generics>,
lifetime: _serde::export::PhantomData<&'de ()>,
lifetime: _serde::export::PhantomData<&#delife ()>,
}
impl #de_impl_generics _serde::Deserialize<'de> for __DeserializeWith #de_ty_generics #where_clause {
impl #de_impl_generics _serde::Deserialize<#delife> for __DeserializeWith #de_ty_generics #where_clause {
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
where __D: _serde::Deserializer<'de>
where __D: _serde::Deserializer<#delife>
{
_serde::export::Ok(__DeserializeWith {
value: try!(#deserialize_with(__deserializer)),
@@ -1692,6 +1756,68 @@ fn wrap_deserialize_with(
(wrapper, wrapper_ty)
}
fn wrap_deserialize_field_with(
params: &Parameters,
field_ty: &syn::Ty,
deserialize_with: &syn::Path,
) -> (Tokens, Tokens) {
wrap_deserialize_with(params, quote!(#field_ty), deserialize_with)
}
fn wrap_deserialize_variant_with(
params: &Parameters,
variant: &Variant,
deserialize_with: &syn::Path,
) -> (Tokens, Tokens, Tokens) {
let this = &params.this;
let variant_ident = &variant.ident;
let field_tys = variant.fields.iter().map(|field| field.ty);
let (wrapper, wrapper_ty) =
wrap_deserialize_with(params, quote!((#(#field_tys),*)), deserialize_with);
let field_access = (0..variant.fields.len()).map(|n| Ident::new(format!("{}", n)));
let unwrap_fn = match variant.style {
Style::Struct => {
let field_idents = variant.fields.iter().map(|field| field.ident.as_ref().unwrap());
quote! {
{
|__wrap| {
#this::#variant_ident { #(#field_idents: __wrap.value.#field_access),* }
}
}
}
}
Style::Tuple => {
quote! {
{
|__wrap| {
#this::#variant_ident(#(__wrap.value.#field_access),*)
}
}
}
}
Style::Newtype => {
quote! {
{
|__wrap| {
#this::#variant_ident(__wrap.value)
}
}
}
}
Style::Unit => {
quote! {
{
|__wrap| { #this::#variant_ident }
}
}
}
};
(wrapper, wrapper_ty, unwrap_fn)
}
fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
match *field.attrs.default() {
attr::Default::Default => {
@@ -1732,20 +1858,24 @@ struct DeImplGenerics<'a>(&'a Parameters);
impl<'a> ToTokens for DeImplGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
let mut generics = self.0.generics.clone();
generics.lifetimes.insert(0, self.0.de_lifetime_def());
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
generics.lifetimes.insert(0, de_lifetime);
}
let (impl_generics, _, _) = generics.split_for_impl();
impl_generics.to_tokens(tokens);
}
}
struct DeTyGenerics<'a>(&'a syn::Generics);
struct DeTyGenerics<'a>(&'a Parameters);
impl<'a> ToTokens for DeTyGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
let mut generics = self.0.clone();
generics
.lifetimes
.insert(0, syn::LifetimeDef::new("'de"));
let mut generics = self.0.generics.clone();
if self.0.borrowed.de_lifetime_def().is_some() {
generics
.lifetimes
.insert(0, syn::LifetimeDef::new("'de"));
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
}
@@ -1754,7 +1884,7 @@ impl<'a> ToTokens for DeTyGenerics<'a> {
fn split_with_de_lifetime(params: &Parameters,)
-> (DeImplGenerics, DeTyGenerics, syn::TyGenerics, &syn::WhereClause) {
let de_impl_generics = DeImplGenerics(&params);
let de_ty_generics = DeTyGenerics(&params.generics);
let de_ty_generics = DeTyGenerics(&params);
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
(de_impl_generics, de_ty_generics, ty_generics, where_clause)
}
+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.12")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.14")]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
+160 -52
View File
@@ -143,12 +143,16 @@ fn build_generics(cont: &Container) -> syn::Generics {
}
}
// Fields with a `skip_serializing` or `serialize_with` attribute are not
// serialized by us so we do not generate a bound. Fields with a `bound`
// attribute specify their own bound so we do not generate one. All other fields
// may need a `T: Serialize` bound where T is the type of the field.
fn needs_serialize_bound(attrs: &attr::Field) -> bool {
!attrs.skip_serializing() && attrs.serialize_with().is_none() && attrs.ser_bound().is_none()
// Fields with a `skip_serializing` or `serialize_with` attribute, or which
// belong to a variant with a `serialize_with` attribute, are not serialized by
// us so we do not generate a bound. Fields with a `bound` attribute specify
// their own bound so we do not generate one. All other fields may need a `T:
// Serialize` bound where T is the type of the field.
fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
!field.skip_serializing() &&
field.serialize_with().is_none() &&
field.ser_bound().is_none() &&
variant.map_or(true, |variant| variant.serialize_with().is_none())
}
fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
@@ -203,7 +207,7 @@ fn serialize_newtype_struct(
let mut field_expr = get_field(params, field, 0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
}
quote_expr! {
@@ -242,6 +246,7 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
params,
false,
quote!(_serde::ser::SerializeStruct::serialize_field),
quote!(_serde::ser::SerializeStruct::skip_field),
);
let type_name = cattrs.name().serialize_name();
@@ -395,6 +400,19 @@ fn serialize_externally_tagged_variant(
let type_name = cattrs.name().serialize_name();
let variant_name = variant.attrs.name().serialize_name();
if let Some(path) = variant.attrs.serialize_with() {
let ser = wrap_serialize_variant_with(params, path, &variant);
return quote_expr! {
_serde::Serializer::serialize_newtype_variant(
__serializer,
#type_name,
#variant_index,
#variant_name,
#ser,
)
};
}
match variant.style {
Style::Unit => {
quote_expr! {
@@ -410,7 +428,7 @@ fn serialize_externally_tagged_variant(
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
}
quote_expr! {
@@ -460,6 +478,20 @@ fn serialize_internally_tagged_variant(
let enum_ident_str = params.type_name();
let variant_ident_str = variant.ident.as_ref();
if let Some(path) = variant.attrs.serialize_with() {
let ser = wrap_serialize_variant_with(params, path, &variant);
return quote_expr! {
_serde::private::ser::serialize_tagged_newtype(
__serializer,
#enum_ident_str,
#variant_ident_str,
#tag,
#variant_name,
#ser,
)
};
}
match variant.style {
Style::Unit => {
quote_block! {
@@ -474,7 +506,7 @@ fn serialize_internally_tagged_variant(
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
}
quote_expr! {
@@ -515,44 +547,57 @@ fn serialize_adjacently_tagged_variant(
let variant_name = variant.attrs.name().serialize_name();
let inner = Stmts(
match variant.style {
Style::Unit => {
return quote_block! {
let mut __struct = try!(_serde::Serializer::serialize_struct(
__serializer, #type_name, 1));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name));
_serde::ser::SerializeStruct::end(__struct)
};
if let Some(path) = variant.attrs.serialize_with() {
let ser = wrap_serialize_variant_with(params, path, &variant);
quote_expr! {
_serde::Serialize::serialize(#ser, __serializer)
}
Style::Newtype => {
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
} else {
match variant.style {
Style::Unit => {
return quote_block! {
let mut __struct = try!(_serde::Serializer::serialize_struct(
__serializer, #type_name, 1));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name));
_serde::ser::SerializeStruct::end(__struct)
};
}
Style::Newtype => {
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
}
quote_expr! {
_serde::Serialize::serialize(#field_expr, __serializer)
quote_expr! {
_serde::Serialize::serialize(#field_expr, __serializer)
}
}
Style::Tuple => {
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
}
Style::Struct => {
serialize_struct_variant(
StructVariant::Untagged,
params,
&variant.fields,
&variant_name,
)
}
}
Style::Tuple => {
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
}
Style::Struct => {
serialize_struct_variant(
StructVariant::Untagged,
params,
&variant.fields,
&variant_name,
)
}
},
);
let fields_ty = variant.fields.iter().map(|f| &f.ty);
let ref fields_ident: Vec<_> = match variant.style {
Style::Unit => unreachable!(),
Style::Unit => {
if variant.attrs.serialize_with().is_some() {
vec![]
} else {
unreachable!()
}
}
Style::Newtype => vec![Ident::new("__field0")],
Style::Tuple => {
(0..variant.fields.len())
@@ -576,7 +621,11 @@ fn serialize_adjacently_tagged_variant(
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
let wrapper_generics = bound::with_lifetime_bound(&params.generics, "'__a");
let wrapper_generics = if let Style::Unit = variant.style {
params.generics.clone()
} else {
bound::with_lifetime_bound(&params.generics, "'__a")
};
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote_block! {
@@ -612,6 +661,13 @@ fn serialize_untagged_variant(
variant: &Variant,
cattrs: &attr::Container,
) -> Fragment {
if let Some(path) = variant.attrs.serialize_with() {
let ser = wrap_serialize_variant_with(params, path, &variant);
return quote_expr! {
_serde::Serialize::serialize(#ser, __serializer)
};
}
match variant.style {
Style::Unit => {
quote_expr! {
@@ -622,7 +678,7 @@ fn serialize_untagged_variant(
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
}
quote_expr! {
@@ -707,15 +763,23 @@ fn serialize_struct_variant<'a>(
fields: &[Field],
name: &str,
) -> Fragment {
let method = match context {
let (method, skip_method) = match context {
StructVariant::ExternallyTagged { .. } => {
quote!(_serde::ser::SerializeStructVariant::serialize_field)
(
quote!(_serde::ser::SerializeStructVariant::serialize_field),
quote!(_serde::ser::SerializeStructVariant::skip_field),
)
}
StructVariant::InternallyTagged { .. } |
StructVariant::Untagged => quote!(_serde::ser::SerializeStruct::serialize_field),
StructVariant::Untagged => {
(
quote!(_serde::ser::SerializeStruct::serialize_field),
quote!(_serde::ser::SerializeStruct::skip_field),
)
}
};
let serialize_fields = serialize_struct_visitor(fields, params, true, method);
let serialize_fields = serialize_struct_visitor(fields, params, true, method, skip_method);
let mut serialized_fields = fields
.iter()
@@ -808,7 +872,7 @@ fn serialize_tuple_struct_visitor(
.map(|path| quote!(#path(#field_expr)));
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
}
let ser = quote! {
@@ -829,6 +893,7 @@ fn serialize_struct_visitor(
params: &Parameters,
is_enum: bool,
func: Tokens,
skip_func: Tokens,
) -> Vec<Tokens> {
fields
.iter()
@@ -850,7 +915,7 @@ fn serialize_struct_visitor(
.map(|path| quote!(#path(#field_expr)));
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_with(params, field.ty, path, field_expr)
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
}
let ser = quote! {
@@ -859,28 +924,71 @@ fn serialize_struct_visitor(
match skip {
None => ser,
Some(skip) => quote!(if !#skip { #ser }),
Some(skip) => {
quote! {
if !#skip {
#ser
} else {
try!(#skip_func(&mut __serde_state, #key_expr));
}
}
}
}
},
)
.collect()
}
fn wrap_serialize_with(
fn wrap_serialize_field_with(
params: &Parameters,
field_ty: &syn::Ty,
serialize_with: &syn::Path,
value: Tokens,
field_expr: Tokens,
) -> Tokens {
wrap_serialize_with(params,
serialize_with,
&[field_ty],
&[quote!(#field_expr)])
}
fn wrap_serialize_variant_with(
params: &Parameters,
serialize_with: &syn::Path,
variant: &Variant,
) -> Tokens {
let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect();
let field_exprs: Vec<_> = variant.fields.iter()
.enumerate()
.map(|(i, field)| {
let id = field.ident.as_ref().map_or_else(|| Ident::new(format!("__field{}", i)),
|id| id.clone());
quote!(#id)
})
.collect();
wrap_serialize_with(params, serialize_with, field_tys.as_slice(), field_exprs.as_slice())
}
fn wrap_serialize_with(
params: &Parameters,
serialize_with: &syn::Path,
field_tys: &[&syn::Ty],
field_exprs: &[Tokens],
) -> Tokens {
let this = &params.this;
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
let wrapper_generics = bound::with_lifetime_bound(&params.generics, "'__a");
let wrapper_generics = if field_exprs.len() == 0 {
params.generics.clone()
} else {
bound::with_lifetime_bound(&params.generics, "'__a")
};
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
let field_access = (0..field_exprs.len()).map(|n| Ident::new(format!("{}", n)));
quote!({
struct __SerializeWith #wrapper_impl_generics #where_clause {
value: &'__a #field_ty,
values: (#(&'__a #field_tys, )*),
phantom: _serde::export::PhantomData<#this #ty_generics>,
}
@@ -888,12 +996,12 @@ fn wrap_serialize_with(
fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error>
where __S: _serde::Serializer
{
#serialize_with(self.value, __s)
#serialize_with(#(self.values.#field_access, )* __s)
}
}
&__SerializeWith {
value: #value,
values: (#(#field_exprs, )*),
phantom: _serde::export::PhantomData::<#this #ty_generics>,
}
})
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive_internals"
version = "0.15.1" # remember to update html_root_url
version = "0.16.0" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "AST representation used by Serde derive macros. Unstable."
+40
View File
@@ -510,6 +510,8 @@ pub struct Variant {
skip_deserializing: bool,
skip_serializing: bool,
other: bool,
serialize_with: Option<syn::Path>,
deserialize_with: Option<syn::Path>,
}
impl Variant {
@@ -520,6 +522,8 @@ impl Variant {
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
let mut rename_all = Attr::none(cx, "rename_all");
let mut other = BoolAttr::none(cx, "other");
let mut serialize_with = Attr::none(cx, "serialize_with");
let mut deserialize_with = Attr::none(cx, "deserialize_with");
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
for meta_item in meta_items {
@@ -569,6 +573,32 @@ impl Variant {
other.set_true();
}
// Parse `#[serde(with = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
let mut ser_path = path.clone();
ser_path.segments.push("serialize".into());
serialize_with.set(ser_path);
let mut de_path = path;
de_path.segments.push("deserialize".into());
deserialize_with.set(de_path);
}
}
// Parse `#[serde(serialize_with = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
serialize_with.set(path);
}
}
// Parse `#[serde(deserialize_with = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
deserialize_with.set(path);
}
}
MetaItem(ref meta_item) => {
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
}
@@ -595,6 +625,8 @@ impl Variant {
skip_deserializing: skip_deserializing.get(),
skip_serializing: skip_serializing.get(),
other: other.get(),
serialize_with: serialize_with.get(),
deserialize_with: deserialize_with.get(),
}
}
@@ -626,6 +658,14 @@ impl Variant {
pub fn other(&self) -> bool {
self.other
}
pub fn serialize_with(&self) -> Option<&syn::Path> {
self.serialize_with.as_ref()
}
pub fn deserialize_with(&self) -> Option<&syn::Path> {
self.deserialize_with.as_ref()
}
}
/// Represents field attribute information
+17 -10
View File
@@ -27,6 +27,8 @@ pub enum RenameRule {
ScreamingSnakeCase,
/// Rename direct children to "kebab-case" style.
KebabCase,
/// Rename direct children to "SCREAMING-KEBAB-CASE" style.
ScreamingKebabCase
}
impl RenameRule {
@@ -47,6 +49,7 @@ impl RenameRule {
}
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
ScreamingKebabCase => ScreamingSnakeCase.apply_to_variant(variant).replace('_', "-")
}
}
@@ -74,6 +77,7 @@ impl RenameRule {
}
ScreamingSnakeCase => field.to_ascii_uppercase(),
KebabCase => field.replace('_', "-"),
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-")
}
}
}
@@ -89,6 +93,7 @@ impl FromStr for RenameRule {
"snake_case" => Ok(SnakeCase),
"SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
"kebab-case" => Ok(KebabCase),
"SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase),
_ => Err(()),
}
}
@@ -96,12 +101,12 @@ impl FromStr for RenameRule {
#[test]
fn rename_variants() {
for &(original, lower, camel, snake, screaming, kebab) in
for &(original, lower, camel, snake, screaming, kebab, screaming_kebab) in
&[
("Outcome", "outcome", "outcome", "outcome", "OUTCOME", "outcome"),
("VeryTasty", "verytasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty"),
("A", "a", "a", "a", "A", "a"),
("Z42", "z42", "z42", "z42", "Z42", "z42"),
("Outcome", "outcome", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"),
("VeryTasty", "verytasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"),
("A", "a", "a", "a", "A", "a", "A"),
("Z42", "z42", "z42", "z42", "Z42", "z42", "Z42"),
] {
assert_eq!(None.apply_to_variant(original), original);
assert_eq!(LowerCase.apply_to_variant(original), lower);
@@ -110,17 +115,18 @@ fn rename_variants() {
assert_eq!(SnakeCase.apply_to_variant(original), snake);
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
assert_eq!(KebabCase.apply_to_variant(original), kebab);
assert_eq!(ScreamingKebabCase.apply_to_variant(original), screaming_kebab);
}
}
#[test]
fn rename_fields() {
for &(original, pascal, camel, screaming, kebab) in
for &(original, pascal, camel, screaming, kebab, screaming_kebab) in
&[
("outcome", "Outcome", "outcome", "OUTCOME", "outcome"),
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty"),
("a", "A", "a", "A", "a"),
("z42", "Z42", "z42", "Z42", "z42"),
("outcome", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"),
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"),
("a", "A", "a", "A", "a", "A"),
("z42", "Z42", "z42", "Z42", "z42", "Z42"),
] {
assert_eq!(None.apply_to_field(original), original);
assert_eq!(PascalCase.apply_to_field(original), pascal);
@@ -128,5 +134,6 @@ fn rename_fields() {
assert_eq!(SnakeCase.apply_to_field(original), original);
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
assert_eq!(KebabCase.apply_to_field(original), kebab);
assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
}
}
+56
View File
@@ -15,6 +15,7 @@ use Ctxt;
pub fn check(cx: &Ctxt, cont: &Container) {
check_getter(cx, cont);
check_identifier(cx, cont);
check_variant_skip_attrs(cx, cont);
}
/// Getters are only allowed inside structs (not enums) with the `remote`
@@ -94,3 +95,58 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
}
}
}
/// Skip-(de)serializing attributes are not allowed on variants marked
/// (de)serialize_with.
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
let variants = match cont.body {
Body::Enum(ref variants) => variants,
Body::Struct(_, _) => {
return;
}
};
for variant in variants.iter() {
if variant.attrs.serialize_with().is_some() {
if variant.attrs.skip_serializing() {
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
#[serde(skip_serializing)]", variant.ident));
}
for (i, field) in variant.fields.iter().enumerate() {
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i),
|ident| format!("`{}`", ident));
if field.attrs.skip_serializing() {
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing)]",
variant.ident, ident));
}
if field.attrs.skip_serializing_if().is_some() {
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing_if)]",
variant.ident, ident));
}
}
}
if variant.attrs.deserialize_with().is_some() {
if variant.attrs.skip_deserializing() {
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] and \
#[serde(skip_deserializing)]", variant.ident));
}
for (i, field) in variant.fields.iter().enumerate() {
if field.attrs.skip_deserializing() {
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i),
|ident| format!("`{}`", ident));
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] \
and a field {} marked with #[serde(skip_deserializing)]",
variant.ident, ident));
}
}
}
}
}
+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.1")]
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.16.0")]
extern crate syn;
#[macro_use]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "1.0.12" # remember to update html_root_url
version = "1.0.14" # 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.12")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.14")]
#[macro_use]
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() { }
+142
View File
@@ -6,11 +6,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
#[macro_use]
extern crate serde_derive;
extern crate serde;
use self::serde::{Serialize, Serializer, Deserialize, Deserializer};
use self::serde::de::{self, Unexpected};
extern crate serde_test;
use self::serde_test::{Token, assert_tokens, assert_ser_tokens, assert_de_tokens,
@@ -811,6 +814,145 @@ fn test_serialize_with_enum() {
);
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
enum WithVariant {
#[serde(serialize_with="serialize_unit_variant_as_i8")]
#[serde(deserialize_with="deserialize_i8_as_unit_variant")]
Unit,
#[serde(serialize_with="SerializeWith::serialize_with")]
#[serde(deserialize_with="DeserializeWith::deserialize_with")]
Newtype(i32),
#[serde(serialize_with="serialize_variant_as_string")]
#[serde(deserialize_with="deserialize_string_as_variant")]
Tuple(String, u8),
#[serde(serialize_with="serialize_variant_as_string")]
#[serde(deserialize_with="deserialize_string_as_variant")]
Struct {
f1: String,
f2: u8,
},
}
fn serialize_unit_variant_as_i8<S>(serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
serializer.serialize_i8(0)
}
fn deserialize_i8_as_unit_variant<'de, D>(deserializer: D) -> Result<(), D::Error>
where D: Deserializer<'de>,
{
let n = i8::deserialize(deserializer)?;
match n {
0 => Ok(()),
_ => Err(de::Error::invalid_value(Unexpected::Signed(n as i64), &"0")),
}
}
fn serialize_variant_as_string<S>(f1: &str,
f2: &u8,
serializer: S)
-> Result<S::Ok, S::Error>
where S: Serializer,
{
serializer.serialize_str(format!("{};{:?}", f1, f2).as_str())
}
fn deserialize_string_as_variant<'de, D>(deserializer: D) -> Result<(String, u8), D::Error>
where D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
let mut pieces = s.split(';');
let f1 = match pieces.next() {
Some(x) => x,
None => return Err(de::Error::invalid_length(0, &"2")),
};
let f2 = match pieces.next() {
Some(x) => x,
None => return Err(de::Error::invalid_length(1, &"2")),
};
let f2 = match f2.parse() {
Ok(n) => n,
Err(_) => {
return Err(de::Error::invalid_value(Unexpected::Str(f2), &"an 8-bit signed integer"));
}
};
Ok((f1.into(), f2))
}
#[test]
fn test_serialize_with_variant() {
assert_ser_tokens(
&WithVariant::Unit,
&[
Token::NewtypeVariant { name: "WithVariant", variant: "Unit" },
Token::I8(0),
],
);
assert_ser_tokens(
&WithVariant::Newtype(123),
&[
Token::NewtypeVariant { name: "WithVariant", variant: "Newtype" },
Token::Bool(true),
],
);
assert_ser_tokens(
&WithVariant::Tuple("hello".into(), 0),
&[
Token::NewtypeVariant { name: "WithVariant", variant: "Tuple" },
Token::Str("hello;0"),
],
);
assert_ser_tokens(
&WithVariant::Struct { f1: "world".into(), f2: 1 },
&[
Token::NewtypeVariant { name: "WithVariant", variant: "Struct" },
Token::Str("world;1"),
],
);
}
#[test]
fn test_deserialize_with_variant() {
assert_de_tokens(
&WithVariant::Unit,
&[
Token::NewtypeVariant { name: "WithVariant", variant: "Unit" },
Token::I8(0),
],
);
assert_de_tokens(
&WithVariant::Newtype(123),
&[
Token::NewtypeVariant { name: "WithVariant", variant: "Newtype" },
Token::Bool(true),
],
);
assert_de_tokens(
&WithVariant::Tuple("hello".into(), 0),
&[
Token::NewtypeVariant { name: "WithVariant", variant: "Tuple" },
Token::Str("hello;0"),
],
);
assert_de_tokens(
&WithVariant::Struct { f1: "world".into(), f2: 1 },
&[
Token::NewtypeVariant { name: "WithVariant", variant: "Struct" },
Token::Str("world;1"),
],
);
}
#[derive(Debug, PartialEq, Deserialize)]
struct DeserializeWithStruct<B>
where
+9
View File
@@ -521,6 +521,15 @@ declare_tests! {
Token::I32(2),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Map { len: Some(3) },
Token::U32(0),
Token::I32(1),
Token::U32(1),
Token::I32(2),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Struct { name: "Struct", len: 3 },
Token::Str("a"),
+168
View File
@@ -10,6 +10,8 @@
// successfully when there are a variety of generics and non-(de)serializable
// types involved.
#![deny(warnings)]
#![cfg_attr(feature = "unstable", feature(non_ascii_idents))]
// Clippy false positive
@@ -373,6 +375,146 @@ fn test_gen() {
#[serde(with = "vis::SDef")]
s: vis::S,
}
#[derive(Serialize, Deserialize)]
enum ExternallyTaggedVariantWith {
#[allow(dead_code)]
Normal { f1: String },
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
#[allow(dead_code)]
Newtype(X),
#[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)]
Tuple(String, u8),
#[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)]
Struct {
f1: String,
f2: u8,
},
#[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")]
#[allow(dead_code)]
Unit,
}
assert_ser::<ExternallyTaggedVariantWith>();
#[derive(Serialize, Deserialize)]
#[serde(tag = "t")]
enum InternallyTaggedVariantWith {
#[allow(dead_code)]
Normal { f1: String },
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
#[allow(dead_code)]
Newtype(X),
#[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)]
Struct {
f1: String,
f2: u8,
},
#[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")]
#[allow(dead_code)]
Unit,
}
assert_ser::<InternallyTaggedVariantWith>();
#[derive(Serialize, Deserialize)]
#[serde(tag = "t", content = "c")]
enum AdjacentlyTaggedVariantWith {
#[allow(dead_code)]
Normal { f1: String },
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
#[allow(dead_code)]
Newtype(X),
#[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)]
Tuple(String, u8),
#[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)]
Struct {
f1: String,
f2: u8,
},
#[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")]
#[allow(dead_code)]
Unit,
}
assert_ser::<AdjacentlyTaggedVariantWith>();
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum UntaggedVariantWith {
#[allow(dead_code)]
Normal { f1: String },
#[serde(serialize_with = "ser_x")]
#[serde(deserialize_with = "de_x")]
#[allow(dead_code)]
Newtype(X),
#[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)]
Tuple(String, u8),
#[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)]
Struct {
f1: String,
f2: u8,
},
#[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")]
#[allow(dead_code)]
Unit,
}
assert_ser::<UntaggedVariantWith>();
#[derive(Serialize, Deserialize)]
struct StaticStrStruct<'a> {
a: &'a str,
b: &'static str,
}
#[derive(Serialize, Deserialize)]
struct StaticStrTupleStruct<'a>(&'a str, &'static str);
#[derive(Serialize, Deserialize)]
struct StaticStrNewtypeStruct(&'static str);
#[derive(Serialize, Deserialize)]
enum StaticStrEnum<'a> {
Struct {
a: &'a str,
b: &'static str,
},
Tuple(&'a str, &'static str),
Newtype(&'static str),
}
}
//////////////////////////////////////////////////////////////////////////
@@ -414,3 +556,29 @@ impl DeserializeWith for X {
unimplemented!()
}
}
pub fn serialize_some_unit_variant<S>(_: S) -> StdResult<S::Ok, S::Error>
where S: Serializer,
{
unimplemented!()
}
pub fn deserialize_some_unit_variant<'de, D>(_: D) -> StdResult<(), D::Error>
where D: Deserializer<'de>,
{
unimplemented!()
}
pub fn serialize_some_other_variant<S>(_: &str, _: &u8, _: S) -> StdResult<S::Ok, S::Error>
where S: Serializer,
{
unimplemented!()
}
pub fn deserialize_some_other_variant<'de, D>(_: D) -> StdResult<(String, u8), D::Error>
where D: Deserializer<'de>,
{
unimplemented!()
}
pub fn is_zero(n: &u8) -> bool { *n == 0 }
+3
View File
@@ -23,7 +23,10 @@ fn test_variant_identifier() {
Bbb,
}
assert_de_tokens(&V::Aaa, &[Token::U8(0)]);
assert_de_tokens(&V::Aaa, &[Token::U16(0)]);
assert_de_tokens(&V::Aaa, &[Token::U32(0)]);
assert_de_tokens(&V::Aaa, &[Token::U64(0)]);
assert_de_tokens(&V::Aaa, &[Token::Str("Aaa")]);
assert_de_tokens(&V::Aaa, &[Token::Bytes(b"Aaa")]);
}
+25 -1
View File
@@ -6,6 +6,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![deny(trivial_numeric_casts)]
#[macro_use]
extern crate serde_derive;
@@ -1149,7 +1151,7 @@ fn test_rename_all() {
SerializeMap {
serialize: bool,
serialize_seq: bool,
},
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
@@ -1159,6 +1161,13 @@ fn test_rename_all() {
serialize_seq: bool,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "SCREAMING-KEBAB-CASE")]
struct ScreamingKebab {
serialize: bool,
serialize_seq: bool,
}
assert_tokens(
&E::Serialize {
serialize: true,
@@ -1218,4 +1227,19 @@ fn test_rename_all() {
Token::StructEnd,
],
);
assert_tokens(
&ScreamingKebab {
serialize: true,
serialize_seq: true,
},
&[
Token::Struct { name: "ScreamingKebab", len: 2 },
Token::Str("SERIALIZE"),
Token::Bool(true),
Token::Str("SERIALIZE-SEQ"),
Token::Bool(true),
Token::StructEnd,
]
);
}