Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
302 changes: 217 additions & 85 deletions serde/src/private/de.rs

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion serde_derive/src/de/enum_adjacently.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ pub(super) fn deserialize(
marker: _serde::#private::PhantomData,
lifetime: _serde::#private::PhantomData,
};
let __deserializer = _serde::#private::de::ContentDeserializer::<__A::Error>::new(__content);
let __deserializer = _serde::#private::de::ContentDeserializer::<__A::Error>::new(__content, self.__is_human_readable);
let __ret = _serde::de::DeserializeSeed::deserialize(__seed, __deserializer)?;
// Visit remaining keys, looking for duplicates.
#visit_remaining_keys
Expand Down Expand Up @@ -208,6 +208,7 @@ pub(super) fn deserialize(
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData<&#delife ()>,
__is_human_readable: bool,
}

#[automatically_derived]
Expand Down Expand Up @@ -311,13 +312,15 @@ pub(super) fn deserialize(

#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[#tag, #content];
let __is_human_readable = _serde::Deserializer::is_human_readable(&__deserializer);
_serde::Deserializer::deserialize_struct(
__deserializer,
#type_name,
FIELDS,
__Visitor {
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData,
__is_human_readable: __is_human_readable,
},
)
}
Expand Down
3 changes: 2 additions & 1 deletion serde_derive/src/de/enum_internally.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ pub(super) fn deserialize(

#variants_stmt

let __is_human_readable = _serde::Deserializer::is_human_readable(&__deserializer);
let (__tag, __content) = _serde::Deserializer::deserialize_any(
__deserializer,
_serde::#private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting))?;
let __deserializer = _serde::#private::de::ContentDeserializer::<__D::Error>::new(__content);
let __deserializer = _serde::#private::de::ContentDeserializer::<__D::Error>::new(__content, __is_human_readable);

match __tag {
#(#variant_arms)*
Expand Down
3 changes: 2 additions & 1 deletion serde_derive/src/de/enum_untagged.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ pub(super) fn deserialize(

let private2 = private;
quote_block! {
let __is_human_readable = _serde::Deserializer::is_human_readable(&__deserializer);
let __content = _serde::de::DeserializeSeed::deserialize(_serde::#private::de::ContentVisitor::new(), __deserializer)?;
let __deserializer = _serde::#private::de::ContentRefDeserializer::<__D::Error>::new(&__content);
let __deserializer = _serde::#private::de::ContentRefDeserializer::<__D::Error>::new(&__content, __is_human_readable);

#first_attempt

Expand Down
58 changes: 49 additions & 9 deletions serde_derive/src/de/struct_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,11 @@ pub(super) fn deserialize(
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this_type #ty_generics;

fn deserialize<__D>(self, __deserializer: __D) -> _serde::#private::Result<Self::Value, __D::Error>
fn deserialize<__D>(mut self, __deserializer: __D) -> _serde::#private::Result<Self::Value, __D::Error>
where
__D: _serde::Deserializer<#delife>,
{
self.__is_human_readable = _serde::Deserializer::is_human_readable(&__deserializer);
_serde::Deserializer::deserialize_map(__deserializer, self)
}
}
Expand All @@ -130,14 +131,25 @@ pub(super) fn deserialize(
})
};

let visitor_expr = quote! {
__Visitor {
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData,
let visitor_expr = if has_flatten {
quote! {
__Visitor {
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData,
__is_human_readable: __is_human_readable,
}
}
} else {
quote! {
__Visitor {
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData,
}
}
};
let dispatch = match form {
StructForm::Struct if has_flatten => quote! {
let __is_human_readable = _serde::Deserializer::is_human_readable(&__deserializer);
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
},
StructForm::Struct => {
Expand All @@ -146,27 +158,53 @@ pub(super) fn deserialize(
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
}
}
StructForm::ExternallyTagged(_) if has_flatten => quote! {
_serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr)
},
StructForm::ExternallyTagged(_) if has_flatten => {
// __is_human_readable is not available here; it will be set in
// DeserializeSeed::deserialize before visit_map is called.
let visitor_expr_default = quote! {
__Visitor {
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData,
__is_human_readable: true,
}
};
quote! {
_serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr_default)
}
}
StructForm::ExternallyTagged(_) => quote! {
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
},
StructForm::InternallyTagged(_) if has_flatten => quote! {
let __is_human_readable = _serde::Deserializer::is_human_readable(&__deserializer);
_serde::Deserializer::deserialize_any(__deserializer, #visitor_expr)
},
StructForm::InternallyTagged(_) => quote! {
_serde::Deserializer::deserialize_any(__deserializer, #visitor_expr)
},
StructForm::Untagged(_) if has_flatten => quote! {
let __is_human_readable = _serde::Deserializer::is_human_readable(&__deserializer);
_serde::Deserializer::deserialize_any(__deserializer, #visitor_expr)
},
StructForm::Untagged(_) => quote! {
_serde::Deserializer::deserialize_any(__deserializer, #visitor_expr)
},
};

let is_human_readable_field = if has_flatten {
Some(quote! { __is_human_readable: bool, })
} else {
None
};

quote_block! {
#field_visitor

#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::#private::PhantomData<&#delife ()>,
#is_human_readable_field
}

#[automatically_derived]
Expand Down Expand Up @@ -224,6 +262,7 @@ fn deserialize_map(
// Collect contents for flatten fields into a buffer
let let_collect = if has_flatten {
Some(quote! {
let __is_human_readable = self.__is_human_readable;
let mut __collect = _serde::#private::Vec::<_serde::#private::Option<(
_serde::#private::de::Content,
_serde::#private::de::Content
Expand Down Expand Up @@ -340,7 +379,8 @@ fn deserialize_map(
let #name: #field_ty = #func(
_serde::#private::de::FlatMapDeserializer(
&mut __collect,
_serde::#private::PhantomData))?;
_serde::#private::PhantomData,
__is_human_readable))?;
}
});

Expand Down
70 changes: 70 additions & 0 deletions test_suite/tests/regression/issue2172.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Untagged enum deserializing expects human-readable representation even with
// non human-readable data formats.
//
// https://github.com/serde-rs/serde/issues/2172

use serde_derive::{Deserialize, Serialize};
use serde_test::{assert_tokens, Configure, Token};

/// Type that serializes as a string when human-readable, or as bytes when compact.
#[derive(Debug, PartialEq)]
struct HrBytes(Vec<u8>);

impl serde::Serialize for HrBytes {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
hex_encode(&self.0).serialize(serializer)
} else {
self.0.serialize(serializer)
}
}
}

impl<'de> serde::Deserialize<'de> for HrBytes {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
if deserializer.is_human_readable() {
let s = String::deserialize(deserializer)?;
hex_decode(&s).map(HrBytes).map_err(serde::de::Error::custom)
} else {
Vec::deserialize(deserializer).map(HrBytes)
}
}
}

fn hex_encode(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{:02x}", b)).collect()
}

fn hex_decode(s: &str) -> Result<Vec<u8>, String> {
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).map_err(|e| e.to_string()))
.collect()
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
enum Untagged {
Hr(HrBytes),
}

#[test]
fn human_readable() {
assert_tokens(
&Untagged::Hr(HrBytes(vec![1, 2])).readable(),
&[Token::Str("0102")],
);
}

#[test]
fn compact() {
assert_tokens(
&Untagged::Hr(HrBytes(vec![1, 2])).compact(),
&[
Token::Seq { len: Some(2) },
Token::U8(1),
Token::U8(2),
Token::SeqEnd,
],
);
}
4 changes: 2 additions & 2 deletions test_suite/tests/regression/issue2565.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use serde_derive::{Deserialize, Serialize};
use serde_test::{assert_tokens, Token};
use serde_test::{assert_tokens, Configure, Token};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum Enum {
Expand Down Expand Up @@ -33,7 +33,7 @@ fn simple_variant() {
#[test]
fn flatten_variant() {
assert_tokens(
&Enum::Flatten { flatten: (), a: 42 },
&Enum::Flatten { flatten: (), a: 42 }.readable(),
&[
Token::NewtypeVariant {
name: "Enum",
Expand Down
78 changes: 78 additions & 0 deletions test_suite/tests/regression/issue2704.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// human_readable flag does not get carried through #[serde(flatten)].
//
// https://github.com/serde-rs/serde/issues/2704

use serde_derive::{Deserialize, Serialize};
use serde_test::{assert_tokens, Configure, Token};

/// Type that serializes as a string when human-readable, or as a u32 when compact.
#[derive(Debug, PartialEq)]
struct HrU32(u32);

impl serde::Serialize for HrU32 {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
self.0.to_string().serialize(serializer)
} else {
self.0.serialize(serializer)
}
}
}

impl<'de> serde::Deserialize<'de> for HrU32 {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
if deserializer.is_human_readable() {
let s = String::deserialize(deserializer)?;
s.parse().map(HrU32).map_err(serde::de::Error::custom)
} else {
u32::deserialize(deserializer).map(HrU32)
}
}
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Inner {
value: HrU32,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Outer {
#[serde(flatten)]
inner: Inner,
}

#[test]
fn human_readable() {
assert_tokens(
&Outer {
inner: Inner {
value: HrU32(42),
},
}
.readable(),
&[
Token::Map { len: None },
Token::Str("value"),
Token::Str("42"),
Token::MapEnd,
],
);
}

#[test]
fn compact() {
assert_tokens(
&Outer {
inner: Inner {
value: HrU32(42),
},
}
.compact(),
&[
Token::Map { len: None },
Token::Str("value"),
Token::U32(42),
Token::MapEnd,
],
);
}
Loading