Skip to content

Commit 43035f6

Browse files
authored
Merge pull request #2505 from Baptistemontan/rework_adjacently_tagged_enum
Revisit of the representation of adjacently tagged enums tag
2 parents 83b1a3d + 957ef20 commit 43035f6

File tree

6 files changed

+212
-34
lines changed

6 files changed

+212
-34
lines changed

serde/src/private/de.rs

+62-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use crate::lib::*;
22

33
use crate::de::value::{BorrowedBytesDeserializer, BytesDeserializer};
4-
use crate::de::{Deserialize, Deserializer, Error, IntoDeserializer, Visitor};
4+
use crate::de::{
5+
Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, IntoDeserializer, VariantAccess,
6+
Visitor,
7+
};
58

69
#[cfg(any(feature = "std", feature = "alloc"))]
7-
use crate::de::{DeserializeSeed, MapAccess, Unexpected};
10+
use crate::de::{MapAccess, Unexpected};
811

912
#[cfg(any(feature = "std", feature = "alloc"))]
1013
pub use self::content::{
@@ -2836,3 +2839,60 @@ fn flat_map_take_entry<'de>(
28362839
None
28372840
}
28382841
}
2842+
2843+
pub struct AdjacentlyTaggedEnumVariantSeed<F> {
2844+
pub tag: &'static str,
2845+
pub variants: &'static [&'static str],
2846+
pub fields_enum: PhantomData<F>,
2847+
}
2848+
2849+
pub struct AdjacentlyTaggedEnumVariantVisitor<F> {
2850+
tag: &'static str,
2851+
fields_enum: PhantomData<F>,
2852+
}
2853+
2854+
impl<'de, F> Visitor<'de> for AdjacentlyTaggedEnumVariantVisitor<F>
2855+
where
2856+
F: Deserialize<'de>,
2857+
{
2858+
type Value = F;
2859+
2860+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2861+
write!(formatter, "enum {}", self.tag)
2862+
}
2863+
2864+
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
2865+
where
2866+
A: EnumAccess<'de>,
2867+
{
2868+
let (variant, variant_access) = match data.variant() {
2869+
Ok(values) => values,
2870+
Err(err) => return Err(err),
2871+
};
2872+
if let Err(err) = variant_access.unit_variant() {
2873+
return Err(err);
2874+
}
2875+
Ok(variant)
2876+
}
2877+
}
2878+
2879+
impl<'de, F> DeserializeSeed<'de> for AdjacentlyTaggedEnumVariantSeed<F>
2880+
where
2881+
F: Deserialize<'de>,
2882+
{
2883+
type Value = F;
2884+
2885+
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
2886+
where
2887+
D: Deserializer<'de>,
2888+
{
2889+
deserializer.deserialize_enum(
2890+
self.tag,
2891+
self.variants,
2892+
AdjacentlyTaggedEnumVariantVisitor {
2893+
tag: self.tag,
2894+
fields_enum: PhantomData,
2895+
},
2896+
)
2897+
}
2898+
}

serde/src/private/ser.rs

+25
Original file line numberDiff line numberDiff line change
@@ -1355,3 +1355,28 @@ where
13551355
Ok(())
13561356
}
13571357
}
1358+
1359+
pub struct AdjacentlyTaggedEnumVariantSerializer {
1360+
tag: &'static str,
1361+
variant_index: u32,
1362+
variant_name: &'static str,
1363+
}
1364+
1365+
impl AdjacentlyTaggedEnumVariantSerializer {
1366+
pub fn new(tag: &'static str, variant_index: u32, variant_name: &'static str) -> Self {
1367+
AdjacentlyTaggedEnumVariantSerializer {
1368+
tag,
1369+
variant_index,
1370+
variant_name,
1371+
}
1372+
}
1373+
}
1374+
1375+
impl Serialize for AdjacentlyTaggedEnumVariantSerializer {
1376+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1377+
where
1378+
S: Serializer,
1379+
{
1380+
serializer.serialize_unit_variant(self.tag, self.variant_index, self.variant_name)
1381+
}
1382+
}

