Skip to content

Commit

Permalink
Fix serde-rs#1495: Do not buffer content of the internally tagged enu…
Browse files Browse the repository at this point in the history
…ms if tag is the first field

failures (2):
    newtype_unit
    newtype_unit_struct
  • Loading branch information
Mingun committed Oct 21, 2024
1 parent 032dbfc commit 19b34f6
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 29 deletions.
11 changes: 7 additions & 4 deletions serde/src/private/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,7 @@ mod content {
/// # Parameters
/// - `map`: map that will be drained
/// - `tag_name`: name of tag in the `#[serde(tag = "tag_name")]` attribute
/// - `tag`: tag, if first value in map was a tag
/// - `vec`: placeholder for all other key-value pairs
/// - `first_key`: the first key already fetched from the map
///
/// # Returns
/// A tuple with two values:
Expand All @@ -237,13 +236,17 @@ mod content {
pub fn drain_map<'de, T, A>(
mut map: A,
tag_name: &'static str,
mut tag: Option<T>,
mut vec: Vec<(Content<'de>, Content<'de>)>,
first_key: Content<'de>,
) -> Result<(T, ContentDeserializer<'de, A::Error>), A::Error>
where
T: Deserialize<'de>,
A: MapAccess<'de>,
{
let mut tag = None;
let mut vec =
Vec::with_capacity(size_hint::cautious::<(Content, Content)>(map.size_hint()));

vec.push((first_key, tri!(map.next_value())));
while let Some(key) = tri!(map.next_key_seed(TagOrContentVisitor::new(tag_name))) {
match key {
TagOrContent::Tag => {
Expand Down
18 changes: 7 additions & 11 deletions serde_derive/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1440,26 +1440,22 @@ fn deserialize_internally_tagged_enum(
where
__M: _serde::de::MapAccess<#delife>,
{
let mut __vec = _serde::__private::Vec::with_capacity(
_serde::de::MapAccess::size_hint(&__map).unwrap_or(0)
);

// Read the first field. If it is a tag, immediately deserialize the typed data.
// Otherwise, we collect everything until we find the tag, and then deserialize
// using ContentDeserializer.
match _serde::de::MapAccess::next_key_seed(
&mut __map, _serde::__private::de::TagOrContentVisitor::new(#tag)
)? {
_serde::__private::Some(_serde::__private::de::TagOrContent::Tag) => {
let __tag = _serde::de::MapAccess::next_value(&mut __map)?;
let (__tag, __deserializer) = _serde::__private::de::drain_map(
__map, #tag, _serde::__private::Some(__tag), __vec
)?;

Self::visit(__tag, __deserializer)
Self::visit(__tag, _serde::de::value::MapAccessDeserializer::new(__map))
},
_serde::__private::Some(_serde::__private::de::TagOrContent::Content(__key)) => {
let __val = _serde::de::MapAccess::next_value(&mut __map)?;
__vec.push((__key, __val));
// Drain map to Content::Map, convert it to ContentDeserializer
// Special handling for tag key -- search them and return as separate result
let (__tag, __deserializer) = _serde::__private::de::drain_map(
__map, #tag, _serde::__private::None, __vec
__map, #tag, __key
)?;

Self::visit(__tag, __deserializer)
Expand Down
19 changes: 5 additions & 14 deletions test_suite/tests/expand/expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1770,9 +1770,6 @@ mod expand {
where
__M: _serde::de::MapAccess<'de>,
{
let mut __vec = _serde::__private::Vec::with_capacity(
_serde::de::MapAccess::size_hint(&__map).unwrap_or(0),
);
match _serde::de::MapAccess::next_key_seed(
&mut __map,
_serde::__private::de::TagOrContentVisitor::new("tag"),
Expand All @@ -1781,24 +1778,18 @@ mod expand {
_serde::__private::de::TagOrContent::Tag,
) => {
let __tag = _serde::de::MapAccess::next_value(&mut __map)?;
let (__tag, __deserializer) = _serde::__private::de::drain_map(
__map,
"tag",
_serde::__private::Some(__tag),
__vec,
)?;
Self::visit(__tag, __deserializer)
Self::visit(
__tag,
_serde::de::value::MapAccessDeserializer::new(__map),
)
}
_serde::__private::Some(
_serde::__private::de::TagOrContent::Content(__key),
) => {
let __val = _serde::de::MapAccess::next_value(&mut __map)?;
__vec.push((__key, __val));
let (__tag, __deserializer) = _serde::__private::de::drain_map(
__map,
"tag",
_serde::__private::None,
__vec,
__key,
)?;
Self::visit(__tag, __deserializer)
}
Expand Down

0 comments on commit 19b34f6

Please sign in to comment.