diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index 1cf079f2e..65e311b20 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -2547,12 +2547,12 @@ pub trait IdentifierDeserializer<'de, E: Error> { fn borrowed(self) -> Self::BorrowedDeserializer; } -impl<'de, E> IdentifierDeserializer<'de, E> for u32 +impl<'de, E> IdentifierDeserializer<'de, E> for u64 where E: Error, { - type Deserializer = >::Deserializer; - type BorrowedDeserializer = >::Deserializer; + type Deserializer = >::Deserializer; + type BorrowedDeserializer = >::Deserializer; fn from(self) -> Self::Deserializer { self.into_deserializer() diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index a898f5ba2..624270293 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1965,6 +1965,8 @@ fn deserialize_generated_identifier( } } +// Generates `Deserialize::deserialize` body for an enum with +// `serde(field_identifier)` or `serde(variant_identifier)` attribute. fn deserialize_custom_identifier( params: &Parameters, variants: &[Variant], @@ -1982,6 +1984,9 @@ fn deserialize_custom_identifier( let (ordinary, fallthrough) = if let Some(last) = variants.last() { let last_ident = &last.ident; if last.attrs.other() { + // Process `serde(other)` attribute. It would always be found on the + // last variant (checked in `check_identifier`), so all preceding + // are ordinary variants. let ordinary = &variants[..variants.len() - 1]; let fallthrough = quote!(_serde::__private::Ok(#this::#last_ident)); (ordinary, Some((fallthrough.clone(), fallthrough))) @@ -2137,7 +2142,8 @@ fn deserialize_identifier( (None, None, None, None) }; - let (fallthrough_arm, fallthrough_borrowed_arm) = if let Some(fallthrough) = fallthrough { + let (fallthrough_arm, fallthrough_borrowed_arm) = if let Some(fallthrough) = fallthrough.clone() + { fallthrough } else if is_variant { let fallthrough = quote! { @@ -2151,8 +2157,19 @@ fn deserialize_identifier( (fallthrough.clone(), fallthrough) }; + let u64_fallthrough_arm = if let Some((fallthrough, _)) = fallthrough { + fallthrough + } else { + let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len()); + quote! { + _serde::__private::Err(_serde::de::Error::invalid_value( + _serde::de::Unexpected::Unsigned(__value), + &#fallthrough_msg, + )) + } + }; + let variant_indices = 0_u64..; - let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len()); let visit_other = if collect_other_fields { quote! { fn visit_bool<__E>(self, __value: bool) -> _serde::__private::Result @@ -2256,10 +2273,7 @@ fn deserialize_identifier( #( #variant_indices => _serde::__private::Ok(#main_constructors), )* - _ => _serde::__private::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &#fallthrough_msg, - )) + _ => #u64_fallthrough_arm, } } } diff --git a/serde_test/src/de.rs b/serde_test/src/de.rs index 4d3d0675e..673a0c0e1 100644 --- a/serde_test/src/de.rs +++ b/serde_test/src/de.rs @@ -168,14 +168,42 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { self.next_token(); visitor.visit_str(variant) } + (Token::BorrowedStr(variant), Token::Unit) => { + self.next_token(); + visitor.visit_borrowed_str(variant) + } + (Token::String(variant), Token::Unit) => { + self.next_token(); + visitor.visit_string(variant.to_string()) + } (Token::Bytes(variant), Token::Unit) => { self.next_token(); visitor.visit_bytes(variant) } + (Token::BorrowedBytes(variant), Token::Unit) => { + self.next_token(); + visitor.visit_borrowed_bytes(variant) + } + (Token::ByteBuf(variant), Token::Unit) => { + self.next_token(); + visitor.visit_byte_buf(variant.to_vec()) + } + (Token::U8(variant), Token::Unit) => { + self.next_token(); + visitor.visit_u8(variant) + } + (Token::U16(variant), Token::Unit) => { + self.next_token(); + visitor.visit_u16(variant) + } (Token::U32(variant), Token::Unit) => { self.next_token(); visitor.visit_u32(variant) } + (Token::U64(variant), Token::Unit) => { + self.next_token(); + visitor.visit_u64(variant) + } (variant, Token::Unit) => unexpected!(variant), (variant, _) => { visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any)) diff --git a/test_suite/tests/expand/de_enum.expanded.rs b/test_suite/tests/expand/de_enum.expanded.rs index d721ff02f..0207a9123 100644 --- a/test_suite/tests/expand/de_enum.expanded.rs +++ b/test_suite/tests/expand/de_enum.expanded.rs @@ -614,12 +614,7 @@ const _: () = { 1u64 => _serde::__private::Ok(__Field::__field1), 2u64 => _serde::__private::Ok(__Field::__field2), 3u64 => _serde::__private::Ok(__Field::__field3), - _ => _serde::__private::Err( - _serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 4", - ), - ), + _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( @@ -1152,12 +1147,7 @@ const _: () = { 1u64 => _serde::__private::Ok(__Field::__field1), 2u64 => _serde::__private::Ok(__Field::__field2), 3u64 => _serde::__private::Ok(__Field::__field3), - _ => _serde::__private::Err( - _serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 4", - ), - ), + _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( diff --git a/test_suite/tests/expand/default_ty_param.expanded.rs b/test_suite/tests/expand/default_ty_param.expanded.rs index 082c6249e..f3de6dbaa 100644 --- a/test_suite/tests/expand/default_ty_param.expanded.rs +++ b/test_suite/tests/expand/default_ty_param.expanded.rs @@ -77,10 +77,7 @@ const _: () = { { match __value { 0u64 => _serde::__private::Ok(__Field::__field0), - _ => _serde::__private::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - )), + _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( @@ -284,10 +281,7 @@ const _: () = { { match __value { 0u64 => _serde::__private::Ok(__Field::__field0), - _ => _serde::__private::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - )), + _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( diff --git a/test_suite/tests/expand/generic_enum.expanded.rs b/test_suite/tests/expand/generic_enum.expanded.rs index 627dbf604..4d309d406 100644 --- a/test_suite/tests/expand/generic_enum.expanded.rs +++ b/test_suite/tests/expand/generic_enum.expanded.rs @@ -394,12 +394,7 @@ const _: () = { match __value { 0u64 => _serde::__private::Ok(__Field::__field0), 1u64 => _serde::__private::Ok(__Field::__field1), - _ => _serde::__private::Err( - _serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 2", - ), - ), + _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( diff --git a/test_suite/tests/expand/generic_struct.expanded.rs b/test_suite/tests/expand/generic_struct.expanded.rs index 9a9162b3a..fadecf6dd 100644 --- a/test_suite/tests/expand/generic_struct.expanded.rs +++ b/test_suite/tests/expand/generic_struct.expanded.rs @@ -73,10 +73,7 @@ const _: () = { { match __value { 0u64 => _serde::__private::Ok(__Field::__field0), - _ => _serde::__private::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - )), + _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( @@ -280,10 +277,7 @@ const _: () = { { match __value { 0u64 => _serde::__private::Ok(__Field::__field0), - _ => _serde::__private::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - )), + _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( diff --git a/test_suite/tests/expand/lifetimes.expanded.rs b/test_suite/tests/expand/lifetimes.expanded.rs index 796a02d23..9a13fb508 100644 --- a/test_suite/tests/expand/lifetimes.expanded.rs +++ b/test_suite/tests/expand/lifetimes.expanded.rs @@ -281,12 +281,7 @@ const _: () = { { match __value { 0u64 => _serde::__private::Ok(__Field::__field0), - _ => _serde::__private::Err( - _serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - ), - ), + _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( @@ -494,12 +489,7 @@ const _: () = { { match __value { 0u64 => _serde::__private::Ok(__Field::__field0), - _ => _serde::__private::Err( - _serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 1", - ), - ), + _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( diff --git a/test_suite/tests/expand/named_map.expanded.rs b/test_suite/tests/expand/named_map.expanded.rs index 54d3a0ac0..6a93e6f45 100644 --- a/test_suite/tests/expand/named_map.expanded.rs +++ b/test_suite/tests/expand/named_map.expanded.rs @@ -100,10 +100,7 @@ const _: () = { 0u64 => _serde::__private::Ok(__Field::__field0), 1u64 => _serde::__private::Ok(__Field::__field1), 2u64 => _serde::__private::Ok(__Field::__field2), - _ => _serde::__private::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 3", - )), + _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( @@ -415,10 +412,7 @@ const _: () = { 0u64 => _serde::__private::Ok(__Field::__field0), 1u64 => _serde::__private::Ok(__Field::__field1), 2u64 => _serde::__private::Ok(__Field::__field2), - _ => _serde::__private::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &"field index 0 <= i < 3", - )), + _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( diff --git a/test_suite/tests/test_de.rs b/test_suite/tests/test_de.rs index a0261bd35..cb861374f 100644 --- a/test_suite/tests/test_de.rs +++ b/test_suite/tests/test_de.rs @@ -622,6 +622,24 @@ declare_tests! { Token::I32(2), Token::MapEnd, ], + Struct { a: 1, b: 2, c: 0 } => &[ + Token::Map { len: Some(3) }, + Token::U8(0), + Token::I32(1), + + Token::U8(1), + Token::I32(2), + Token::MapEnd, + ], + Struct { a: 1, b: 2, c: 0 } => &[ + Token::Map { len: Some(3) }, + Token::U16(0), + Token::I32(1), + + Token::U16(1), + Token::I32(2), + Token::MapEnd, + ], Struct { a: 1, b: 2, c: 0 } => &[ Token::Map { len: Some(3) }, Token::U32(0), @@ -631,6 +649,34 @@ declare_tests! { Token::I32(2), Token::MapEnd, ], + Struct { a: 1, b: 2, c: 0 } => &[ + Token::Map { len: Some(3) }, + Token::U64(0), + Token::I32(1), + + Token::U64(1), + Token::I32(2), + Token::MapEnd, + ], + // Mixed key types + Struct { a: 1, b: 2, c: 0 } => &[ + Token::Map { len: Some(3) }, + Token::U8(0), + Token::I32(1), + + Token::U64(1), + Token::I32(2), + Token::MapEnd, + ], + Struct { a: 1, b: 2, c: 0 } => &[ + Token::Map { len: Some(3) }, + Token::U8(0), + Token::I32(1), + + Token::Str("b"), + Token::I32(2), + Token::MapEnd, + ], Struct { a: 1, b: 2, c: 0 } => &[ Token::Struct { name: "Struct", len: 2 }, Token::Str("a"), @@ -647,6 +693,46 @@ declare_tests! { Token::SeqEnd, ], } + test_struct_borrowed_keys { + Struct { a: 1, b: 2, c: 0 } => &[ + Token::Map { len: Some(3) }, + Token::BorrowedStr("a"), + Token::I32(1), + + Token::BorrowedStr("b"), + Token::I32(2), + Token::MapEnd, + ], + Struct { a: 1, b: 2, c: 0 } => &[ + Token::Struct { name: "Struct", len: 2 }, + Token::BorrowedStr("a"), + Token::I32(1), + + Token::BorrowedStr("b"), + Token::I32(2), + Token::StructEnd, + ], + } + test_struct_owned_keys { + Struct { a: 1, b: 2, c: 0 } => &[ + Token::Map { len: Some(3) }, + Token::String("a"), + Token::I32(1), + + Token::String("b"), + Token::I32(2), + Token::MapEnd, + ], + Struct { a: 1, b: 2, c: 0 } => &[ + Token::Struct { name: "Struct", len: 2 }, + Token::String("a"), + Token::I32(1), + + Token::String("b"), + Token::I32(2), + Token::StructEnd, + ], + } test_struct_with_skip { Struct { a: 1, b: 2, c: 0 } => &[ Token::Map { len: Some(3) }, @@ -663,6 +749,21 @@ declare_tests! { Token::I32(4), Token::MapEnd, ], + Struct { a: 1, b: 2, c: 0 } => &[ + Token::Map { len: Some(3) }, + Token::U8(0), + Token::I32(1), + + Token::U16(1), + Token::I32(2), + + Token::U32(2), + Token::I32(3), + + Token::U64(3), + Token::I32(4), + Token::MapEnd, + ], Struct { a: 1, b: 2, c: 0 } => &[ Token::Struct { name: "Struct", len: 2 }, Token::Str("a"), @@ -780,6 +881,26 @@ declare_tests! { Token::Str("Unit"), Token::Unit, ], + EnumOther::Unit => &[ + Token::Enum { name: "EnumOther" }, + Token::U8(0), + Token::Unit, + ], + EnumOther::Unit => &[ + Token::Enum { name: "EnumOther" }, + Token::U16(0), + Token::Unit, + ], + EnumOther::Unit => &[ + Token::Enum { name: "EnumOther" }, + Token::U32(0), + Token::Unit, + ], + EnumOther::Unit => &[ + Token::Enum { name: "EnumOther" }, + Token::U64(0), + Token::Unit, + ], } test_enum_other { EnumOther::Other => &[ @@ -787,6 +908,26 @@ declare_tests! { Token::Str("Foo"), Token::Unit, ], + EnumOther::Other => &[ + Token::Enum { name: "EnumOther" }, + Token::U8(42), + Token::Unit, + ], + EnumOther::Other => &[ + Token::Enum { name: "EnumOther" }, + Token::U16(42), + Token::Unit, + ], + EnumOther::Other => &[ + Token::Enum { name: "EnumOther" }, + Token::U32(42), + Token::Unit, + ], + EnumOther::Other => &[ + Token::Enum { name: "EnumOther" }, + Token::U64(42), + Token::Unit, + ], } test_box { Box::new(0i32) => &[Token::I32(0)], diff --git a/test_suite/tests/test_identifier.rs b/test_suite/tests/test_identifier.rs index eba7d4dac..12c6697e6 100644 --- a/test_suite/tests/test_identifier.rs +++ b/test_suite/tests/test_identifier.rs @@ -1,3 +1,4 @@ +//! Tests for `#[serde(field_identifier)]` and `#[serde(variant_identifier)]` use serde::Deserialize; use serde_test::{assert_de_tokens, Token}; @@ -27,6 +28,10 @@ fn test_field_identifier() { Bbb, } + assert_de_tokens(&F::Aaa, &[Token::U8(0)]); + assert_de_tokens(&F::Aaa, &[Token::U16(0)]); + assert_de_tokens(&F::Aaa, &[Token::U32(0)]); + assert_de_tokens(&F::Aaa, &[Token::U64(0)]); assert_de_tokens(&F::Aaa, &[Token::Str("aaa")]); assert_de_tokens(&F::Aaa, &[Token::Bytes(b"aaa")]); } @@ -42,6 +47,10 @@ fn test_unit_fallthrough() { Other, } + assert_de_tokens(&F::Other, &[Token::U8(42)]); + assert_de_tokens(&F::Other, &[Token::U16(42)]); + assert_de_tokens(&F::Other, &[Token::U32(42)]); + assert_de_tokens(&F::Other, &[Token::U64(42)]); assert_de_tokens(&F::Other, &[Token::Str("x")]); } @@ -68,5 +77,9 @@ fn test_newtype_fallthrough_generic() { Other(T), } + assert_de_tokens(&F::Other(42u8), &[Token::U8(42)]); + assert_de_tokens(&F::Other(42u16), &[Token::U16(42)]); + assert_de_tokens(&F::Other(42u32), &[Token::U32(42)]); + assert_de_tokens(&F::Other(42u64), &[Token::U64(42)]); assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]); }