serde_derive/src/de.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1480,6 +1480,14 @@ fn deserialize_adjacently_tagged_enum(
14801480
}
14811481
};
14821482

1483+
let variant_seed = quote! {
1484+
_serde::__private::de::AdjacentlyTaggedEnumVariantSeed::<__Field> {
1485+
tag: #tag,
1486+
variants: &VARIANTS,
1487+
fields_enum: _serde::__private::PhantomData
1488+
}
1489+
};
1490+
14831491
let mut missing_content = quote! {
14841492
_serde::__private::Err(<__A::Error as _serde::de::Error>::missing_field(#content))
14851493
};
@@ -1527,6 +1535,10 @@ fn deserialize_adjacently_tagged_enum(
15271535
_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content)?
15281536
};
15291537

1538+
let variant_from_map = quote! {
1539+
_serde::de::MapAccess::next_value_seed(&mut __map, #variant_seed)?
1540+
};
1541+
15301542
// When allowing unknown fields, we want to transparently step through keys
15311543
// we don't care about until we find `tag`, `content`, or run out of keys.
15321544
let next_relevant_key = if deny_unknown_fields {
@@ -1572,11 +1584,11 @@ fn deserialize_adjacently_tagged_enum(
15721584

15731585
let finish_content_then_tag = if variant_arms.is_empty() {
15741586
quote! {
1575-
match _serde::de::MapAccess::next_value::<__Field>(&mut __map)? {}
1587+
match #variant_from_map {}
15761588
}
15771589
} else {
15781590
quote! {
1579-
let __ret = match _serde::de::MapAccess::next_value(&mut __map)? {
1591+
let __ret = match #variant_from_map {
15801592
// Deserialize the buffered content now that we know the variant.
15811593
#(#variant_arms)*
15821594
}?;
@@ -1632,7 +1644,7 @@ fn deserialize_adjacently_tagged_enum(
16321644
// First key is the tag.
16331645
_serde::__private::Some(_serde::__private::de::TagOrContentField::Tag) => {
16341646
// Parse the tag.
1635-
let __field = _serde::de::MapAccess::next_value(&mut __map)?;
1647+
let __field = #variant_from_map;
16361648
// Visit the second key.
16371649
match #next_relevant_key {
16381650
// Second key is a duplicate of the tag.

serde_derive/src/ser.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,14 @@ fn serialize_variant(
478478
serialize_internally_tagged_variant(params, variant, cattrs, tag)
479479
}
480480
(attr::TagType::Adjacent { tag, content }, false) => {
481-
serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content)
481+
serialize_adjacently_tagged_variant(
482+
params,
483+
variant,
484+
cattrs,
485+
variant_index,
486+
tag,
487+
content,
488+
)
482489
}
483490
(attr::TagType::None, _) | (_, true) => {
484491
serialize_untagged_variant(params, variant, cattrs)
@@ -634,12 +641,14 @@ fn serialize_adjacently_tagged_variant(
634641
params: &Parameters,
635642
variant: &Variant,
636643
cattrs: &attr::Container,
644+
variant_index: u32,
637645
tag: &str,
638646
content: &str,
639647
) -> Fragment {
640648
let this_type = &params.this_type;
641649
let type_name = cattrs.name().serialize_name();
642650
let variant_name = variant.attrs.name().serialize_name();
651+
let variant_serializer = quote!(&_serde::__private::ser::AdjacentlyTaggedEnumVariantSerializer::new(#tag, #variant_index, #variant_name));
643652

644653
let inner = Stmts(if let Some(path) = variant.attrs.serialize_with() {
645654
let ser = wrap_serialize_variant_with(params, path, variant);
@@ -653,7 +662,7 @@ fn serialize_adjacently_tagged_variant(
653662
let mut __struct = _serde::Serializer::serialize_struct(
654663
__serializer, #type_name, 1)?;
655664
_serde::ser::SerializeStruct::serialize_field(
656-
&mut __struct, #tag, #variant_name)?;
665+
&mut __struct, #tag, #variant_serializer)?;
657666
_serde::ser::SerializeStruct::end(__struct)
658667
};
659668
}
@@ -670,7 +679,7 @@ fn serialize_adjacently_tagged_variant(
670679
let mut __struct = _serde::Serializer::serialize_struct(
671680
__serializer, #type_name, 2)?;
672681
_serde::ser::SerializeStruct::serialize_field(
673-
&mut __struct, #tag, #variant_name)?;
682+
&mut __struct, #tag, #variant_serializer)?;
674683
#func(
675684
&mut __struct, #content, #field_expr)?;
676685
_serde::ser::SerializeStruct::end(__struct)
@@ -735,7 +744,7 @@ fn serialize_adjacently_tagged_variant(
735744
let mut __struct = _serde::Serializer::serialize_struct(
736745
__serializer, #type_name, 2)?;
737746
_serde::ser::SerializeStruct::serialize_field(
738-
&mut __struct, #tag, #variant_name)?;
747+
&mut __struct, #tag, #variant_serializer)?;
739748
_serde::ser::SerializeStruct::serialize_field(
740749
&mut __struct, #content, &__AdjacentlyTagged {
741750
data: (#(#fields_ident,)*),

test_suite/tests/test_annotations.rs

+21-6
Original file line numberDiff line numberDiff line change
@@ -2108,7 +2108,10 @@ fn test_adjacently_tagged_enum_bytes() {
21082108
len: 2,
21092109
},
21102110
Token::Str("t"),
2111-
Token::Str("A"),
2111+
Token::UnitVariant {
2112+
name: "t",
2113+
variant: "A",
2114+
},
21122115
Token::Str("c"),
21132116
Token::Struct { name: "A", len: 1 },
21142117
Token::Str("a"),
@@ -2126,7 +2129,10 @@ fn test_adjacently_tagged_enum_bytes() {
21262129
len: 2,
21272130
},
21282131
Token::Bytes(b"t"),
2129-
Token::Str("A"),
2132+
Token::UnitVariant {
2133+
name: "t",
2134+
variant: "A",
2135+
},
21302136
Token::Bytes(b"c"),
21312137
Token::Struct { name: "A", len: 1 },
21322138
Token::Str("a"),
@@ -2167,7 +2173,10 @@ fn test_adjacently_tagged_enum_containing_flatten() {
21672173
len: 2,
21682174
},
21692175
Token::Str("t"),
2170-
Token::Str("A"),
2176+
Token::UnitVariant {
2177+
name: "t",
2178+
variant: "A",
2179+
},
21712180
Token::Str("c"),
21722181
Token::Map { len: None },
21732182
Token::Str("a"),
@@ -2757,7 +2766,7 @@ fn test_expecting_message_adjacently_tagged_enum() {
27572766
// Check that #[serde(expecting = "...")] doesn't affect variant identifier error message
27582767
assert_de_tokens_error::<Enum>(
27592768
&[Token::Map { len: None }, Token::Str("tag"), Token::Unit],
2760-
r#"invalid type: unit value, expected variant identifier"#,
2769+
r#"invalid type: unit value, expected enum tag"#,
27612770
);
27622771
}
27632772

@@ -2992,7 +3001,10 @@ mod flatten {
29923001
Token::Str("outer"),
29933002
Token::U32(42),
29943003
Token::Str("tag"),
2995-
Token::Str("Struct"),
3004+
Token::UnitVariant {
3005+
name: "tag",
3006+
variant: "Struct",
3007+
},
29963008
Token::Str("content"),
29973009
Token::Struct {
29983010
len: 2,
@@ -3020,7 +3032,10 @@ mod flatten {
30203032
Token::Str("outer"),
30213033
Token::U32(42),
30223034
Token::Str("tag"),
3023-
Token::Str("Newtype"),
3035+
Token::UnitVariant {
3036+
name: "tag",
3037+
variant: "Newtype",
3038+
},
30243039
Token::Str("content"),
30253040
Token::Struct {
30263041
len: 1,

0 commit comments

Comments
 (0)