Compare commits

...

40 Commits

Author SHA1 Message Date
David Tolnay dcbc3e0162 Release 1.0.165 2023-07-03 04:21:59 -07:00
David Tolnay 0289d31724 Fix -Zminimal-versions build 2023-07-03 04:21:14 -07:00
David Tolnay 015e39776f No need for single-element vec for chaining one element 2023-07-02 21:11:09 -07:00
David Tolnay 6a9a21f178 Resolve useless_conversion clippy lint in test
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
       --> test_suite/tests/test_de.rs:202:12
        |
    202 |     .chain(vec![Token::MapEnd].into_iter())
        |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![Token::MapEnd]`
        |
    note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
       --> /home/david/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:522:12
        |
    522 |         U: IntoIterator<Item = Self::Item>,
        |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
        = note: `-D clippy::useless-conversion` implied by `-D clippy::all`
2023-07-02 21:10:06 -07:00
David Tolnay 81ac54b20d Resolve redundant_closure_call clippy lint
error: try not to call a closure in the expression where it is declared
        --> serde/src/de/impls.rs:1590:76
         |
    1590 |                       <(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port))
         |                                                                              ^^^^^^^^^^^^^^
    ...
    1620 | / parse_socket_impl!("IPv6 socket address" net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(
    1621 | |     ip, port, 0, 0
    1622 | | ));
         | |__- in this macro invocation
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
         = note: `-D clippy::redundant-closure-call` implied by `-D clippy::all`
         = note: this error originates in the macro `parse_socket_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
