diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index 51705d95..3c0a187a 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -894,7 +894,7 @@ mod content { where D: Deserializer<'de>, { - deserializer.deserialize_str(self) + deserializer.deserialize_identifier(self) } } @@ -905,6 +905,20 @@ mod content { write!(formatter, "{:?} or {:?}", self.tag, self.content) } + fn visit_u64(self, field_index: u64) -> Result + where + E: de::Error, + { + match field_index { + 0 => Ok(TagOrContentField::Tag), + 1 => Ok(TagOrContentField::Content), + _ => Err(de::Error::invalid_value( + Unexpected::Unsigned(field_index), + &self, + )), + } + } + fn visit_str(self, field: &str) -> Result where E: de::Error, @@ -917,6 +931,19 @@ mod content { Err(de::Error::invalid_value(Unexpected::Str(field), &self)) } } + + fn visit_bytes(self, field: &[u8]) -> Result + where + E: de::Error, + { + if field == self.tag.as_bytes() { + Ok(TagOrContentField::Tag) + } else if field == self.content.as_bytes() { + Ok(TagOrContentField::Content) + } else { + Err(de::Error::invalid_value(Unexpected::Bytes(field), &self)) + } + } } /// Used by generated code to deserialize an adjacently tagged enum when @@ -942,7 +969,7 @@ mod content { where D: Deserializer<'de>, { - deserializer.deserialize_str(self) + deserializer.deserialize_identifier(self) } } @@ -957,6 +984,17 @@ mod content { ) } + fn visit_u64(self, field_index: u64) -> Result + where + E: de::Error, + { + match field_index { + 0 => Ok(TagContentOtherField::Tag), + 1 => Ok(TagContentOtherField::Content), + _ => Ok(TagContentOtherField::Other), + } + } + fn visit_str(self, field: &str) -> Result where E: de::Error, diff --git a/test_suite/tests/test_macros.rs b/test_suite/tests/test_macros.rs index c6973db9..0c38fc39 100644 --- a/test_suite/tests/test_macros.rs +++ b/test_suite/tests/test_macros.rs @@ -1086,6 +1086,34 @@ fn test_adjacently_tagged_enum() { ], ); + // unit with no content (integer tag) + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(0), // tag field + Token::Str("Unit"), + Token::StructEnd, + ], + ); + + // unit with no content (bytes tag) + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"t"), + Token::Str("Unit"), + Token::StructEnd, + ], + ); + // unit with tag first assert_de_tokens( &AdjacentlyTagged::Unit::, @@ -1102,6 +1130,38 @@ fn test_adjacently_tagged_enum() { ], ); + // unit with tag first (integer tag) + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(0), // tag field + Token::Str("Unit"), + Token::U64(1), // content field + Token::Unit, + Token::StructEnd, + ], + ); + + // unit with tag first (bytes tag) + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"t"), + Token::Str("Unit"), + Token::Bytes(b"c"), + Token::Unit, + Token::StructEnd, + ], + ); + // unit with content first assert_de_tokens( &AdjacentlyTagged::Unit::, @@ -1118,6 +1178,38 @@ fn test_adjacently_tagged_enum() { ], ); + // unit with content first (integer tag) + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(1), // content field + Token::Unit, + Token::U64(0), // tag field + Token::Str("Unit"), + Token::StructEnd, + ], + ); + + // unit with content first (bytes tag) + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"c"), + Token::Unit, + Token::Bytes(b"t"), + Token::Str("Unit"), + Token::StructEnd, + ], + ); + // unit with excess content (f, g, h) assert_de_tokens( &AdjacentlyTagged::Unit::, @@ -1140,6 +1232,50 @@ fn test_adjacently_tagged_enum() { ], ); + // unit with excess content (f, g, 3) (integer tag) + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("f"), + Token::Unit, + Token::U64(0), // tag field + Token::Str("Unit"), + Token::Str("g"), + Token::Unit, + Token::U64(1), // content field + Token::Unit, + Token::U64(3), // unknown field + Token::Unit, + Token::StructEnd, + ], + ); + + // unit with excess content (f, b"g", 3) (bytes tag) + assert_de_tokens( + &AdjacentlyTagged::Unit::, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("f"), + Token::Unit, + Token::Bytes(b"t"), + Token::Str("Unit"), + Token::Bytes(b"g"), + Token::Unit, + Token::Str("c"), + Token::Unit, + Token::U64(3), + Token::Unit, + Token::StructEnd, + ], + ); + // newtype with tag first assert_tokens( &AdjacentlyTagged::Newtype::(1), @@ -1156,6 +1292,38 @@ fn test_adjacently_tagged_enum() { ], ); + // newtype with tag first (integer tag) + assert_de_tokens( + &AdjacentlyTagged::Newtype::(1), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(0), // tag field + Token::Str("Newtype"), + Token::U64(1), // content field + Token::U8(1), + Token::StructEnd, + ], + ); + + // newtype with tag first (bytes tag) + assert_de_tokens( + &AdjacentlyTagged::Newtype::(1), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"t"), + Token::Str("Newtype"), + Token::Bytes(b"c"), + Token::U8(1), + Token::StructEnd, + ], + ); + // newtype with content first assert_de_tokens( &AdjacentlyTagged::Newtype::(1), @@ -1172,6 +1340,38 @@ fn test_adjacently_tagged_enum() { ], ); + // newtype with content first (integer tag) + assert_de_tokens( + &AdjacentlyTagged::Newtype::(1), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(1), // content field + Token::U8(1), + Token::U64(0), // tag field + Token::Str("Newtype"), + Token::StructEnd, + ], + ); + + // newtype with content first (bytes tag) + assert_de_tokens( + &AdjacentlyTagged::Newtype::(1), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"c"), + Token::U8(1), + Token::Bytes(b"t"), + Token::Str("Newtype"), + Token::StructEnd, + ], + ); + // optional newtype with no content field assert_de_tokens( &AdjacentlyTagged::Newtype::>(None), @@ -1186,6 +1386,34 @@ fn test_adjacently_tagged_enum() { ], ); + // optional newtype with no content field (integer tag) + assert_de_tokens( + &AdjacentlyTagged::Newtype::>(None), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 1, + }, + Token::U64(0), // tag field + Token::Str("Newtype"), + Token::StructEnd, + ], + ); + + // optional newtype with no content field (bytes tag) + assert_de_tokens( + &AdjacentlyTagged::Newtype::>(None), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 1, + }, + Token::Bytes(b"t"), + Token::Str("Newtype"), + Token::StructEnd, + ], + ); + // tuple with tag first assert_tokens( &AdjacentlyTagged::Tuple::(1, 1), @@ -1205,6 +1433,44 @@ fn test_adjacently_tagged_enum() { ], ); + // tuple with tag first (integer tag) + assert_de_tokens( + &AdjacentlyTagged::Tuple::(1, 1), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(0), // tag field + Token::Str("Tuple"), + Token::U64(1), // content field + Token::Tuple { len: 2 }, + Token::U8(1), + Token::U8(1), + Token::TupleEnd, + Token::StructEnd, + ], + ); + + // tuple with tag first (bytes tag) + assert_de_tokens( + &AdjacentlyTagged::Tuple::(1, 1), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"t"), + Token::Str("Tuple"), + Token::Bytes(b"c"), + Token::Tuple { len: 2 }, + Token::U8(1), + Token::U8(1), + Token::TupleEnd, + Token::StructEnd, + ], + ); + // tuple with content first assert_de_tokens( &AdjacentlyTagged::Tuple::(1, 1), @@ -1224,6 +1490,44 @@ fn test_adjacently_tagged_enum() { ], ); + // tuple with content first (integer tag) + assert_de_tokens( + &AdjacentlyTagged::Tuple::(1, 1), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(1), // content field + Token::Tuple { len: 2 }, + Token::U8(1), + Token::U8(1), + Token::TupleEnd, + Token::U64(0), // tag field + Token::Str("Tuple"), + Token::StructEnd, + ], + ); + + // tuple with content first (bytes tag) + assert_de_tokens( + &AdjacentlyTagged::Tuple::(1, 1), + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"c"), + Token::Tuple { len: 2 }, + Token::U8(1), + Token::U8(1), + Token::TupleEnd, + Token::Bytes(b"t"), + Token::Str("Tuple"), + Token::StructEnd, + ], + ); + // struct with tag first assert_tokens( &AdjacentlyTagged::Struct:: { f: 1 }, @@ -1246,6 +1550,50 @@ fn test_adjacently_tagged_enum() { ], ); + // struct with tag first (integer tag) + assert_de_tokens( + &AdjacentlyTagged::Struct:: { f: 1 }, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(0), // tag field + Token::Str("Struct"), + Token::U64(1), // content field + Token::Struct { + name: "Struct", + len: 1, + }, + Token::Str("f"), + Token::U8(1), + Token::StructEnd, + Token::StructEnd, + ], + ); + + // struct with tag first (bytes tag) + assert_de_tokens( + &AdjacentlyTagged::Struct:: { f: 1 }, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"t"), + Token::Str("Struct"), + Token::Bytes(b"c"), + Token::Struct { + name: "Struct", + len: 1, + }, + Token::Str("f"), + Token::U8(1), + Token::StructEnd, + Token::StructEnd, + ], + ); + // struct with content first assert_de_tokens( &AdjacentlyTagged::Struct:: { f: 1 }, @@ -1267,6 +1615,50 @@ fn test_adjacently_tagged_enum() { Token::StructEnd, ], ); + + // struct with content first (integer tag) + assert_de_tokens( + &AdjacentlyTagged::Struct:: { f: 1 }, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(1), // content field + Token::Struct { + name: "Struct", + len: 1, + }, + Token::Str("f"), + Token::U8(1), + Token::StructEnd, + Token::U64(0), // tag field + Token::Str("Struct"), + Token::StructEnd, + ], + ); + + // struct with content first (bytes tag) + assert_de_tokens( + &AdjacentlyTagged::Struct:: { f: 1 }, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"c"), + Token::Struct { + name: "Struct", + len: 1, + }, + Token::Str("f"), + Token::U8(1), + Token::StructEnd, + Token::Bytes(b"t"), + Token::Str("Struct"), + Token::StructEnd, + ], + ); } #[test] @@ -1292,6 +1684,126 @@ fn test_adjacently_tagged_enum_deny_unknown_fields() { ], ); + assert_de_tokens( + &AdjacentlyTagged::Unit, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(0), // tag field + Token::Str("Unit"), + Token::U64(1), // content field + Token::Unit, + Token::StructEnd, + ], + ); + + assert_de_tokens( + &AdjacentlyTagged::Unit, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"t"), + Token::Str("Unit"), + Token::Bytes(b"c"), + Token::Unit, + Token::StructEnd, + ], + ); + + assert_de_tokens( + &AdjacentlyTagged::Unit, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("t"), + Token::Str("Unit"), + Token::U64(1), // content field + Token::Unit, + Token::StructEnd, + ], + ); + + assert_de_tokens( + &AdjacentlyTagged::Unit, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(0), // tag field + Token::Str("Unit"), + Token::Str("c"), + Token::Unit, + Token::StructEnd, + ], + ); + + assert_de_tokens( + &AdjacentlyTagged::Unit, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"t"), + Token::Str("Unit"), + Token::U64(1), // content field + Token::Unit, + Token::StructEnd, + ], + ); + + assert_de_tokens( + &AdjacentlyTagged::Unit, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"t"), + Token::Str("Unit"), + Token::Str("c"), + Token::Unit, + Token::StructEnd, + ], + ); + + assert_de_tokens( + &AdjacentlyTagged::Unit, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("c"), + Token::Unit, + Token::Bytes(b"t"), + Token::Str("Unit"), + Token::StructEnd, + ], + ); + + assert_de_tokens( + &AdjacentlyTagged::Unit, + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Str("c"), + Token::Unit, + Token::Bytes(b"t"), + Token::Str("Unit"), + Token::StructEnd, + ], + ); + assert_de_tokens_error::( &[ Token::Struct { @@ -1330,6 +1842,54 @@ fn test_adjacently_tagged_enum_deny_unknown_fields() { ], r#"invalid value: string "h", expected "t" or "c""#, ); + + assert_de_tokens_error::( + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(2), + ], + r#"invalid value: integer `2`, expected "t" or "c""#, + ); + + assert_de_tokens_error::( + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::U64(0), // tag field + Token::Str("Unit"), + Token::U64(3), + ], + r#"invalid value: integer `3`, expected "t" or "c""#, + ); + + assert_de_tokens_error::( + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"h"), + ], + r#"invalid value: byte array, expected "t" or "c""#, + ); + + assert_de_tokens_error::( + &[ + Token::Struct { + name: "AdjacentlyTagged", + len: 2, + }, + Token::Bytes(b"c"), + Token::Unit, + Token::Bytes(b"h"), + ], + r#"invalid value: byte array, expected "t" or "c""#, + ); } #[test]