Compare commits

...

21 Commits

Author SHA1 Message Date
David Tolnay 3e4a23cbd0 Release 1.0.161 2023-05-04 16:45:18 -07:00
David Tolnay 6326ceec3f Don't panic in serde_test on running out of tokens 2023-05-04 16:38:20 -07:00
David Tolnay 8f4d37c7ec Convert serde_test's assert_next_token from macro to function 2023-05-04 16:34:14 -07:00
David Tolnay 1b8290b318 Convert serde_test's unexpected from macro to function 2023-05-04 16:30:34 -07:00
David Tolnay 48193fbccd Merge pull request #2435 from Mingun/hitchhiker-guide
Don't panic in serde_test
2023-05-04 16:27:35 -07:00
Mingun ac8ea72d88 Don't panic in serde_test
Panics lead to reporting errors in tests inside of serde_test internals,
returning errors moves the report location to the corresponding assert_tokens
expression
2023-04-30 00:06:51 +05:00
David Tolnay f583401284 Merge pull request #2433 from Mingun/rm-gitattributes
Remove unused after .gitattributes
2023-04-26 12:04:04 -07:00
Mingun 2d88228b7d Remove unused after a649190a4d .gitattributes 2023-04-26 23:54:09 +05:00
David Tolnay 0c6a2bbf79 Release 1.0.160 2023-04-10 22:15:49 -07:00
David Tolnay a80d830f27 Merge pull request #2426 from compiler-errors/dont-doc-private
Make derived serializer/deserializer internals `doc(hidden)`
2023-04-10 22:12:35 -07:00
Michael Goulet 5f3fd9994e Make serializer/deserializer internals doc(hidden) 2023-04-10 21:41:50 -07:00
David Tolnay d6de911855 Release 1.0.159 2023-03-27 22:05:58 -07:00
David Tolnay 04af32230e Merge pull request #2422 from dtolnay/emptyattr
Accept empty #[serde()] attribute
2023-03-27 22:05:18 -07:00
David Tolnay 4cb8d079f8 Accept empty #[serde()] attribute 2023-03-27 22:00:46 -07:00
David Tolnay 6ab55a1e52 Add regression test for issue 2415
Currently fails:

    error: unexpected end of input, unexpected token in nested attribute, expected ident
     --> test_suite/tests/regression/issue2415.rs:4:9
      |
    4 | #[serde()]
      |         ^
2023-03-27 22:00:01 -07:00
David Tolnay acfd19cb46 Release serde_derive_internals 0.27.0 2023-03-20 04:32:49 -07:00
David Tolnay e3058105f0 Release 1.0.158 2023-03-20 04:24:27 -07:00
David Tolnay dc200a6450 Reformat comments of non-public serde_derive internals
Fixes these being treated as "tests" by `cargo test` in serde_derive:

    running 3 tests
    test src/internals/check.rs - internals::check::check_remote_generic (line 23) ... FAILED
    test src/internals/check.rs - internals::check::check_remote_generic (line 29) ... FAILED
    test src/lib.rs - (line 3) ... ok

    failures:

    ---- src/internals/check.rs - internals::check::check_remote_generic (line 23) stdout ----
    error: unknown start of token: \u{2026}
     --> src/internals/check.rs:25:20
      |
    4 | struct Generic<T> {…}
      |                    ^

    error: cannot find attribute `serde` in this scope
     --> src/internals/check.rs:24:3
      |
    3 | #[serde(remote = "Generic")]
      |   ^^^^^
      |
      = note: `serde` is in scope, but it is a crate, not an attribute

    error[E0392]: parameter `T` is never used
     --> src/internals/check.rs:25:16
      |
    4 | struct Generic<T> {…}
      |                ^ unused parameter
      |
      = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
      = help: if you intended `T` to be a const parameter, use `const T: usize` instead

    ---- src/internals/check.rs - internals::check::check_remote_generic (line 29) stdout ----
    error: unknown start of token: \u{2026}
     --> src/internals/check.rs:31:21
      |
    4 | struct ConcreteDef {…}
      |                     ^

    error: cannot find attribute `serde` in this scope
     --> src/internals/check.rs:30:3
      |
    3 | #[serde(remote = "Generic<T>")]
      |   ^^^^^
      |
      = note: `serde` is in scope, but it is a crate, not an attribute