2023-07-02 21:08:50 -07:00
David Tolnay 6b4e75520a Resolve explicit_iter_loop pedantic clippy lint
error: it is more concise to loop over references to containers instead of using explicit iteration methods
        --> serde/src/private/de.rs:2761:22
         |
    2761 |         for entry in self.0.iter_mut() {
         |                      ^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *self.0`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop
         = note: `-D clippy::explicit-iter-loop` implied by `-D clippy::pedantic`

    error: it is more concise to loop over references to containers instead of using explicit iteration methods
       --> serde_derive/src/internals/check.rs:202:20
        |
    202 |     for variant in variants.iter() {
        |                    ^^^^^^^^^^^^^^^ help: to write this more concisely, try: `variants`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop
        = note: `-D clippy::explicit-iter-loop` implied by `-D clippy::pedantic`

    error: it is more concise to loop over references to containers instead of using explicit iteration methods
       --> serde_derive/src/bound.rs:262:28
        |
    262 |             for variant in variants.iter() {
        |                            ^^^^^^^^^^^^^^^ help: to write this more concisely, try: `variants`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop
2023-07-02 21:08:44 -07:00
David Tolnay b053b4f492 Touch up early return in Enum checks 2023-07-02 21:08:44 -07:00
David Tolnay c0ba323166 Support a manual trigger on CI workflow 2023-06-23 22:50:52 -07:00
David Tolnay 20a48c9580 Remove .clippy.toml in favor of respecting rust-version from Cargo.toml 2023-06-15 18:31:38 -07:00
David Tolnay 09938803af Resolve redundant_static_lifetimes clippy lint 2023-06-15 18:31:38 -07:00
David Tolnay 6d0b43a220 Resolve redundant_field_names clippy lint 2023-06-15 18:31:38 -07:00
David Tolnay 8a4dfa7231 Merge pull request #2466 from Mingun/fix-de-count-of-field
Fix incorrect count of fields passed to tuple deserialization methods
2023-06-07 22:13:08 -07:00
David Tolnay 107018c628 Release 1.0.164 2023-06-07 22:05:07 -07:00
David Tolnay a398237930 Point out serde(untagged) variants which are out of order
Previously if someone wrote an enum containing:

- `A` (untagged)
- `B` (tagged)
- `C` (tagged)
- `D` (untagged)
- `E` (tagged)
- `F` (untagged)

serde_derive would produce errors referring to B and E only, saying
you're supposed to put untagged variants at the end. The choice of B and
E for this error doesn't make a lot of sense because in order to resolve
the issue, the user must either:

- move A and D down

or:

- move B, C, and E up.

This commit changes the error to appear on A and D instead.
2023-06-07 21:49:30 -07:00
David Tolnay b63c65d7f5 Merge pull request #2470 from dtolnay/contentref
Reuse a single ContentRefDeserializer throughout untagged enum deserialization
2023-06-07 21:38:49 -07:00
David Tolnay f60324e883 Reuse a single ContentRefDeserializer throughout untagged enum deserialization 2023-06-07 21:33:14 -07:00
David Tolnay 361c23a09a Simplify enumerate().find(...) -> Iterator::position 2023-06-07 21:23:31 -07:00
David Tolnay 43b23c7ea0 Format PR 2403 with rustfmt 2023-06-07 21:18:30 -07:00
David Tolnay 6081497506 Resolve semicolon_if_nothing_returned pedantic clippy lint
error: consider adding a `;` to the last statement for consistent formatting
       --> serde_derive/src/internals/ast.rs:161:13
        |
    161 |             seen_untagged = variant.attrs.untagged()
        |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `seen_untagged = variant.attrs.untagged();`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
        = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D clippy::pedantic`

    error: consider adding a `;` to the last statement for consistent formatting
       --> serde_derive/src/internals/ast.rs:159:17
        |
    159 | ...   cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum")
        |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum");`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
2023-06-07 21:17:24 -07:00
David Ewert 48e5753e76 Allowed Enum variants to be individually marked as untagged (#2403) 2023-06-07 20:58:59 -07:00
David Tolnay bbba632ab3 Revert "Ui tests with compile_error resolved at call site"
This reverts commit e77db40b8d.
2023-06-07 20:50:51 -07:00
David Tolnay e77db40b8d Ui tests with compile_error resolved at call site 2023-06-07 20:02:04 -07:00
Mingun 2c1f62d4b4 Fix incorrect count of fields passed to tuple deserialization methods
This count should mean the number of fields expected in the serialized form,
so if some fields are skipped, they shouldn't be counted

Methods affected:
- Deserializer::deserialize_tuple
- Deserializer::deserialize_tuple_struct
- VariantAccess::tuple_variant
2023-05-28 23:17:05 +05:00
David Tolnay 1aebdc2760 Release serde_derive_internals 0.28.0 2023-05-25 08:20:10 -07:00
David Tolnay 705e58be8c Merge pull request #2464 from serde-rs/combine
Use syn::Error's combine() API instead of Vec<syn::Error>
2023-05-25 08:19:16 -07:00
David Tolnay 7c2c12aa43 Use syn::Error's combine() API instead of Vec<syn::Error> 2023-05-25 08:10:14 -07:00
David Tolnay a0f850f15b Show error details during miri setup in CI
Without this, if it fails, the only information printed is useless:

    Preparing a sysroot for Miri (target: x86_64-unknown-linux-gnu)...
    fatal error: failed to build sysroot; run `cargo miri setup` to see the error details
2023-05-23 08:29:47 -07:00
David Tolnay fccb9499bc Release 1.0.163 2023-05-10 00:47:53 -07:00
David Tolnay a139ab2572 Adjust PR 2446 with less overgeneralized name 2023-05-10 00:45:52 -07:00
David Tolnay 1d910a484c Format with rustfmt 1.5.2-nightly 2023-05-10 00:40:39 -07:00
David Tolnay ee9166ec97 Revise comments on the FlatMapDeserializer entry taker 2023-05-10 00:39:10 -07:00
David Tolnay b5a9eff32e Resolve while_let_on_iterator clippy lint
warning: this loop could be written as a `for` loop
        --> serde/src/private/de.rs:2905:9
         |
    2905 |         while let Some(item) = self.iter.next() {
         |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for item in self.iter.by_ref()`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
         = note: `#[warn(clippy::while_let_on_iterator)]` on by default
2023-05-10 00:23:38 -07:00
David Tolnay 9441a29663 Merge pull request #2446 from Mingun/dedup2
Eliminate some duplicated code
2023-05-10 00:13:44 -07:00
Mingun ab6588ef74 Extract duplicated code into a function 2023-05-08 10:39:30 +05:00
Mingun 1d11f03449 Extract logic of taking flattened fields into a function 2023-05-08 10:39:27 +05:00
Mingun e11d01fe1d Remove constructors for FlatMapAccess and FlatStructAccess
They are used only in one place each, so for simplifying understanding it is better to inline them
2023-05-08 09:40:06 +05:00
Mingun a901f50850 FlatMapAccess and FlatStructAccess does not need to be public 2023-05-08 09:37:15 +05:00
Mingun c399e9c368 Remove FlatInternallyTaggedAccess because it is the same as FlatMapAccess 2023-05-08 09:25:18 +05:00
David Tolnay 25381be0c9 Merge pull request #2442 from taiki-e/derive-build-script
Remove build script from serde_derive
2023-05-05 14:35:09 -07:00
Taiki Endo ef2a7c753f Remove build script from serde_derive
The current serde_derive's MSRV is 1.56, and both underscore consts and
ptr::addr_of! are always available.
2023-05-06 05:34:38 +09:00
33 changed files with 432 additions and 345 deletions
+2
View File
@@ -3,6 +3,7 @@ name: CI
on:
push:
pull_request:
workflow_dispatch:
schedule: [cron: "40 1 * * *"]
permissions:
@@ -149,6 +150,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@miri
- run: cargo miri setup
- run: cd serde && cargo miri test --features derive,rc,unstable
env:
MIRIFLAGS: -Zmiri-strict-provenance
-1
View File
@@ -1 +0,0 @@
msrv = "1.13.0"
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.162" # remember to update html_root_url and serde_derive dependency
version = "1.0.165" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["encoding", "no-std"]
@@ -15,7 +15,7 @@ repository = "https://github.com/serde-rs/serde"
rust-version = "1.19"
[dependencies]
serde_derive = { version = "=1.0.162", optional = true, path = "../serde_derive" }
serde_derive = { version = "=1.0.165", optional = true, path = "../serde_derive" }
[dev-dependencies]
serde_derive = { version = "1.0", path = "../serde_derive" }
+14 -17
View File
@@ -994,7 +994,8 @@ seq_impl!(
HashSet::clear,
HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()),
HashSet::reserve,
HashSet::insert);
HashSet::insert
);
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
@@ -1409,16 +1410,14 @@ macro_rules! map_impl {
}
#[cfg(any(feature = "std", feature = "alloc"))]
map_impl!(
BTreeMap<K: Ord, V>,
map,
BTreeMap::new());
map_impl!(BTreeMap<K: Ord, V>, map, BTreeMap::new());
#[cfg(feature = "std")]
map_impl!(
HashMap<K: Eq + Hash, V, S: BuildHasher + Default>,
map,
HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default()));
HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default())
);
////////////////////////////////////////////////////////////////////////////////
@@ -1588,7 +1587,7 @@ macro_rules! parse_socket_impl {
if deserializer.is_human_readable() {
deserializer.deserialize_str(FromStrVisitor::new($expecting))
} else {
<(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port))
<(_, u16)>::deserialize(deserializer).map($new)
}
}
}
@@ -1615,12 +1614,10 @@ impl<'de> Deserialize<'de> for net::SocketAddr {
}
#[cfg(feature = "std")]
parse_socket_impl!("IPv4 socket address" net::SocketAddrV4, net::SocketAddrV4::new);
parse_socket_impl!("IPv4 socket address" net::SocketAddrV4, |(ip, port)| net::SocketAddrV4::new(ip, port));
#[cfg(feature = "std")]
parse_socket_impl!("IPv6 socket address" net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(
ip, port, 0, 0
));
parse_socket_impl!("IPv6 socket address" net::SocketAddrV6, |(ip, port)| net::SocketAddrV6::new(ip, port, 0, 0));
////////////////////////////////////////////////////////////////////////////////
@@ -2099,7 +2096,7 @@ impl<'de> Deserialize<'de> for Duration {
}
}
const FIELDS: &'static [&'static str] = &["secs", "nanos"];
const FIELDS: &[&str] = &["secs", "nanos"];
deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor)
}
}
@@ -2241,7 +2238,7 @@ impl<'de> Deserialize<'de> for SystemTime {
}
}
const FIELDS: &'static [&'static str] = &["secs_since_epoch", "nanos_since_epoch"];
const FIELDS: &[&str] = &["secs_since_epoch", "nanos_since_epoch"];
let duration = try!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor));
#[cfg(not(no_systemtime_checked_add))]
let ret = UNIX_EPOCH
@@ -2309,7 +2306,7 @@ mod range {
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
pub const FIELDS: &'static [&'static str] = &["start", "end"];
pub const FIELDS: &[&str] = &["start", "end"];
// If this were outside of the serde crate, it would just use:
//
@@ -2535,7 +2532,7 @@ where
}
}
const VARIANTS: &'static [&'static str] = &["Unbounded", "Included", "Excluded"];
const VARIANTS: &[&str] = &["Unbounded", "Included", "Excluded"];
deserializer.deserialize_enum("Bound", VARIANTS, BoundVisitor(PhantomData))
}
@@ -2643,7 +2640,7 @@ where
}
}
const VARIANTS: &'static [&'static str] = &["Ok", "Err"];
const VARIANTS: &[&str] = &["Ok", "Err"];
deserializer.deserialize_enum("Result", VARIANTS, ResultVisitor(PhantomData))
}
@@ -2709,7 +2706,7 @@ struct FromStrVisitor<T> {
impl<T> FromStrVisitor<T> {
fn new(expecting: &'static str) -> Self {
FromStrVisitor {
expecting: expecting,
expecting,
ty: PhantomData,
}
}
+1 -1
View File
@@ -31,7 +31,7 @@ pub fn encode(c: char) -> Encode {
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
0
};
Encode { buf: buf, pos: pos }
Encode { buf, pos }
}
pub struct Encode {
+14 -18
View File
@@ -251,7 +251,7 @@ macro_rules! primitive_deserializer {
#[allow(missing_docs)]
pub fn new(value: $ty) -> Self {
$name {
value: value,
value,
marker: PhantomData,
}
}
@@ -330,7 +330,7 @@ impl<E> U32Deserializer<E> {
#[allow(missing_docs)]
pub fn new(value: u32) -> Self {
U32Deserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -419,7 +419,7 @@ impl<'a, E> StrDeserializer<'a, E> {
#[allow(missing_docs)]
pub fn new(value: &'a str) -> Self {
StrDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -498,7 +498,7 @@ impl<'de, E> BorrowedStrDeserializer<'de, E> {
/// Create a new borrowed deserializer from the given string.
pub fn new(value: &'de str) -> BorrowedStrDeserializer<'de, E> {
BorrowedStrDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -598,7 +598,7 @@ impl<E> StringDeserializer<E> {
#[allow(missing_docs)]
pub fn new(value: String) -> Self {
StringDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -701,7 +701,7 @@ impl<'a, E> CowStrDeserializer<'a, E> {
#[allow(missing_docs)]
pub fn new(value: Cow<'a, str>) -> Self {
CowStrDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -783,7 +783,7 @@ impl<'a, E> BytesDeserializer<'a, E> {
/// Create a new deserializer from the given bytes.
pub fn new(value: &'a [u8]) -> Self {
BytesDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -842,7 +842,7 @@ impl<'de, E> BorrowedBytesDeserializer<'de, E> {
/// Create a new borrowed deserializer from the given borrowed bytes.
pub fn new(value: &'de [u8]) -> Self {
BorrowedBytesDeserializer {
value: value,
value,
marker: PhantomData,
}
}
@@ -1053,7 +1053,7 @@ pub struct SeqAccessDeserializer<A> {
impl<A> SeqAccessDeserializer<A> {
/// Construct a new `SeqAccessDeserializer<A>`.
pub fn new(seq: A) -> Self {
SeqAccessDeserializer { seq: seq }
SeqAccessDeserializer { seq }
}
}
@@ -1454,7 +1454,7 @@ pub struct MapAccessDeserializer<A> {
impl<A> MapAccessDeserializer<A> {
/// Construct a new `MapAccessDeserializer<A>`.
pub fn new(map: A) -> Self {
MapAccessDeserializer { map: map }
MapAccessDeserializer { map }
}
}
@@ -1519,7 +1519,7 @@ pub struct EnumAccessDeserializer<A> {
impl<A> EnumAccessDeserializer<A> {
/// Construct a new `EnumAccessDeserializer<A>`.
pub fn new(access: A) -> Self {
EnumAccessDeserializer { access: access }
EnumAccessDeserializer { access }
}
}
@@ -1613,7 +1613,7 @@ mod private {
}
pub fn map_as_enum<A>(map: A) -> MapAsEnum<A> {
MapAsEnum { map: map }
MapAsEnum { map }
}
impl<'de, A> VariantAccess<'de> for MapAsEnum<A>
@@ -1637,10 +1637,7 @@ mod private {
where
V: Visitor<'de>,
{
self.map.next_value_seed(SeedTupleVariant {
len: len,
visitor: visitor,
})
self.map.next_value_seed(SeedTupleVariant { len, visitor })
}
fn struct_variant<V>(
@@ -1651,8 +1648,7 @@ mod private {
where
V: Visitor<'de>,
{
self.map
.next_value_seed(SeedStructVariant { visitor: visitor })
self.map.next_value_seed(SeedStructVariant { visitor })
}
}
+1 -1
View File
@@ -93,7 +93,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.162")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.165")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and
+61 -110
View File
@@ -518,7 +518,7 @@ mod content {
impl<'de> TagOrContentVisitor<'de> {
fn new(name: &'static str) -> Self {
TagOrContentVisitor {
name: name,
name,
value: PhantomData,
}
}
@@ -815,7 +815,7 @@ mod content {
pub fn new(name: &'static str, expecting: &'static str) -> Self {
TaggedContentVisitor {
tag_name: name,
expecting: expecting,
expecting,
value: PhantomData,
}
}
@@ -859,7 +859,7 @@ mod content {
};
let rest = de::value::SeqAccessDeserializer::new(seq);
Ok(TaggedContent {
tag: tag,
tag,
content: try!(Content::deserialize(rest)),
})
}
@@ -887,7 +887,7 @@ mod content {
match tag {
None => Err(de::Error::missing_field(self.tag_name)),
Some(tag) => Ok(TaggedContent {
tag: tag,
tag,
content: Content::Map(vec),
}),
}
@@ -1464,7 +1464,7 @@ mod content {
/// private API, don't use
pub fn new(content: Content<'de>) -> Self {
ContentDeserializer {
content: content,
content,
err: PhantomData,
}
}
@@ -1485,8 +1485,8 @@ mod content {
{
pub fn new(variant: Content<'de>, value: Option<Content<'de>>) -> EnumDeserializer<'de, E> {
EnumDeserializer {
variant: variant,
value: value,
variant,
value,
err: PhantomData,
}
}
@@ -2142,8 +2142,8 @@ mod content {
};
visitor.visit_enum(EnumRefDeserializer {
variant: variant,
value: value,
variant,
value,
err: PhantomData,
})
}
@@ -2187,12 +2187,20 @@ mod content {
/// private API, don't use
pub fn new(content: &'a Content<'de>) -> Self {
ContentRefDeserializer {
content: content,
content,
err: PhantomData,
}
}
}
impl<'a, 'de: 'a, E> Copy for ContentRefDeserializer<'a, 'de, E> {}
impl<'a, 'de: 'a, E> Clone for ContentRefDeserializer<'a, 'de, E> {
fn clone(&self) -> Self {
*self
}
}
struct EnumRefDeserializer<'a, 'de: 'a, E>
where
E: de::Error,
@@ -2488,8 +2496,8 @@ mod content {
/// Not public API.
pub fn new(type_name: &'a str, variant_name: &'a str) -> Self {
InternallyTaggedUnitVisitor {
type_name: type_name,
variant_name: variant_name,
type_name,
variant_name,
}
}
}
@@ -2533,8 +2541,8 @@ mod content {
/// Not public API.
pub fn new(type_name: &'a str, variant_name: &'a str) -> Self {
UntaggedUnitVisitor {
type_name: type_name,
variant_name: variant_name,
type_name,
variant_name,
}
}
}
@@ -2738,11 +2746,7 @@ where
where
V: Visitor<'de>,
{
visitor.visit_map(FlatInternallyTaggedAccess {
iter: self.0.iter_mut(),
pending: None,
_marker: PhantomData,
})
self.deserialize_map(visitor)
}
fn deserialize_enum<V>(
@@ -2754,17 +2758,8 @@ where
where
V: Visitor<'de>,
{
for item in self.0.iter_mut() {
// items in the vector are nulled out when used. So we can only use
// an item if it's still filled in and if the field is one we care
// about.
let use_item = match *item {
None => false,
Some((ref c, _)) => c.as_str().map_or(false, |x| variants.contains(&x)),
};
if use_item {
let (key, value) = item.take().unwrap();
for entry in self.0 {
if let Some((key, value)) = flat_map_take_entry(entry, variants) {
return visitor.visit_enum(EnumDeserializer::new(key, Some(value)));
}
}
@@ -2779,7 +2774,11 @@ where
where
V: Visitor<'de>,
{
visitor.visit_map(FlatMapAccess::new(self.0.iter()))
visitor.visit_map(FlatMapAccess {
iter: self.0.iter(),
pending_content: None,
_marker: PhantomData,
})
}
fn deserialize_struct<V>(
@@ -2791,7 +2790,12 @@ where
where
V: Visitor<'de>,
{
visitor.visit_map(FlatStructAccess::new(self.0.iter_mut(), fields))
visitor.visit_map(FlatStructAccess {
iter: self.0.iter_mut(),
pending_content: None,
fields,
_marker: PhantomData,
})
}
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
@@ -2845,25 +2849,12 @@ where
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapAccess<'a, 'de: 'a, E> {
struct FlatMapAccess<'a, 'de: 'a, E> {
iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<&'a Content<'de>>,
_marker: PhantomData<E>,
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> {
fn new(
iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>,
) -> FlatMapAccess<'a, 'de, E> {
FlatMapAccess {
iter: iter,
pending_content: None,
_marker: PhantomData,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
where
@@ -2878,6 +2869,10 @@ where
for item in &mut self.iter {
// Items in the vector are nulled out when used by a struct.
if let Some((ref key, ref content)) = *item {
// Do not take(), instead borrow this entry. The internally tagged
// enum does its own buffering so we can't tell whether this entry
// is going to be consumed. Borrowing here leaves the entry
// available for later flattened fields.
self.pending_content = Some(content);
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some);
}
@@ -2897,28 +2892,13 @@ where
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatStructAccess<'a, 'de: 'a, E> {
struct FlatStructAccess<'a, 'de: 'a, E> {
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<Content<'de>>,
fields: &'static [&'static str],
_marker: PhantomData<E>,
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatStructAccess<'a, 'de, E> {
fn new(
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
fields: &'static [&'static str],
) -> FlatStructAccess<'a, 'de, E> {
FlatStructAccess {
iter: iter,
pending_content: None,
fields: fields,
_marker: PhantomData,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E>
where
@@ -2930,17 +2910,8 @@ where
where
T: DeserializeSeed<'de>,
{
while let Some(item) = self.iter.next() {
// items in the vector are nulled out when used. So we can only use
// an item if it's still filled in and if the field is one we care
// about. In case we do not know which fields we want, we take them all.
let use_item = match *item {
None => false,
Some((ref c, _)) => c.as_str().map_or(false, |key| self.fields.contains(&key)),
};
if use_item {
let (key, content) = item.take().unwrap();
for entry in self.iter.by_ref() {
if let Some((key, content)) = flat_map_take_entry(entry, self.fields) {
self.pending_content = Some(content);
return seed.deserialize(ContentDeserializer::new(key)).map(Some);
}
@@ -2959,44 +2930,24 @@ where
}
}
/// Claims one key-value pair from a FlatMapDeserializer's field buffer if the
/// field name matches any of the recognized ones.
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatInternallyTaggedAccess<'a, 'de: 'a, E> {
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
pending: Option<&'a Content<'de>>,
_marker: PhantomData<E>,
}
fn flat_map_take_entry<'de>(
entry: &mut Option<(Content<'de>, Content<'de>)>,
recognized: &[&str],
) -> Option<(Content<'de>, Content<'de>)> {
// Entries in the FlatMapDeserializer buffer are nulled out as they get
// claimed for deserialization. We only use an entry if it is still present
// and if the field is one recognized by the current data structure.
let is_recognized = match entry {
None => false,
Some((k, _v)) => k.as_str().map_or(false, |name| recognized.contains(&name)),
};
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatInternallyTaggedAccess<'a, 'de, E>
where
E: Error,
{
type Error = E;
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
for item in &mut self.iter {
if let Some((ref key, ref content)) = *item {
// Do not take(), instead borrow this entry. The internally tagged
// enum does its own buffering so we can't tell whether this entry
// is going to be consumed. Borrowing here leaves the entry
// available for later flattened fields.
self.pending = Some(content);
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some);
}
}
Ok(None)
}
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.pending.take() {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => panic!("value is missing"),
}
if is_recognized {
entry.take()
} else {
None
}
}
+18 -18
View File
@@ -27,10 +27,10 @@ where
T: Serialize,
{
value.serialize(TaggedSerializer {
type_ident: type_ident,
variant_ident: variant_ident,
tag: tag,
variant_name: variant_name,
type_ident,
variant_ident,
tag,
variant_name,
delegate: serializer,
})
}
@@ -350,8 +350,8 @@ mod content {
impl<M> SerializeTupleVariantAsMapValue<M> {
pub fn new(map: M, name: &'static str, len: usize) -> Self {
SerializeTupleVariantAsMapValue {
map: map,
name: name,
map,
name,
fields: Vec::with_capacity(len),
}
}
@@ -390,8 +390,8 @@ mod content {
impl<M> SerializeStructVariantAsMapValue<M> {
pub fn new(map: M, name: &'static str, len: usize) -> Self {
SerializeStructVariantAsMapValue {
map: map,
name: name,
map,
name,
fields: Vec::with_capacity(len),
}
}
@@ -711,7 +711,7 @@ mod content {
len: usize,
) -> Result<Self::SerializeTupleStruct, E> {
Ok(SerializeTupleStruct {
name: name,
name,
fields: Vec::with_capacity(len),
error: PhantomData,
})
@@ -725,9 +725,9 @@ mod content {
len: usize,
) -> Result<Self::SerializeTupleVariant, E> {
Ok(SerializeTupleVariant {
name: name,
variant_index: variant_index,
variant: variant,
name,
variant_index,
variant,
fields: Vec::with_capacity(len),
error: PhantomData,
})
@@ -747,7 +747,7 @@ mod content {
len: usize,
) -> Result<Self::SerializeStruct, E> {
Ok(SerializeStruct {
name: name,
name,
fields: Vec::with_capacity(len),
error: PhantomData,
})
@@ -761,9 +761,9 @@ mod content {
len: usize,
) -> Result<Self::SerializeStructVariant, E> {
Ok(SerializeStructVariant {
name: name,
variant_index: variant_index,
variant: variant,
name,
variant_index,
variant,
fields: Vec::with_capacity(len),
error: PhantomData,
})
@@ -1273,8 +1273,8 @@ where
{
fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> {
FlatMapSerializeStructVariantAsMapValue {
map: map,
name: name,
map,
name,
fields: Vec::new(),
}
}
+1 -1
View File
@@ -713,7 +713,7 @@ impl Serialize for net::IpAddr {
}
#[cfg(feature = "std")]
const DEC_DIGITS_LUT: &'static [u8] = b"\
const DEC_DIGITS_LUT: &[u8] = b"\
0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\
4041424344454647484950515253545556575859\
-1
View File
@@ -1 +0,0 @@
msrv = "1.31.0"
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.162" # remember to update html_root_url
version = "1.0.165" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std"]
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -24,7 +24,7 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = "2.0.3"
syn = "2.0.21"
[dev-dependencies]
serde = { version = "1.0", path = "../serde" }
-38
View File
@@ -1,38 +0,0 @@
use std::env;
use std::process::Command;
use std::str;
// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let minor = match rustc_minor_version() {
Some(minor) => minor,
None => return,
};
// Underscore const names stabilized in Rust 1.37:
// https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html#using-unnamed-const-items-for-macros
if minor < 37 {
println!("cargo:rustc-cfg=no_underscore_consts");
}
// The ptr::addr_of! macro stabilized in Rust 1.51:
// https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis
if minor < 51 {
println!("cargo:rustc-cfg=no_ptr_addr_of");
}
}
fn rustc_minor_version() -> Option<u32> {
let rustc = env::var_os("RUSTC")?;
let output = Command::new(rustc).arg("--version").output().ok()?;
let version = str::from_utf8(&output.stdout).ok()?;
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return None;
}
pieces.next()?.parse().ok()
}
+1 -1
View File
@@ -259,7 +259,7 @@ pub fn with_bound(
};
match &cont.data {
Data::Enum(variants) => {
for variant in variants.iter() {
for variant in variants {
let relevant_fields = variant
.fields
.iter()
+76 -52
View File
@@ -15,9 +15,7 @@ use this;
use std::collections::BTreeSet;
use std::ptr;
pub fn expand_derive_deserialize(
input: &mut syn::DeriveInput,
) -> Result<TokenStream, Vec<syn::Error>> {
pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
replace_receiver(input);
let ctxt = Ctxt::new();
@@ -69,8 +67,6 @@ pub fn expand_derive_deserialize(
Ok(dummy::wrap_in_const(
cont.attrs.custom_serde_path(),
"DESERIALIZE",
ident,
impl_block,
))
}
@@ -449,14 +445,19 @@ fn deserialize_tuple(
cattrs: &attr::Container,
deserializer: Option<TokenStream>,
) -> Fragment {
assert!(!cattrs.has_flatten());
let field_count = fields
.iter()
.filter(|field| !field.attrs.skip_deserializing())
.count();
let this_type = &params.this_type;
let this_value = &params.this_value;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime();
assert!(!cattrs.has_flatten());
// If there are getters (implying private fields), construct the local type
// and use an `Into` conversion to get the remote type. If there are no
// getters then construct the target type directly.
@@ -497,19 +498,18 @@ fn deserialize_tuple(
}
};
let dispatch = if let Some(deserializer) = deserializer {
quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr))
quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #field_count, #visitor_expr))
} else if is_enum {
quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr))
quote!(_serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr))
} else if nfields == 1 {
let type_name = cattrs.name().deserialize_name();
quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr))
} else {
let type_name = cattrs.name().deserialize_name();
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr))
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr))
};
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing());
let visitor_var = if all_skipped {
let visitor_var = if field_count == 0 {
quote!(_)
} else {
quote!(mut __seq)
@@ -552,13 +552,18 @@ fn deserialize_tuple_in_place(
cattrs: &attr::Container,
deserializer: Option<TokenStream>,
) -> Fragment {
assert!(!cattrs.has_flatten());
let field_count = fields
.iter()
.filter(|field| !field.attrs.skip_deserializing())
.count();
let this_type = &params.this_type;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime();
assert!(!cattrs.has_flatten());
let is_enum = variant_ident.is_some();
let expecting = match variant_ident {
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
@@ -584,19 +589,18 @@ fn deserialize_tuple_in_place(
};
let dispatch = if let Some(deserializer) = deserializer {
quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr))
quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #field_count, #visitor_expr))
} else if is_enum {
quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr))
quote!(_serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr))
} else if nfields == 1 {
let type_name = cattrs.name().deserialize_name();
quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr))
} else {
let type_name = cattrs.name().deserialize_name();
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr))
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr))
};
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing());
let visitor_var = if all_skipped {
let visitor_var = if field_count == 0 {
quote!(_)
} else {
quote!(mut __seq)
@@ -1170,6 +1174,22 @@ fn deserialize_enum(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
// The variants have already been checked (in ast.rs) that all untagged variants appear at the end
match variants.iter().position(|var| var.attrs.untagged()) {
Some(variant_idx) => {
let (tagged, untagged) = variants.split_at(variant_idx);
let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs));
deserialize_untagged_enum_after(params, untagged, cattrs, Some(tagged_frag))
}
None => deserialize_homogeneous_enum(params, variants, cattrs),
}
}
fn deserialize_homogeneous_enum(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
match cattrs.tag() {
attr::TagType::External => deserialize_externally_tagged_enum(params, variants, cattrs),
@@ -1670,6 +1690,16 @@ fn deserialize_untagged_enum(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
let first_attempt = None;
deserialize_untagged_enum_after(params, variants, cattrs, first_attempt)
}
fn deserialize_untagged_enum_after(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
first_attempt: Option<Expr>,
) -> Fragment {
let attempts = variants
.iter()
@@ -1679,12 +1709,10 @@ fn deserialize_untagged_enum(
params,
variant,
cattrs,
quote!(
_serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content)
),
quote!(__deserializer),
))
});
let attempts = first_attempt.into_iter().chain(attempts);
// TODO this message could be better by saving the errors from the failed
// attempts. The heuristic used by TOML was to count the number of fields
// processed before an error, and use the error that happened after the
@@ -1699,6 +1727,7 @@ fn deserialize_untagged_enum(
quote_block! {
let __content = try!(<_serde::__private::de::Content as _serde::Deserialize>::deserialize(__deserializer));
let __deserializer = _serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content);
#(
if let _serde::__private::Ok(__ok) = #attempts {
@@ -3086,23 +3115,31 @@ struct DeTypeGenerics<'a>(&'a Parameters);
#[cfg(feature = "deserialize_in_place")]
struct InPlaceTypeGenerics<'a>(&'a Parameters);
fn de_type_generics_to_tokens(
mut generics: syn::Generics,
borrowed: &BorrowedLifetimes,
tokens: &mut TokenStream,
) {
if borrowed.de_lifetime_param().is_some() {
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
// Prepend 'de lifetime to list of generics
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
}
impl<'a> ToTokens for DeTypeGenerics<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let mut generics = self.0.generics.clone();
if self.0.borrowed.de_lifetime_param().is_some() {
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
de_type_generics_to_tokens(self.0.generics.clone(), &self.0.borrowed, tokens);
}
}
@@ -3115,20 +3152,7 @@ impl<'a> ToTokens for InPlaceTypeGenerics<'a> {
.chain(generics.params)
.collect();
if self.0.borrowed.de_lifetime_param().is_some() {
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
de_type_generics_to_tokens(generics, &self.0.borrowed, tokens);
}
}
+3 -19
View File
@@ -1,23 +1,11 @@
use proc_macro2::{Ident, TokenStream};
use quote::format_ident;
use proc_macro2::TokenStream;
use syn;
use try;
pub fn wrap_in_const(
serde_path: Option<&syn::Path>,
trait_: &str,
ty: &Ident,
code: TokenStream,
) -> TokenStream {
pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream {
let try_replacement = try::replacement();
let dummy_const = if cfg!(no_underscore_consts) {
format_ident!("_IMPL_{}_FOR_{}", trait_, unraw(ty))
} else {
format_ident!("_")
};
let use_serde = match serde_path {
Some(path) => quote! {
use #path as _serde;
@@ -31,14 +19,10 @@ pub fn wrap_in_const(
quote! {
#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = {
const _: () = {
#use_serde
#try_replacement
#code
};
}
}
fn unraw(ident: &Ident) -> String {
ident.to_string().trim_start_matches("r#").to_owned()
}
+15 -2
View File
@@ -140,7 +140,7 @@ fn enum_from_ast<'a>(
variants: &'a Punctuated<syn::Variant, Token![,]>,
container_default: &attr::Default,
) -> Vec<Variant<'a>> {
variants
let variants: Vec<Variant> = variants
.iter()
.map(|variant| {
let attrs = attr::Variant::from_ast(cx, variant);
@@ -154,7 +154,20 @@ fn enum_from_ast<'a>(
original: variant,
}
})
.collect()
.collect();
let index_of_last_tagged_variant = variants
.iter()
.rposition(|variant| !variant.attrs.untagged());
if let Some(index_of_last_tagged_variant) = index_of_last_tagged_variant {
for variant in &variants[..index_of_last_tagged_variant] {
if variant.attrs.untagged() {
cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum");
}
}
}
variants
}
fn struct_from_ast<'a>(
+9
View File
@@ -740,6 +740,7 @@ pub struct Variant {
serialize_with: Option<syn::ExprPath>,
deserialize_with: Option<syn::ExprPath>,
borrow: Option<BorrowAttribute>,
untagged: bool,
}
struct BorrowAttribute {
@@ -762,6 +763,7 @@ impl Variant {
let mut serialize_with = Attr::none(cx, SERIALIZE_WITH);
let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH);
let mut borrow = Attr::none(cx, BORROW);
let mut untagged = BoolAttr::none(cx, UNTAGGED);
for attr in &variant.attrs {
if attr.path() != SERDE {
@@ -879,6 +881,8 @@ impl Variant {
cx.error_spanned_by(variant, msg);
}
}
} else if meta.path == UNTAGGED {
untagged.set_true(&meta.path);
} else {
let path = meta.path.to_token_stream().to_string().replace(' ', "");
return Err(
@@ -905,6 +909,7 @@ impl Variant {
serialize_with: serialize_with.get(),
deserialize_with: deserialize_with.get(),
borrow: borrow.get(),
untagged: untagged.get(),
}
}
@@ -956,6 +961,10 @@ impl Variant {
pub fn deserialize_with(&self) -> Option<&syn::ExprPath> {
self.deserialize_with.as_ref()
}
pub fn untagged(&self) -> bool {
self.untagged
}
}
/// Represents field attribute information
+3 -7
View File
@@ -110,9 +110,7 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
fn check_identifier(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data {
Data::Enum(variants) => variants,
Data::Struct(_, _) => {
return;
}
Data::Struct(_, _) => return,
};
for (i, variant) in variants.iter().enumerate() {
@@ -194,12 +192,10 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
let variants = match &cont.data {
Data::Enum(variants) => variants,
Data::Struct(_, _) => {
return;
}
Data::Struct(_, _) => return,
};
for variant in variants.iter() {
for variant in variants {
if variant.attrs.serialize_with().is_some() {
if variant.attrs.skip_serializing() {
cx.error_spanned_by(
+12 -5
View File
@@ -44,12 +44,19 @@ impl Ctxt {
}
/// Consume this object, producing a formatted error string if there are errors.
pub fn check(self) -> Result<(), Vec<syn::Error>> {
let errors = self.errors.borrow_mut().take().unwrap();
match errors.len() {
0 => Ok(()),
_ => Err(errors),
pub fn check(self) -> syn::Result<()> {
let mut errors = self.errors.borrow_mut().take().unwrap().into_iter();
let mut combined = match errors.next() {
Some(first) => first,
None => return Ok(()),
};
for rest in errors {
combined.combine(rest);
}
Err(combined)
}
}
+3 -8
View File
@@ -13,7 +13,7 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.162")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.165")]
#![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints
#![allow(
@@ -92,7 +92,7 @@ mod try;
pub fn derive_serialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
ser::expand_derive_serialize(&mut input)
.unwrap_or_else(to_compile_errors)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
@@ -100,11 +100,6 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream {
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
de::expand_derive_deserialize(&mut input)
.unwrap_or_else(to_compile_errors)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
let compile_errors = errors.iter().map(syn::Error::to_compile_error);
quote!(#(#compile_errors)*)
}
+7 -22
View File
@@ -97,29 +97,14 @@ fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> Toke
let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
#[cfg(not(no_ptr_addr_of))]
{
quote! {
match _serde::__private::None::<&#type_ident #ty_generics> {
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
#(
let _ = _serde::__private::ptr::addr_of!(__v.#members);
)*
}
_ => {}
}
}
}
#[cfg(no_ptr_addr_of)]
{
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
quote! {
match _serde::__private::None::<#type_ident #ty_generics> {
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
_ => {}
quote! {
match _serde::__private::None::<&#type_ident #ty_generics> {
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
#(
let _ = _serde::__private::ptr::addr_of!(__v.#members);
)*
}
_ => {}
}
}
}
+8 -10
View File
@@ -10,9 +10,7 @@ use internals::{attr, replace_receiver, Ctxt, Derive};
use pretend;
use this;
pub fn expand_derive_serialize(
input: &mut syn::DeriveInput,
) -> Result<TokenStream, Vec<syn::Error>> {
pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
replace_receiver(input);
let ctxt = Ctxt::new();
@@ -59,8 +57,6 @@ pub fn expand_derive_serialize(
Ok(dummy::wrap_in_const(
cont.attrs.custom_serde_path(),
"SERIALIZE",
ident,
impl_block,
))
}
@@ -477,17 +473,19 @@ fn serialize_variant(
}
};
let body = Match(match cattrs.tag() {
attr::TagType::External => {
let body = Match(match (cattrs.tag(), variant.attrs.untagged()) {
(attr::TagType::External, false) => {
serialize_externally_tagged_variant(params, variant, variant_index, cattrs)
}
attr::TagType::Internal { tag } => {
(attr::TagType::Internal { tag }, false) => {
serialize_internally_tagged_variant(params, variant, cattrs, tag)
}
attr::TagType::Adjacent { tag, content } => {
(attr::TagType::Adjacent { tag, content }, false) => {
serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content)
}
attr::TagType::None => serialize_untagged_variant(params, variant, cattrs),
(attr::TagType::None, _) | (_, true) => {
serialize_untagged_variant(params, variant, cattrs)
}
});
quote! {
-1
View File
@@ -1 +0,0 @@
msrv = "1.31.0"
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive_internals"
version = "0.27.0" # remember to update html_root_url
version = "0.28.0" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
description = "AST representation used by Serde derive macros. Unstable."
documentation = "https://docs.rs/serde_derive_internals"
@@ -17,7 +17,7 @@ path = "lib.rs"
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
syn = { version = "2.0.21", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
+1 -1
View File
@@ -1,4 +1,4 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.27.0")]
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.28.0")]
#![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints
#![allow(
-1
View File
@@ -1 +0,0 @@
msrv = "1.13.0"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "1.0.162" # remember to update html_root_url
version = "1.0.165" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["development-tools::testing"]
+1 -1
View File
@@ -140,7 +140,7 @@
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.162")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.165")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
// Ignored clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))]
+157 -1
View File
@@ -1533,7 +1533,7 @@ fn test_invalid_length_enum() {
Token::TupleVariant {
name: "InvalidLengthEnum",
variant: "B",
len: 3,
len: 2,
},
Token::I32(1),
Token::TupleVariantEnd,
@@ -2442,6 +2442,162 @@ fn test_untagged_enum_containing_flatten() {
);
}
#[test]
fn test_partially_untagged_enum() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum Exp {
Lambda(u32, Box<Exp>),
#[serde(untagged)]
App(Box<Exp>, Box<Exp>),
#[serde(untagged)]
Var(u32),
}
use Exp::*;
let data = Lambda(0, Box::new(App(Box::new(Var(0)), Box::new(Var(0)))));
assert_tokens(
&data,
&[
Token::TupleVariant {
name: "Exp",
variant: "Lambda",
len: 2,
},
Token::U32(0),
Token::Tuple { len: 2 },
Token::U32(0),
Token::U32(0),
Token::TupleEnd,
Token::TupleVariantEnd,
],
);
}
#[test]
fn test_partially_untagged_enum_generic() {
trait Trait<T> {
type Assoc;
type Assoc2;
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum E<A, B, C>
where
A: Trait<C, Assoc2 = B>,
{
A(A::Assoc),
#[serde(untagged)]
B(A::Assoc2),
}
impl<T> Trait<T> for () {
type Assoc = T;
type Assoc2 = bool;
}
type MyE = E<(), bool, u32>;
use E::*;
assert_tokens::<MyE>(&B(true), &[Token::Bool(true)]);
assert_tokens::<MyE>(
&A(5),
&[
Token::NewtypeVariant {
name: "E",
variant: "A",
},
Token::U32(5),
],
);
}
#[test]
fn test_partially_untagged_enum_desugared() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum Test {
A(u32, u32),
B(u32),
#[serde(untagged)]
C(u32),
#[serde(untagged)]
D(u32, u32),
}
use Test::*;
mod desugared {
use super::*;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub(super) enum Test {
A(u32, u32),
B(u32),
}
}
use desugared::Test as TestTagged;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(untagged)]
enum TestUntagged {
Tagged(TestTagged),
C(u32),
D(u32, u32),
}
impl From<Test> for TestUntagged {
fn from(test: Test) -> Self {
match test {
A(x, y) => TestUntagged::Tagged(TestTagged::A(x, y)),
B(x) => TestUntagged::Tagged(TestTagged::B(x)),
C(x) => TestUntagged::C(x),
D(x, y) => TestUntagged::D(x, y),
}
}
}
fn assert_tokens_desugared(value: Test, tokens: &[Token]) {
assert_tokens(&value, tokens);
let desugared: TestUntagged = value.into();
assert_tokens(&desugared, tokens);
}
assert_tokens_desugared(
A(0, 1),
&[
Token::TupleVariant {
name: "Test",
variant: "A",
len: 2,
},
Token::U32(0),
Token::U32(1),
Token::TupleVariantEnd,
],
);
assert_tokens_desugared(
B(1),
&[
Token::NewtypeVariant {
name: "Test",
variant: "B",
},
Token::U32(1),
],
);
assert_tokens_desugared(C(2), &[Token::U32(2)]);
assert_tokens_desugared(
D(3, 5),
&[
Token::Tuple { len: 2 },
Token::U32(3),
Token::U32(5),
Token::TupleEnd,
],
);
}
#[test]
fn test_flatten_untagged_enum() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
+2 -1
View File
@@ -14,6 +14,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::default::Default;
use std::ffi::{CStr, CString, OsString};
use std::fmt::Debug;
use std::iter;
use std::net;
use std::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
@@ -199,7 +200,7 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) {
]
.into_iter()
.chain(ignorable_tokens.iter().copied())
.chain(vec![Token::MapEnd].into_iter())
.chain(iter::once(Token::MapEnd))
.collect();
let expected = IgnoreBase { a: 1 };
@@ -0,0 +1,10 @@
use serde_derive::Serialize;
#[derive(Serialize)]
enum E {
#[serde(untagged)]
A(u8),
B(String),
}
fn main() {}
@@ -0,0 +1,5 @@
error: all variants with the #[serde(untagged)] attribute must be placed at the end of the enum
--> tests/ui/enum-representation/partially_tagged_wrong_order.rs:6:5
|
6 | A(u8),
| ^