2023-03-20 04:23:46 -07:00
David Tolnay 2c0999a0b9 Merge pull request #2410 from serde-rs/attrvalue
Check for None-delimited group in attribute value
2023-03-20 04:23:33 -07:00
David Tolnay dd460f82a1 Check for None-delimited group in attribute value 2023-03-20 04:16:52 -07:00
David Tolnay c3d637f397 Add regression test for issue 2409 2023-03-20 03:59:43 -07:00
17 changed files with 205 additions and 161 deletions
-1
View File
@@ -1 +0,0 @@
test_suite/tests/expand/*.expanded.rs linguist-generated
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "1.0.157" # remember to update html_root_url and serde_derive dependency version = "1.0.161" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs" build = "build.rs"
categories = ["encoding", "no-std"] categories = ["encoding", "no-std"]
@@ -15,7 +15,7 @@ repository = "https://github.com/serde-rs/serde"
rust-version = "1.19" rust-version = "1.19"
[dependencies] [dependencies]
serde_derive = { version = "=1.0.157", optional = true, path = "../serde_derive" } serde_derive = { version = "=1.0.161", optional = true, path = "../serde_derive" }
[dev-dependencies] [dev-dependencies]
serde_derive = { version = "1.0", path = "../serde_derive" } serde_derive = { version = "1.0", path = "../serde_derive" }
+1 -1
View File
@@ -93,7 +93,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here. // Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.157")] #![doc(html_root_url = "https://docs.rs/serde/1.0.161")]
// Support using Serde without the standard library! // Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and // Unstable functionality only if the user asks for it. For tracking and
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.157" # remember to update html_root_url version = "1.0.161" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std"] categories = ["no-std"]
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -24,7 +24,7 @@ proc-macro = true
[dependencies] [dependencies]
proc-macro2 = "1.0" proc-macro2 = "1.0"
quote = "1.0" quote = "1.0"
syn = "2.0" syn = "2.0.3"
[dev-dependencies] [dev-dependencies]
serde = { version = "1.0", path = "../serde" } serde = { version = "1.0", path = "../serde" }
+18
View File
@@ -419,6 +419,7 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
let expecting = cattrs.expecting().unwrap_or(&expecting); let expecting = cattrs.expecting().unwrap_or(&expecting);
quote_block! { quote_block! {
#[doc(hidden)]
struct __Visitor; struct __Visitor;
impl<'de> _serde::de::Visitor<'de> for __Visitor { impl<'de> _serde::de::Visitor<'de> for __Visitor {
@@ -515,6 +516,7 @@ fn deserialize_tuple(
}; };
quote_block! { quote_block! {
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause { struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -605,6 +607,7 @@ fn deserialize_tuple_in_place(
let place_life = place_lifetime(); let place_life = place_lifetime();
quote_block! { quote_block! {
#[doc(hidden)]
struct __Visitor #in_place_impl_generics #where_clause { struct __Visitor #in_place_impl_generics #where_clause {
place: &#place_life mut #this_type #ty_generics, place: &#place_life mut #this_type #ty_generics,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1020,6 +1023,7 @@ fn deserialize_struct(
quote_block! { quote_block! {
#field_visitor #field_visitor
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause { struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1132,6 +1136,7 @@ fn deserialize_struct_in_place(
Some(quote_block! { Some(quote_block! {
#field_visitor #field_visitor
#[doc(hidden)]
struct __Visitor #in_place_impl_generics #where_clause { struct __Visitor #in_place_impl_generics #where_clause {
place: &#place_life mut #this_type #ty_generics, place: &#place_life mut #this_type #ty_generics,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1203,6 +1208,7 @@ fn prepare_enum_variant_enum(
let variants_stmt = { let variants_stmt = {
let variant_names = variant_names_idents.iter().map(|(name, _, _)| name); let variant_names = variant_names_idents.iter().map(|(name, _, _)| name);
quote! { quote! {
#[doc(hidden)]
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
} }
}; };
@@ -1275,6 +1281,7 @@ fn deserialize_externally_tagged_enum(
quote_block! { quote_block! {
#variant_visitor #variant_visitor
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause { struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1522,6 +1529,7 @@ fn deserialize_adjacently_tagged_enum(
#variants_stmt #variants_stmt
#[doc(hidden)]
struct __Seed #de_impl_generics #where_clause { struct __Seed #de_impl_generics #where_clause {
field: __Field, field: __Field,
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -1541,6 +1549,7 @@ fn deserialize_adjacently_tagged_enum(
} }
} }
#[doc(hidden)]
struct __Visitor #de_impl_generics #where_clause { struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -1643,6 +1652,7 @@ fn deserialize_adjacently_tagged_enum(
} }
} }
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[#tag, #content]; const FIELDS: &'static [&'static str] = &[#tag, #content];
_serde::Deserializer::deserialize_struct( _serde::Deserializer::deserialize_struct(
__deserializer, __deserializer,
@@ -1954,11 +1964,13 @@ fn deserialize_generated_identifier(
quote_block! { quote_block! {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[doc(hidden)]
enum __Field #lifetime { enum __Field #lifetime {
#(#field_idents,)* #(#field_idents,)*
#ignore_variant #ignore_variant
} }
#[doc(hidden)]
struct __FieldVisitor; struct __FieldVisitor;
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
@@ -2046,11 +2058,13 @@ fn deserialize_custom_identifier(
None None
} else if is_variant { } else if is_variant {
let variants = quote! { let variants = quote! {
#[doc(hidden)]
const VARIANTS: &'static [&'static str] = &[ #(#names),* ]; const VARIANTS: &'static [&'static str] = &[ #(#names),* ];
}; };
Some(variants) Some(variants)
} else { } else {
let fields = quote! { let fields = quote! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#names),* ]; const FIELDS: &'static [&'static str] = &[ #(#names),* ];
}; };
Some(fields) Some(fields)
@@ -2072,6 +2086,7 @@ fn deserialize_custom_identifier(
quote_block! { quote_block! {
#names_const #names_const
#[doc(hidden)]
struct __FieldVisitor #de_impl_generics #where_clause { struct __FieldVisitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>, marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>, lifetime: _serde::__private::PhantomData<&#delife ()>,
@@ -2406,6 +2421,7 @@ fn deserialize_struct_as_struct_visitor(
.flat_map(|(_, _, aliases)| aliases); .flat_map(|(_, _, aliases)| aliases);
quote_block! { quote_block! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
} }
}; };
@@ -2684,6 +2700,7 @@ fn deserialize_struct_as_struct_in_place_visitor(
let fields_stmt = { let fields_stmt = {
let field_names = field_names_idents.iter().map(|(name, _, _)| name); let field_names = field_names_idents.iter().map(|(name, _, _)| name);
quote_block! { quote_block! {
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
} }
}; };
@@ -2864,6 +2881,7 @@ fn wrap_deserialize_with(
let delife = params.borrowed.de_lifetime(); let delife = params.borrowed.de_lifetime();
let wrapper = quote! { let wrapper = quote! {
#[doc(hidden)]
struct __DeserializeWith #de_impl_generics #where_clause { struct __DeserializeWith #de_impl_generics #where_clause {
value: #value_ty, value: #value_ty,
phantom: _serde::__private::PhantomData<#this_type #ty_generics>, phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
+28 -5
View File
@@ -307,6 +307,12 @@ impl Container {
continue; continue;
} }
if let syn::Meta::List(meta) = &attr.meta {
if meta.tokens.is_empty() {
continue;
}
}
if let Err(err) = attr.parse_nested_meta(|meta| { if let Err(err) = attr.parse_nested_meta(|meta| {
if meta.path == RENAME { if meta.path == RENAME {
// #[serde(rename = "foo")] // #[serde(rename = "foo")]
@@ -762,6 +768,12 @@ impl Variant {
continue; continue;
} }
if let syn::Meta::List(meta) = &attr.meta {
if meta.tokens.is_empty() {
continue;
}
}
if let Err(err) = attr.parse_nested_meta(|meta| { if let Err(err) = attr.parse_nested_meta(|meta| {
if meta.path == RENAME { if meta.path == RENAME {
// #[serde(rename = "foo")] // #[serde(rename = "foo")]
@@ -1033,6 +1045,12 @@ impl Field {
continue; continue;
} }
if let syn::Meta::List(meta) = &attr.meta {
if meta.tokens.is_empty() {
continue;
}
}
if let Err(err) = attr.parse_nested_meta(|meta| { if let Err(err) = attr.parse_nested_meta(|meta| {
if meta.path == RENAME { if meta.path == RENAME {
// #[serde(rename = "foo")] // #[serde(rename = "foo")]
@@ -1381,12 +1399,18 @@ fn get_lit_str2(
meta_item_name: Symbol, meta_item_name: Symbol,
meta: &ParseNestedMeta, meta: &ParseNestedMeta,
) -> syn::Result<Option<syn::LitStr>> { ) -> syn::Result<Option<syn::LitStr>> {
match meta.value()?.parse()? { let expr: syn::Expr = meta.value()?.parse()?;
syn::Expr::Lit(syn::ExprLit { let mut value = &expr;
while let syn::Expr::Group(e) = value {
value = &e.expr;
}
if let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit), lit: syn::Lit::Str(lit),
.. ..
}) => Ok(Some(lit)), }) = value
expr => { {
Ok(Some(lit.clone()))
} else {
cx.error_spanned_by( cx.error_spanned_by(
expr, expr,
format!( format!(
@@ -1397,7 +1421,6 @@ fn get_lit_str2(
Ok(None) Ok(None)
} }
} }
}
fn parse_lit_into_path( fn parse_lit_into_path(
cx: &Ctxt, cx: &Ctxt,
+31 -32
View File
@@ -3,8 +3,8 @@ use internals::attr::{Identifier, TagType};
use internals::{ungroup, Ctxt, Derive}; use internals::{ungroup, Ctxt, Derive};
use syn::{Member, Type}; use syn::{Member, Type};
/// Cross-cutting checks that require looking at more than a single attrs // Cross-cutting checks that require looking at more than a single attrs object.
/// object. Simpler checks should happen when parsing and building the attrs. // Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_remote_generic(cx, cont); check_remote_generic(cx, cont);
check_getter(cx, cont); check_getter(cx, cont);
@@ -17,18 +17,18 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_from_and_try_from(cx, cont); check_from_and_try_from(cx, cont);
} }
/// Remote derive definition type must have either all of the generics of the // Remote derive definition type must have either all of the generics of the
/// remote type: // remote type:
/// //
/// #[serde(remote = "Generic")] // #[serde(remote = "Generic")]
/// struct Generic<T> {…} // struct Generic<T> {…}
/// //
/// or none of them, i.e. defining impls for one concrete instantiation of the // or none of them, i.e. defining impls for one concrete instantiation of the
/// remote type only: // remote type only:
/// //
/// #[serde(remote = "Generic<T>")] // #[serde(remote = "Generic<T>")]
/// struct ConcreteDef {…} // struct ConcreteDef {…}
/// //
fn check_remote_generic(cx: &Ctxt, cont: &Container) { fn check_remote_generic(cx: &Ctxt, cont: &Container) {
if let Some(remote) = cont.attrs.remote() { if let Some(remote) = cont.attrs.remote() {
let local_has_generic = !cont.generics.params.is_empty(); let local_has_generic = !cont.generics.params.is_empty();
@@ -39,8 +39,8 @@ fn check_remote_generic(cx: &Ctxt, cont: &Container) {
} }
} }
/// Getters are only allowed inside structs (not enums) with the `remote` // Getters are only allowed inside structs (not enums) with the `remote`
/// attribute. // attribute.
fn check_getter(cx: &Ctxt, cont: &Container) { fn check_getter(cx: &Ctxt, cont: &Container) {
match cont.data { match cont.data {
Data::Enum(_) => { Data::Enum(_) => {
@@ -62,7 +62,7 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
} }
} }
/// Flattening has some restrictions we can test. // Flattening has some restrictions we can test.
fn check_flatten(cx: &Ctxt, cont: &Container) { fn check_flatten(cx: &Ctxt, cont: &Container) {
match &cont.data { match &cont.data {
Data::Enum(variants) => { Data::Enum(variants) => {
@@ -101,12 +101,12 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
} }
} }
/// The `other` attribute must be used at most once and it must be the last // The `other` attribute must be used at most once and it must be the last
/// variant of an enum. // variant of an enum.
/// //
/// Inside a `variant_identifier` all variants must be unit variants. Inside a // Inside a `variant_identifier` all variants must be unit variants. Inside a
/// `field_identifier` all but possibly one variant must be unit variants. The // `field_identifier` all but possibly one variant must be unit variants. The
/// last variant may be a newtype variant which is an implicit "other" case. // last variant may be a newtype variant which is an implicit "other" case.
fn check_identifier(cx: &Ctxt, cont: &Container) { fn check_identifier(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data { let variants = match &cont.data {
Data::Enum(variants) => variants, Data::Enum(variants) => variants,
@@ -189,8 +189,8 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
} }
} }
/// Skip-(de)serializing attributes are not allowed on variants marked // Skip-(de)serializing attributes are not allowed on variants marked
/// (de)serialize_with. // (de)serialize_with.
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data { let variants = match &cont.data {
Data::Enum(variants) => variants, Data::Enum(variants) => variants,
@@ -264,10 +264,9 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
} }
} }
/// The tag of an internally-tagged struct variant must not be // The tag of an internally-tagged struct variant must not be the same as either
/// the same as either one of its fields, as this would result in // one of its fields, as this would result in duplicate keys in the serialized
/// duplicate keys in the serialized output and/or ambiguity in // output and/or ambiguity in the to-be-deserialized input.
/// the to-be-deserialized input.
fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data { let variants = match &cont.data {
Data::Enum(variants) => variants, Data::Enum(variants) => variants,
@@ -313,8 +312,8 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
} }
} }
/// In the case of adjacently-tagged enums, the type and the // In the case of adjacently-tagged enums, the type and the contents tag must
/// contents tag must differ, for the same reason. // differ, for the same reason.
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
let (type_tag, content_tag) = match cont.attrs.tag() { let (type_tag, content_tag) = match cont.attrs.tag() {
TagType::Adjacent { tag, content } => (tag, content), TagType::Adjacent { tag, content } => (tag, content),
@@ -332,7 +331,7 @@ fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
} }
} }
/// Enums and unit structs cannot be transparent. // Enums and unit structs cannot be transparent.
fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
if !cont.attrs.transparent() { if !cont.attrs.transparent() {
return; return;
+1 -1
View File
@@ -13,7 +13,7 @@
//! //!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html //! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.157")] #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.161")]
#![allow(unknown_lints, bare_trait_objects)] #![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints // Ignored clippy lints
#![allow( #![allow(
+3
View File
@@ -719,6 +719,7 @@ fn serialize_adjacently_tagged_variant(
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote_block! { quote_block! {
#[doc(hidden)]
struct __AdjacentlyTagged #wrapper_generics #where_clause { struct __AdjacentlyTagged #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*), data: (#(&'__a #fields_ty,)*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>, phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -982,6 +983,7 @@ fn serialize_struct_variant_with_flatten(
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
quote_block! { quote_block! {
#[doc(hidden)]
struct __EnumFlatten #wrapper_generics #where_clause { struct __EnumFlatten #wrapper_generics #where_clause {
data: (#(&'__a #fields_ty,)*), data: (#(&'__a #fields_ty,)*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>, phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
@@ -1212,6 +1214,7 @@ fn wrap_serialize_with(
}); });
quote!({ quote!({
#[doc(hidden)]
struct __SerializeWith #wrapper_impl_generics #where_clause { struct __SerializeWith #wrapper_impl_generics #where_clause {
values: (#(&'__a #field_tys, )*), values: (#(&'__a #field_tys, )*),
phantom: _serde::__private::PhantomData<#this_type #ty_generics>, phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive_internals" name = "serde_derive_internals"
version = "0.26.0" # remember to update html_root_url version = "0.27.0" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
description = "AST representation used by Serde derive macros. Unstable." description = "AST representation used by Serde derive macros. Unstable."
documentation = "https://docs.rs/serde_derive_internals" documentation = "https://docs.rs/serde_derive_internals"
+1 -1
View File
@@ -1,4 +1,4 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.26.0")] #![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.27.0")]
#![allow(unknown_lints, bare_trait_objects)] #![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints // Ignored clippy lints
#![allow( #![allow(
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_test" name = "serde_test"
version = "1.0.157" # remember to update html_root_url version = "1.0.161" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs" build = "build.rs"
categories = ["development-tools::testing"] categories = ["development-tools::testing"]
+79 -91
View File
@@ -12,32 +12,29 @@ pub struct Deserializer<'de> {
tokens: &'de [Token], tokens: &'de [Token],
} }
macro_rules! assert_next_token { fn assert_next_token(de: &mut Deserializer, expected: Token) -> Result<(), Error> {
($de:expr, $expected:expr) => { match de.next_token_opt() {
match $de.next_token_opt() { Some(token) if token == expected => Ok(()),
Some(token) if token == $expected => {} Some(other) => Err(de::Error::custom(format!(
Some(other) => panic!(
"expected Token::{} but deserialization wants Token::{}", "expected Token::{} but deserialization wants Token::{}",
other, $expected other, expected,
), ))),
None => panic!( None => Err(de::Error::custom(format!(
"end of tokens but deserialization wants Token::{}", "end of tokens but deserialization wants Token::{}",
$expected expected,
), ))),
} }
};
} }
macro_rules! unexpected { fn unexpected(token: Token) -> Error {
($token:expr) => { de::Error::custom(format!(
panic!("deserialization did not expect this token: {}", $token) "deserialization did not expect this token: {}",
}; token,
))
} }
macro_rules! end_of_tokens { fn end_of_tokens() -> Error {
() => { de::Error::custom("ran out of tokens to deserialize")
panic!("ran out of tokens to deserialize")
};
} }
impl<'de> Deserializer<'de> { impl<'de> Deserializer<'de> {
@@ -49,11 +46,8 @@ impl<'de> Deserializer<'de> {
self.tokens.first().cloned() self.tokens.first().cloned()
} }
fn peek_token(&self) -> Token { fn peek_token(&self) -> Result<Token, Error> {
match self.peek_token_opt() { self.peek_token_opt().ok_or_else(end_of_tokens)
Some(token) => token,
None => end_of_tokens!(),
}
} }
pub fn next_token_opt(&mut self) -> Option<Token> { pub fn next_token_opt(&mut self) -> Option<Token> {
@@ -66,14 +60,10 @@ impl<'de> Deserializer<'de> {
} }
} }
fn next_token(&mut self) -> Token { fn next_token(&mut self) -> Result<Token, Error> {
match self.tokens.split_first() { let (&first, rest) = self.tokens.split_first().ok_or_else(end_of_tokens)?;
Some((&first, rest)) => {
self.tokens = rest; self.tokens = rest;
first Ok(first)
}
None => end_of_tokens!(),
}
} }
pub fn remaining(&self) -> usize { pub fn remaining(&self) -> usize {
@@ -94,7 +84,7 @@ impl<'de> Deserializer<'de> {
len: len, len: len,
end: end, end: end,
})?; })?;
assert_next_token!(self, end); assert_next_token(self, end)?;
Ok(value) Ok(value)
} }
@@ -112,7 +102,7 @@ impl<'de> Deserializer<'de> {
len: len, len: len,
end: end, end: end,
})?; })?;
assert_next_token!(self, end); assert_next_token(self, end)?;
Ok(value) Ok(value)
} }
} }
@@ -129,7 +119,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
let token = self.next_token(); let token = self.next_token()?;
match token { match token {
Token::Bool(v) => visitor.visit_bool(v), Token::Bool(v) => visitor.visit_bool(v),
Token::I8(v) => visitor.visit_i8(v), Token::I8(v) => visitor.visit_i8(v),
@@ -161,50 +151,50 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
Token::Map { len } => self.visit_map(len, Token::MapEnd, visitor), Token::Map { len } => self.visit_map(len, Token::MapEnd, visitor),
Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor), Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor),
Token::Enum { .. } => { Token::Enum { .. } => {
let variant = self.next_token(); let variant = self.next_token()?;
let next = self.peek_token(); let next = self.peek_token()?;
match (variant, next) { match (variant, next) {
(Token::Str(variant), Token::Unit) => { (Token::Str(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_str(variant) visitor.visit_str(variant)
} }
(Token::BorrowedStr(variant), Token::Unit) => { (Token::BorrowedStr(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_borrowed_str(variant) visitor.visit_borrowed_str(variant)
} }
(Token::String(variant), Token::Unit) => { (Token::String(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_string(variant.to_string()) visitor.visit_string(variant.to_string())
} }
(Token::Bytes(variant), Token::Unit) => { (Token::Bytes(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_bytes(variant) visitor.visit_bytes(variant)
} }
(Token::BorrowedBytes(variant), Token::Unit) => { (Token::BorrowedBytes(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_borrowed_bytes(variant) visitor.visit_borrowed_bytes(variant)
} }
(Token::ByteBuf(variant), Token::Unit) => { (Token::ByteBuf(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_byte_buf(variant.to_vec()) visitor.visit_byte_buf(variant.to_vec())
} }
(Token::U8(variant), Token::Unit) => { (Token::U8(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_u8(variant) visitor.visit_u8(variant)
} }
(Token::U16(variant), Token::Unit) => { (Token::U16(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_u16(variant) visitor.visit_u16(variant)
} }
(Token::U32(variant), Token::Unit) => { (Token::U32(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_u32(variant) visitor.visit_u32(variant)
} }
(Token::U64(variant), Token::Unit) => { (Token::U64(variant), Token::Unit) => {
self.next_token(); self.next_token()?;
visitor.visit_u64(variant) visitor.visit_u64(variant)
} }
(variant, Token::Unit) => unexpected!(variant), (variant, Token::Unit) => Err(unexpected(variant)),
(variant, _) => { (variant, _) => {
visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any)) visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any))
} }
@@ -232,9 +222,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
| Token::MapEnd | Token::MapEnd
| Token::StructEnd | Token::StructEnd
| Token::TupleVariantEnd | Token::TupleVariantEnd
| Token::StructVariantEnd => { | Token::StructVariantEnd => Err(unexpected(token)),
unexpected!(token);
}
} }
} }
@@ -242,13 +230,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::Unit | Token::None => { Token::Unit | Token::None => {
self.next_token(); self.next_token()?;
visitor.visit_none() visitor.visit_none()
} }
Token::Some => { Token::Some => {
self.next_token(); self.next_token()?;
visitor.visit_some(self) visitor.visit_some(self)
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -264,9 +252,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::Enum { name: n } if name == n => { Token::Enum { name: n } if name == n => {
self.next_token(); self.next_token()?;
visitor.visit_enum(DeserializerEnumVisitor { de: self }) visitor.visit_enum(DeserializerEnumVisitor { de: self })
} }
@@ -286,9 +274,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::UnitStruct { .. } => { Token::UnitStruct { .. } => {
assert_next_token!(self, Token::UnitStruct { name: name }); assert_next_token(self, Token::UnitStruct { name: name })?;
visitor.visit_unit() visitor.visit_unit()
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -303,9 +291,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::NewtypeStruct { .. } => { Token::NewtypeStruct { .. } => {
assert_next_token!(self, Token::NewtypeStruct { name: name }); assert_next_token(self, Token::NewtypeStruct { name: name })?;
visitor.visit_newtype_struct(self) visitor.visit_newtype_struct(self)
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -316,21 +304,21 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::Unit | Token::UnitStruct { .. } => { Token::Unit | Token::UnitStruct { .. } => {
self.next_token(); self.next_token()?;
visitor.visit_unit() visitor.visit_unit()
} }
Token::Seq { .. } => { Token::Seq { .. } => {
self.next_token(); self.next_token()?;
self.visit_seq(Some(len), Token::SeqEnd, visitor) self.visit_seq(Some(len), Token::SeqEnd, visitor)
} }
Token::Tuple { .. } => { Token::Tuple { .. } => {
self.next_token(); self.next_token()?;
self.visit_seq(Some(len), Token::TupleEnd, visitor) self.visit_seq(Some(len), Token::TupleEnd, visitor)
} }
Token::TupleStruct { .. } => { Token::TupleStruct { .. } => {
self.next_token(); self.next_token()?;
self.visit_seq(Some(len), Token::TupleStructEnd, visitor) self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -346,25 +334,25 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::Unit => { Token::Unit => {
self.next_token(); self.next_token()?;
visitor.visit_unit() visitor.visit_unit()
} }
Token::UnitStruct { .. } => { Token::UnitStruct { .. } => {
assert_next_token!(self, Token::UnitStruct { name: name }); assert_next_token(self, Token::UnitStruct { name: name })?;
visitor.visit_unit() visitor.visit_unit()
} }
Token::Seq { .. } => { Token::Seq { .. } => {
self.next_token(); self.next_token()?;
self.visit_seq(Some(len), Token::SeqEnd, visitor) self.visit_seq(Some(len), Token::SeqEnd, visitor)
} }
Token::Tuple { .. } => { Token::Tuple { .. } => {
self.next_token(); self.next_token()?;
self.visit_seq(Some(len), Token::TupleEnd, visitor) self.visit_seq(Some(len), Token::TupleEnd, visitor)
} }
Token::TupleStruct { len: n, .. } => { Token::TupleStruct { len: n, .. } => {
assert_next_token!(self, Token::TupleStruct { name: name, len: n }); assert_next_token(self, Token::TupleStruct { name: name, len: n })?;
self.visit_seq(Some(len), Token::TupleStructEnd, visitor) self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -380,13 +368,13 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.peek_token() { match self.peek_token()? {
Token::Struct { len: n, .. } => { Token::Struct { len: n, .. } => {
assert_next_token!(self, Token::Struct { name: name, len: n }); assert_next_token(self, Token::Struct { name: name, len: n })?;
self.visit_map(Some(fields.len()), Token::StructEnd, visitor) self.visit_map(Some(fields.len()), Token::StructEnd, visitor)
} }
Token::Map { .. } => { Token::Map { .. } => {
self.next_token(); self.next_token()?;
self.visit_map(Some(fields.len()), Token::MapEnd, visitor) self.visit_map(Some(fields.len()), Token::MapEnd, visitor)
} }
_ => self.deserialize_any(visitor), _ => self.deserialize_any(visitor),
@@ -476,7 +464,7 @@ impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where where
V: DeserializeSeed<'de>, V: DeserializeSeed<'de>,
{ {
match self.de.peek_token() { match self.de.peek_token()? {
Token::UnitVariant { variant: v, .. } Token::UnitVariant { variant: v, .. }
| Token::NewtypeVariant { variant: v, .. } | Token::NewtypeVariant { variant: v, .. }
| Token::TupleVariant { variant: v, .. } | Token::TupleVariant { variant: v, .. }
@@ -497,9 +485,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
type Error = Error; type Error = Error;
fn unit_variant(self) -> Result<(), Error> { fn unit_variant(self) -> Result<(), Error> {
match self.de.peek_token() { match self.de.peek_token()? {
Token::UnitVariant { .. } => { Token::UnitVariant { .. } => {
self.de.next_token(); self.de.next_token()?;
Ok(()) Ok(())
} }
_ => Deserialize::deserialize(self.de), _ => Deserialize::deserialize(self.de),
@@ -510,9 +498,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where where
T: DeserializeSeed<'de>, T: DeserializeSeed<'de>,
{ {
match self.de.peek_token() { match self.de.peek_token()? {
Token::NewtypeVariant { .. } => { Token::NewtypeVariant { .. } => {
self.de.next_token(); self.de.next_token()?;
seed.deserialize(self.de) seed.deserialize(self.de)
} }
_ => seed.deserialize(self.de), _ => seed.deserialize(self.de),
@@ -523,26 +511,26 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.de.peek_token() { match self.de.peek_token()? {
Token::TupleVariant { len: enum_len, .. } => { Token::TupleVariant { len: enum_len, .. } => {
let token = self.de.next_token(); let token = self.de.next_token()?;
if len == enum_len { if len == enum_len {
self.de self.de
.visit_seq(Some(len), Token::TupleVariantEnd, visitor) .visit_seq(Some(len), Token::TupleVariantEnd, visitor)
} else { } else {
unexpected!(token); Err(unexpected(token))
} }
} }
Token::Seq { Token::Seq {
len: Some(enum_len), len: Some(enum_len),
} => { } => {
let token = self.de.next_token(); let token = self.de.next_token()?;
if len == enum_len { if len == enum_len {
self.de.visit_seq(Some(len), Token::SeqEnd, visitor) self.de.visit_seq(Some(len), Token::SeqEnd, visitor)
} else { } else {
unexpected!(token); Err(unexpected(token))
} }
} }
_ => de::Deserializer::deserialize_any(self.de, visitor), _ => de::Deserializer::deserialize_any(self.de, visitor),
@@ -557,27 +545,27 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self.de.peek_token() { match self.de.peek_token()? {
Token::StructVariant { len: enum_len, .. } => { Token::StructVariant { len: enum_len, .. } => {
let token = self.de.next_token(); let token = self.de.next_token()?;
if fields.len() == enum_len { if fields.len() == enum_len {
self.de self.de
.visit_map(Some(fields.len()), Token::StructVariantEnd, visitor) .visit_map(Some(fields.len()), Token::StructVariantEnd, visitor)
} else { } else {
unexpected!(token); Err(unexpected(token))
} }
} }
Token::Map { Token::Map {
len: Some(enum_len), len: Some(enum_len),
} => { } => {
let token = self.de.next_token(); let token = self.de.next_token()?;
if fields.len() == enum_len { if fields.len() == enum_len {
self.de self.de
.visit_map(Some(fields.len()), Token::MapEnd, visitor) .visit_map(Some(fields.len()), Token::MapEnd, visitor)
} else { } else {
unexpected!(token); Err(unexpected(token))
} }
} }
_ => de::Deserializer::deserialize_any(self.de, visitor), _ => de::Deserializer::deserialize_any(self.de, visitor),
@@ -622,7 +610,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
.deserialize(BytesDeserializer { value: variant }) .deserialize(BytesDeserializer { value: variant })
.map(Some), .map(Some),
Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some), Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
Some(other) => unexpected!(other), Some(other) => Err(unexpected(other)),
None => Ok(None), None => Ok(None),
} }
} }
@@ -641,7 +629,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
}; };
seed.deserialize(SeqAccessDeserializer::new(visitor))? seed.deserialize(SeqAccessDeserializer::new(visitor))?
}; };
assert_next_token!(self.de, Token::TupleVariantEnd); assert_next_token(self.de, Token::TupleVariantEnd)?;
Ok(value) Ok(value)
} }
EnumFormat::Map => { EnumFormat::Map => {
@@ -653,7 +641,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
}; };
seed.deserialize(MapAccessDeserializer::new(visitor))? seed.deserialize(MapAccessDeserializer::new(visitor))?
}; };
assert_next_token!(self.de, Token::StructVariantEnd); assert_next_token(self.de, Token::StructVariantEnd)?;
Ok(value) Ok(value)
} }
EnumFormat::Any => seed.deserialize(&mut *self.de), EnumFormat::Any => seed.deserialize(&mut *self.de),
+1 -1
View File
@@ -140,7 +140,7 @@
//! # } //! # }
//! ``` //! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.157")] #![doc(html_root_url = "https://docs.rs/serde_test/1.0.161")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
// Ignored clippy lints // Ignored clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))] #![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))]
+6 -8
View File
@@ -63,14 +63,12 @@ macro_rules! assert_next_token {
($ser:expr, $actual:expr, $pat:pat, $guard:expr) => { ($ser:expr, $actual:expr, $pat:pat, $guard:expr) => {
match $ser.next_token() { match $ser.next_token() {
Some($pat) if $guard => {} Some($pat) if $guard => {}
Some(expected) => { Some(expected) => return Err(ser::Error::custom(
panic!("expected Token::{} but serialized as {}", format!("expected Token::{} but serialized as {}", expected, $actual)
expected, $actual); )),
} None => return Err(ser::Error::custom(
None => { format!("expected end of tokens, but {} was serialized", $actual)
panic!("expected end of tokens, but {} was serialized", )),
$actual);
}
} }
}; };
} }
+11
View File
@@ -0,0 +1,11 @@
use serde::Deserialize;
macro_rules! bug {
($serde_path:literal) => {
#[derive(Deserialize)]
#[serde(crate = $serde_path)]
pub struct Struct;
};
}
bug!("serde");
+5
View File
@@ -0,0 +1,5 @@
use serde_derive::Serialize;
#[derive(Serialize)]
#[serde()]
pub struct S;