Compare commits

...

97 Commits

Author SHA1 Message Date
David Tolnay 3d6c4149b1 Release 1.0.123 2021-01-25 13:43:11 -08:00
David Tolnay 29cdf888c0 Merge pull request #1970 from serde-rs/self
Support `Self` inside fields that use serialize_with
2021-01-25 13:42:35 -08:00
David Tolnay 2ba97394fb Substitute Self in output of Serialize derive 2021-01-25 13:34:09 -08:00
David Tolnay 6699b0bc40 Add regression test for issue 1969 2021-01-25 13:34:08 -08:00
David Tolnay b054ea4105 Ignore some pedantic lints in serde_derive_internals from PR 1830
error: item name ends with its containing module's name
      --> serde_derive_internals/src/receiver.rs:11:1
       |
    11 | / pub fn replace_receiver(input: &mut DeriveInput) {
    12 | |     let self_ty = {
    13 | |         let ident = &input.ident;
    14 | |         let ty_generics = input.generics.split_for_impl().1;
    ...  |
    19 | |     visitor.visit_data_mut(&mut input.data);
    20 | | }
       | |_^
       |
    note: the lint level is defined here
      --> serde_derive_internals/lib.rs:3:22
       |
    3  | #![deny(clippy::all, clippy::pedantic)]
       |                      ^^^^^^^^^^^^^^^^
       = note: `#[deny(clippy::module_name_repetitions)]` implied by `#[deny(clippy::pedantic)]`
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions

    error: binding's name is too similar to existing binding
      --> serde_derive_internals/src/receiver.rs:31:29
       |
    31 |     fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
       |                             ^^^^^
       |
    note: the lint level is defined here
      --> serde_derive_internals/lib.rs:3:22
       |
    3  | #![deny(clippy::all, clippy::pedantic)]
       |                      ^^^^^^^^^^^^^^^^
       = note: `#[deny(clippy::similar_names)]` implied by `#[deny(clippy::pedantic)]`
    note: existing binding defined here
      --> serde_derive_internals/src/receiver.rs:31:23
       |
    31 |     fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
       |                       ^^^^
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#similar_names

    error: unused `self` argument
       --> serde_derive_internals/src/receiver.rs:286:24
        |
    286 |     fn visit_macro_mut(&mut self, _mac: &mut Macro) {}
        |                        ^^^^^^^^^
        |
    note: the lint level is defined here
       --> serde_derive_internals/lib.rs:3:22
        |
    3   | #![deny(clippy::all, clippy::pedantic)]
        |                      ^^^^^^^^^^^^^^^^
        = note: `#[deny(clippy::unused_self)]` implied by `#[deny(clippy::pedantic)]`
        = help: consider refactoring to a associated function
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
2021-01-25 00:03:03 -08:00
David Tolnay e5efb6ad93 Remove dependency on syn/visit-mut feature 2021-01-24 23:56:57 -08:00
David Tolnay 1f423580a5 Deduplicate token stream respanner 2021-01-24 23:06:08 -08:00
David Tolnay 033114a4ae Touch up PR 1830 2021-01-24 23:06:07 -08:00
David Tolnay 7cec99c7fd Pare down PR 1830
Unlike expr macros, macros in type position in a derive input are rare
enough that it's not worth supporting for an issue that has such an easy
workaround (just replace `Self` in the macro input with your type name).
2021-01-24 23:06:06 -08:00
David Tolnay 6c5bf701be Merge pull request 1830 from taiki-e/self 2021-01-24 23:05:51 -08:00
David Tolnay 6e800ff826 Test exhaustiveness of type match in collect_lifetimes 2021-01-24 23:04:01 -08:00
David Tolnay 68bda7a004 Include serde crate in 1.31 CI job 2021-01-24 20:42:20 -08:00
David Tolnay dfeaf77bb2 Merge pull request #1966 from serde-rs/private
Omit derive helpers in versions older than serde_derive msrv
2021-01-24 20:40:06 -08:00
David Tolnay b0cc213e57 Omit derive helpers in versions older than serde_derive msrv 2021-01-24 20:26:56 -08:00
David Tolnay 74ca06662e Omit size_hint::cautious when not allocating 2021-01-24 20:24:03 -08:00
David Tolnay 38edb473de Move size_hint module out of private::de 2021-01-24 20:23:07 -08:00
David Tolnay 1c03647656 Move InPlaceSeed out of private mod 2021-01-24 20:23:06 -08:00
David Tolnay aeee73fe92 Merge pull request #1831 from taiki-e/borrow-macro
Collect lifetimes inside macro invocations
2021-01-24 19:08:20 -08:00
David Tolnay 1a3ef39040 Merge pull request #1842 from Timmmm/fix2
Allow floats to be deserialized from ints in tagged unions
2021-01-24 18:48:46 -08:00
David Tolnay deaf600af7 Merge pull request #1965 from serde-rs/int
Reduce post-macro-expansion code in integer deserialize impls
2021-01-24 18:43:36 -08:00
David Tolnay 48556a4c7f Reduce post-macro-expansion code in integer deserialize impls 2021-01-24 18:26:50 -08:00
David Tolnay d88a4748f7 Remove unused $ty arg from internal impl_deserialize_num macro 2021-01-24 17:06:36 -08:00
David Tolnay ffed19243d Release 1.0.122 2021-01-24 16:17:29 -08:00
David Tolnay bb7f94df84 Add serde_derive_internals to clippy CI job 2021-01-24 16:11:37 -08:00
David Tolnay ff0f467e25 Opt in to pedantic clippy lints in serde_derive_internals 2021-01-24 16:10:36 -08:00
David Tolnay d1975f3661 Update serde_derive_internals to tool attrs 2021-01-24 16:08:42 -08:00
David Tolnay b91713e824 Suppress clippy should_implement_trait lint
I think there is no ambiguity in from_str as a method name so "choose a
less ambiguous method name" is unnecessary, and it can't be a FromStr
impl in this case because FromStr's error type cannot borrow from the
input string slice.

    warning: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
      --> serde_derive_internals/src/case.rs:50:5
       |
    50 | /     pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError> {
    51 | |         for (name, rule) in RENAME_RULES {
    52 | |             if rename_all_str == *name {
    53 | |                 return Ok(*rule);
    ...  |
    58 | |         })
    59 | |     }
       | |_____^
       |
       = note: `#[warn(clippy::should_implement_trait)]` on by default
       = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
2021-01-24 16:04:51 -08:00
David Tolnay 6ea446fb4b Suppress clippy unused_self pedantic lint
This usage is fine. It's mirroring trait signatures in syn::visit::Visit.

    error: unused `self` argument
       --> serde_derive/src/bound.rs:241:24
        |
    241 |         fn visit_macro(&mut self, _mac: &'ast syn::Macro) {}
        |                        ^^^^^^^^^
        |
    note: the lint level is defined here
       --> serde_derive/src/lib.rs:18:22
        |
    18  | #![deny(clippy::all, clippy::pedantic)]
        |                      ^^^^^^^^^^^^^^^^
        = note: `#[deny(clippy::unused_self)]` implied by `#[deny(clippy::pedantic)]`
        = help: consider refactoring to a associated function
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
2021-01-24 16:01:05 -08:00
David Tolnay 85c6904a93 Remove dependency on syn/visit feature
The builtin visitor is fairly expensive to compile (3700 lines of code),
particularly if something else in the dependency graph also enables
syn/full. For the usage in serde_derive, it turns out to be easy to
replace.
2021-01-24 15:50:41 -08:00
David Tolnay 2fd5212204 Remove unused trait impls on private MapAsEnum 2021-01-23 23:19:48 -08:00
David Tolnay 7d1bc1f0fc Merge pull request #1963 from serde-rs/valuedebug
Eliminate inferred bound on error type of value deserializer Debug impls
2021-01-23 23:19:36 -08:00
David Tolnay cdc2fa1b9f Eliminate inferred bound on error type of value deserializer Debug impls 2021-01-23 23:15:41 -08:00
David Tolnay ac4001e590 Remove some unused trait impls from private UnitOnly variant accessor 2021-01-23 23:07:13 -08:00
David Tolnay fbcb2230bb Make use of fmt::Result type alias from libcore 2021-01-23 22:57:13 -08:00
David Tolnay 86c88bea12 Hide some irrelevant detail from de::value::Error's Debug impl 2021-01-23 22:49:00 -08:00
David Tolnay 82d0fe00fd Add link to rust-lang/rust#67295 2021-01-23 22:32:30 -08:00
David Tolnay e61261e002 Move doctest-only helpers to a doc module 2021-01-23 22:32:30 -08:00
David Tolnay 9fd56cd41c Remove unused __private_deserialize macro, originally for doctests 2021-01-23 22:26:16 -08:00
Taiki Endo e81f54fbc8 Make AST borrow checker happy 2021-01-24 15:23:54 +09:00
Taiki Endo c67017d466 Fix handling of Self keyword in type definition 2021-01-24 15:23:51 +09:00
David Tolnay f6e7366b46 Remove unused Debug impl on private::ser::content::Content 2021-01-23 22:10:48 -08:00
David Tolnay 1f9f72bc48 Merge pull request 1898 from Mingun/bytes-into-deserializer 2021-01-23 22:04:20 -08:00
David Tolnay e24dbc418d Skip another clone of the fallthrough arm 2021-01-23 20:52:03 -08:00
David Tolnay 18e5b03fd1 Merge pull request #1962 from serde-rs/dupborrowed
Eliminate duplicated borrowed and non-borrowed identifier deserialization
2021-01-23 20:51:56 -08:00
David Tolnay 5aa163f27e Revert "Regenerate macrotest outputs for PR #1917"
This reverts commit 999b94d6ae.
2021-01-23 20:36:26 -08:00
David Tolnay 3728d3c67a Eliminate duplicated borrowed and non-borrowed identifier deserialization 2021-01-23 20:32:38 -08:00
David Tolnay 3f48ed36cc Restore compatibility with rustc <1.31 in Borrowed identifier deserializer
The implied lifetime bound on T only works on 1.31+. Older versions fail
with:

    error[E0309]: the parameter type `T` may not live long enough
        --> serde/src/private/de.rs:2548:37
         |
    2548 | pub struct Borrowed<'de, T: ?Sized>(pub &'de T);
         |                          --         ^^^^^^^^^^
         |                          |
         |                          help: consider adding an explicit lifetime bound `T: 'de`...
         |
    note: ...so that the reference type `&'de T` does not outlive the data it points at
        --> serde/src/private/de.rs:2548:37
         |
    2548 | pub struct Borrowed<'de, T: ?Sized>(pub &'de T);
         |                                     ^^^^^^^^^^
2021-01-23 20:19:33 -08:00
David Tolnay b6a2d07f26 Return IdentifierDeserializer to just one associated type
The BorrowedDeserializer was added in #1917, but only makes sense for
&str and &[u8], not for u64 which also needs to be have an
IdentifierDeserializer impl.
2021-01-23 20:04:58 -08:00
David Tolnay 84ad76b2e5 Ignore too_many_lines clippy pedantic lint in serde_test
error: this function has too many lines (107/100)
       --> serde_test/src/de.rs:128:5
        |
    128 | /     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
    129 | |     where
    130 | |         V: Visitor<'de>,
    131 | |     {
    ...   |
    238 | |         }
    239 | |     }
        | |_____^
        |
    note: the lint level is defined here
       --> serde_test/src/lib.rs:149:52
        |
    149 | #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
        |                                                    ^^^^^^^^^^^^^^^
        = note: `#[deny(clippy::too_many_lines)]` implied by `#[deny(clippy::pedantic)]`
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
2021-01-23 20:04:30 -08:00
David Tolnay e6b6602a42 Merge pull request 1914 from Mingun/seq-other 2021-01-23 19:50:39 -08:00
David Tolnay 999b94d6ae Regenerate macrotest outputs for PR #1917 2021-01-23 19:43:02 -08:00
David Tolnay fa6712d2bf Merge pull request #1918 from Mingun/fix-serde-test
Fix incorrect message in serializer tokens and correctly implement next_entry_seed
2021-01-23 15:02:32 -08:00
David Tolnay 012ea8eb84 Keep conditional compilation cfg naming consistent with serde crate
The serde crate's build.rs uses names like `core_duration` or
`integer128`, not `has_core_duration` / `has_integer128`.
2021-01-23 14:57:12 -08:00
David Tolnay 9add5812e2 Update track_caller cfg link to show what version it's in 2021-01-23 14:56:03 -08:00
David Tolnay 5fd52100b6 Merge pull request #1920 from Mingun/track_caller
Show correct location in error messages by tracking caller of utility `assert_tokens` functions
2021-01-23 14:54:24 -08:00
David Tolnay 6670a309ca Merge pull request #1961 from serde-rs/renamerule
Provide list of recognized rename rules on parse error
2021-01-23 14:50:02 -08:00
David Tolnay b7bad3a165 Restore compatibility with rustc 1.31 in RenameRule error
str::escape_debug wasn't stabilized until 1.34, whereas serde_derive
currently supports an oldest version of 1.31.
2021-01-23 14:40:44 -08:00
David Tolnay 4e002ece07 Provide list of recognized rename rules on parse error 2021-01-23 14:38:20 -08:00
David Tolnay eaccae2c46 Fix UPPERCASE rename rule variant to follow idiomatic variant naming
This shouldn't have been named this way in PR #1132.
2021-01-23 14:27:33 -08:00
David Tolnay 990a502c39 Parse rename rules based on table of rules
This will make it possible to reuse the same table of recognized rules
in the parse error message.
2021-01-23 14:24:21 -08:00
David Tolnay 661206d885 Merge pull request #1960 from serde-rs/renamerule
Deduplicate RenameRule parse error message generation
2021-01-23 14:23:09 -08:00
David Tolnay 51d4563ed1 Move RenameRule parse error message to a Display impl 2021-01-23 14:13:47 -08:00
David Tolnay 7db0982e58 Add error type to use for RenameRule parsing 2021-01-23 14:09:58 -08:00
David Tolnay ed04824f10 Move RenameRule parse from trait fn to associated
This will allow updating it to return an Err that borrows the input
string, which is not possible with FromStr.
2021-01-23 14:07:59 -08:00
David Tolnay 88ee470a1c Format PR #1916 with rustfmt 1.4.32 2021-01-23 13:39:12 -08:00
David Tolnay a5ecbdb4f4 Merge pull request 1916 from Mingun/expecting-customize 2021-01-23 13:38:45 -08:00
David Tolnay bd588db067 Release 1.0.121 2021-01-23 13:17:08 -08:00
David Tolnay 8f09aeacdd Merge pull request #1959 from serde-rs/1917
Touch up borrowed field identifiers PR
2021-01-23 13:15:30 -08:00
David Tolnay 0b5c56b0db Touch up documentation from PR #1917 2021-01-23 13:09:37 -08:00
David Tolnay 85de92e6f7 Inline forward_deserializer for bytes deserializers 2021-01-23 13:08:08 -08:00
David Tolnay c858a1fa77 Clean up unnecessary macro_use from PR #1917 2021-01-23 12:59:12 -08:00
David Tolnay d02eb22557 Inline some unnecessary constructor functions from PR #1917 2021-01-23 12:58:42 -08:00
David Tolnay 034fe25d5b Remove redundant unused trait impls from private types from PR #1917 2021-01-23 12:58:42 -08:00
David Tolnay 0a230e8598 Inline forward_deserializer into private::de for Str deserializers
We shouldn't try to use the same macro for public and private types. The
API for a private type can usually be pared much further down to save
compile time, such as Debug and Copy and Clone impls.
2021-01-23 12:57:35 -08:00
David Tolnay b20214d4a0 Undo macro exports from PR #1917
All of these macros are only used internally within the serde crate.
There is no need for them to have #[macro_export] and need to be hidden
from docs.
2021-01-23 12:40:01 -08:00
David Tolnay 34f4b68f77 Fix unneeded clone from PR #1917 2021-01-23 12:40:00 -08:00
David Tolnay 60e08f9545 Format PR #1917 with rustfmt 1.4.32 2021-01-23 12:39:59 -08:00
David Tolnay ba46f45dc5 Merge pull request 1917 from Mingun/borrow-identifier 2021-01-23 12:39:28 -08:00
David Tolnay 44b9567e21 Merge pull request #1958 from jonasbb/duration-panic
Prevent panic when deserializing malformed Duration
2021-01-23 00:45:39 -08:00
Jonas Bushart b276849ce1 Prevent panic when deserializing malformed Duration
std::time::Duration::new can panic. There is no alternative non-panicing constructor.
Check the panic condition beforehand and return an error instead of panicing.

Fixes #1933
2021-01-20 20:41:45 +01:00
Mingun 5cbc8439ea Show correct location in error messages by tracking caller of utility assert_tokens functions 2020-10-28 09:11:54 +05:00
Mingun 97c350a95e Forward Readable|Compact next_entry_seed to underlying next_entry_seed instead of usage of default implementation
Difference is noticeable for deserializers that rely on call of next_entry_seed
(for example, current quick-xml supports only next_entry_seed)
2020-10-28 01:05:27 +05:00
Mingun 920a77ad61 Fix incorrect messages in serialized tokens assertions
Serializer contains expected tokens, called methods provide actual tokens
2020-10-28 01:05:27 +05:00
Taiki Endo a227a87865 Collect lifetimes inside macro invocations 2020-10-24 05:29:47 +09:00
Mingun 7a7a182ab6 Allow borrow for field identifiers 2020-10-23 19:03:18 +05:00
Mingun 9e1f573f88 Use forward_deserializer macro for define StrDeserializer for IdentifierDeserializer 2020-10-23 19:03:18 +05:00
Mingun 094f63b86a Introduce a forward_deserializer macro.
It helps to create deserializers that can stop time: save the value and then use visitor to get it later!
2020-10-23 19:03:14 +05:00
Mingun 42fa79455e Make BytesDeserializer public 2020-10-23 12:13:57 +05:00
Mingun 104ad9a7dd Allow to define custom expectation message for type with #[serde(expecting = "...")]
Closes #1883
2020-10-23 01:23:01 +05:00
Mingun 23c14e5f33 Allow to run assert_de_tokens_error on token sequence that is not expected by enum deserializer
Before that fix following code panics, because `Token::Unit` was unexpected by test deserializer:
```
#[derive(Deserialize)]
enum E { ... }

assert_de_tokens_error::<E>(&[Token::Unit], "...");
```
2020-10-22 23:50:48 +05:00
Mingun e80571751d Allow borrowed and owned strings and bytes and u8, u16, u64 for variant keys in serde_test 2020-10-22 20:43:14 +05:00
Mingun 0737474640 Allow field identifiers be any numbers if #[serde(other)] is used
Thus behavior synchronized between string/bytes identifiers and numeric identifiers
2020-10-22 16:35:28 +05:00
Mingun 34de1e00c8 Implement IdentifierDeserializer for u64 instead of u32 because all identifiers deserialized with visit_u64 2020-10-22 16:35:28 +05:00
Mingun f6eb34a830 Assert that numeric field identifiers correctly deserialized (now failing) 2020-10-22 16:35:28 +05:00
Mingun db3074a40f Implement IntoDeserializer for Cow<[u8]> 2020-10-04 13:38:31 +05:00
Mingun 2e821eab4b Make impl IntoDeserializer for &[u8] public 2020-10-03 16:43:31 +05:00
Tim Hutt 010444dfa4 Allow floats to be deserialized from ints in tagged unions 2020-06-22 16:31:13 +01:00
51 changed files with 1804 additions and 812 deletions
+3
View File
@@ -115,6 +115,8 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: dtolnay/rust-toolchain@1.31.0
- run: cd serde && cargo check --no-default-features
- run: cd serde && cargo check
- run: cd serde_derive && cargo check
alloc:
@@ -158,6 +160,7 @@ jobs:
# https://github.com/rust-lang/rust-clippy/issues/5356
- run: cd serde && cargo clippy --features rc,unstable -- -D clippy::all -A clippy::redundant_field_names
- run: cd serde_derive && cargo clippy -- -D clippy::all
- run: cd serde_derive_internals && cargo clippy -- -D clippy::all
- run: cd serde_test && cargo clippy -- -D clippy::all -A clippy::redundant_field_names
- run: cd test_suite && cargo clippy --tests --features unstable -- -D clippy::all -A clippy::redundant_field_names
- run: cd test_suite/no_std && cargo clippy -- -D clippy::all -A clippy::redundant_field_names
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.120" # remember to update html_root_url and serde_derive dependency
version = "1.0.123" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT OR Apache-2.0"
description = "A generic serialization/deserialization framework"
@@ -14,7 +14,7 @@ include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APAC
build = "build.rs"
[dependencies]
serde_derive = { version = "=1.0.120", optional = true, path = "../serde_derive" }
serde_derive = { version = "=1.0.123", optional = true, path = "../serde_derive" }
[dev-dependencies]
serde_derive = { version = "1.0", path = "../serde_derive" }
+5
View File
@@ -71,6 +71,11 @@ fn main() {
println!("cargo:rustc-cfg=num_nonzero");
}
// Current minimum supported version of serde_derive crate is Rust 1.31.
if minor >= 31 {
println!("cargo:rustc-cfg=serde_derive");
}
// TryFrom, Atomic types, and non-zero signed integers stabilized in Rust 1.34:
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#tryfrom-and-tryinto
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#library-stabilizations
-260
View File
@@ -1,260 +0,0 @@
use lib::*;
macro_rules! int_to_int {
($dst:ident, $n:ident) => {
if $dst::min_value() as i64 <= $n as i64 && $n as i64 <= $dst::max_value() as i64 {
Some($n as $dst)
} else {
None
}
};
}
macro_rules! int_to_uint {
($dst:ident, $n:ident) => {
if 0 <= $n && $n as u64 <= $dst::max_value() as u64 {
Some($n as $dst)
} else {
None
}
};
}
macro_rules! uint_to {
($dst:ident, $n:ident) => {
if $n as u64 <= $dst::max_value() as u64 {
Some($n as $dst)
} else {
None
}
};
}
pub trait FromPrimitive: Sized {
fn from_i8(n: i8) -> Option<Self>;
fn from_i16(n: i16) -> Option<Self>;
fn from_i32(n: i32) -> Option<Self>;
fn from_i64(n: i64) -> Option<Self>;
fn from_u8(n: u8) -> Option<Self>;
fn from_u16(n: u16) -> Option<Self>;
fn from_u32(n: u32) -> Option<Self>;
fn from_u64(n: u64) -> Option<Self>;
}
macro_rules! impl_from_primitive_for_int {
($t:ident) => {
impl FromPrimitive for $t {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
int_to_int!($t, n)
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
int_to_int!($t, n)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
int_to_int!($t, n)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
int_to_int!($t, n)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
uint_to!($t, n)
}
}
};
}
macro_rules! impl_from_primitive_for_uint {
($t:ident) => {
impl FromPrimitive for $t {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
int_to_uint!($t, n)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
uint_to!($t, n)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
uint_to!($t, n)
}
}
};
}
macro_rules! impl_from_primitive_for_float {
($t:ident) => {
impl FromPrimitive for $t {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
Some(n as Self)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
Some(n as Self)
}
}
};
}
impl_from_primitive_for_int!(isize);
impl_from_primitive_for_int!(i8);
impl_from_primitive_for_int!(i16);
impl_from_primitive_for_int!(i32);
impl_from_primitive_for_int!(i64);
impl_from_primitive_for_uint!(usize);
impl_from_primitive_for_uint!(u8);
impl_from_primitive_for_uint!(u16);
impl_from_primitive_for_uint!(u32);
impl_from_primitive_for_uint!(u64);
impl_from_primitive_for_float!(f32);
impl_from_primitive_for_float!(f64);
serde_if_integer128! {
impl FromPrimitive for i128 {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
Some(n as i128)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
Some(n as i128)
}
}
impl FromPrimitive for u128 {
#[inline]
fn from_i8(n: i8) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_i16(n: i16) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_i32(n: i32) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_i64(n: i64) -> Option<Self> {
if n >= 0 {
Some(n as u128)
} else {
None
}
}
#[inline]
fn from_u8(n: u8) -> Option<Self> {
Some(n as u128)
}
#[inline]
fn from_u16(n: u16) -> Option<Self> {
Some(n as u128)
}
#[inline]
fn from_u32(n: u32) -> Option<Self> {
Some(n as u128)
}
#[inline]
fn from_u64(n: u64) -> Option<Self> {
Some(n as u128)
}
}
}
+209 -137
View File
@@ -7,11 +7,10 @@ use de::{
#[cfg(any(core_duration, feature = "std", feature = "alloc"))]
use de::MapAccess;
use __private::de::InPlaceSeed;
use de::from_primitive::FromPrimitive;
use seed::InPlaceSeed;
#[cfg(any(feature = "std", feature = "alloc"))]
use __private::de::size_hint;
use __private::size_hint;
////////////////////////////////////////////////////////////////////////////////
@@ -81,38 +80,8 @@ impl<'de> Deserialize<'de> for bool {
////////////////////////////////////////////////////////////////////////////////
macro_rules! visit_integer_method {
($src_ty:ident, $method:ident, $from_method:ident, $group:ident, $group_ty:ident) => {
#[inline]
fn $method<E>(self, v: $src_ty) -> Result<Self::Value, E>
where
E: Error,
{
match FromPrimitive::$from_method(v) {
Some(v) => Ok(v),
None => Err(Error::invalid_value(
Unexpected::$group(v as $group_ty),
&self,
)),
}
}
};
}
macro_rules! visit_float_method {
($src_ty:ident, $method:ident) => {
#[inline]
fn $method<E>(self, v: $src_ty) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v as Self::Value)
}
};
}
macro_rules! impl_deserialize_num {
($ty:ident, $method:ident, $($visit:ident),*) => {
($ty:ident, $deserialize:ident $($methods:tt)*) => {
impl<'de> Deserialize<'de> for $ty {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@@ -128,131 +97,221 @@ macro_rules! impl_deserialize_num {
formatter.write_str(stringify!($ty))
}
$(
impl_deserialize_num!($visit $ty);
)*
$($methods)*
}
deserializer.$method(PrimitiveVisitor)
deserializer.$deserialize(PrimitiveVisitor)
}
}
};
(integer $ty:ident) => {
visit_integer_method!(i8, visit_i8, from_i8, Signed, i64);
visit_integer_method!(i16, visit_i16, from_i16, Signed, i64);
visit_integer_method!(i32, visit_i32, from_i32, Signed, i64);
visit_integer_method!(i64, visit_i64, from_i64, Signed, i64);
visit_integer_method!(u8, visit_u8, from_u8, Unsigned, u64);
visit_integer_method!(u16, visit_u16, from_u16, Unsigned, u64);
visit_integer_method!(u32, visit_u32, from_u32, Unsigned, u64);
visit_integer_method!(u64, visit_u64, from_u64, Unsigned, u64);
};
(float $ty:ident) => {
visit_float_method!(f32, visit_f32);
visit_float_method!(f64, visit_f64);
};
}
impl_deserialize_num!(i8, deserialize_i8, integer);
impl_deserialize_num!(i16, deserialize_i16, integer);
impl_deserialize_num!(i32, deserialize_i32, integer);
impl_deserialize_num!(i64, deserialize_i64, integer);
impl_deserialize_num!(isize, deserialize_i64, integer);
impl_deserialize_num!(u8, deserialize_u8, integer);
impl_deserialize_num!(u16, deserialize_u16, integer);
impl_deserialize_num!(u32, deserialize_u32, integer);
impl_deserialize_num!(u64, deserialize_u64, integer);
impl_deserialize_num!(usize, deserialize_u64, integer);
impl_deserialize_num!(f32, deserialize_f32, integer, float);
impl_deserialize_num!(f64, deserialize_f64, integer, float);
serde_if_integer128! {
impl<'de> Deserialize<'de> for i128 {
macro_rules! num_self {
($ty:ident : $visit:ident) => {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
D: Deserializer<'de>,
E: Error,
{
struct PrimitiveVisitor;
Ok(v)
}
};
}
impl<'de> Visitor<'de> for PrimitiveVisitor {
type Value = i128;
macro_rules! num_as_self {
($($ty:ident : $visit:ident)*) => {
$(
#[inline]
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v as Self::Value)
}
)*
};
}
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("i128")
}
impl_deserialize_num!(integer i128);
#[inline]
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v)
}
#[inline]
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: Error,
{
if v <= i128::max_value() as u128 {
Ok(v as i128)
} else {
Err(Error::invalid_value(Unexpected::Other("u128"), &self))
}
macro_rules! int_to_int {
($($ty:ident : $visit:ident)*) => {
$(
#[inline]
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
if Self::Value::min_value() as i64 <= v as i64 && v as i64 <= Self::Value::max_value() as i64 {
Ok(v as Self::Value)
} else {
Err(Error::invalid_value(Unexpected::Signed(v as i64), &self))
}
}
)*
};
}
deserializer.deserialize_i128(PrimitiveVisitor)
macro_rules! int_to_uint {
($($ty:ident : $visit:ident)*) => {
$(
#[inline]
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
if 0 <= v && v as u64 <= Self::Value::max_value() as u64 {
Ok(v as Self::Value)
} else {
Err(Error::invalid_value(Unexpected::Signed(v as i64), &self))
}
}
)*
};
}
macro_rules! uint_to_self {
($($ty:ident : $visit:ident)*) => {
$(
#[inline]
fn $visit<E>(self, v: $ty) -> Result<Self::Value, E>
where
E: Error,
{
if v as u64 <= Self::Value::max_value() as u64 {
Ok(v as Self::Value)
} else {
Err(Error::invalid_value(Unexpected::Unsigned(v as u64), &self))
}
}
)*
};
}
impl_deserialize_num! {
i8, deserialize_i8
num_self!(i8:visit_i8);
int_to_int!(i16:visit_i16 i32:visit_i32 i64:visit_i64);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
i16, deserialize_i16
num_self!(i16:visit_i16);
num_as_self!(i8:visit_i8);
int_to_int!(i32:visit_i32 i64:visit_i64);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
i32, deserialize_i32
num_self!(i32:visit_i32);
num_as_self!(i8:visit_i8 i16:visit_i16);
int_to_int!(i64:visit_i64);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
i64, deserialize_i64
num_self!(i64:visit_i64);
num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
isize, deserialize_i64
num_as_self!(i8:visit_i8 i16:visit_i16);
int_to_int!(i32:visit_i32 i64:visit_i64);
uint_to_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
u8, deserialize_u8
num_self!(u8:visit_u8);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
uint_to_self!(u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
u16, deserialize_u16
num_self!(u16:visit_u16);
num_as_self!(u8:visit_u8);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
uint_to_self!(u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
u32, deserialize_u32
num_self!(u32:visit_u32);
num_as_self!(u8:visit_u8 u16:visit_u16);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
uint_to_self!(u64:visit_u64);
}
impl_deserialize_num! {
u64, deserialize_u64
num_self!(u64:visit_u64);
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
}
impl_deserialize_num! {
usize, deserialize_u64
num_as_self!(u8:visit_u8 u16:visit_u16);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
uint_to_self!(u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
f32, deserialize_f32
num_self!(f32:visit_f32);
num_as_self!(f64:visit_f64);
num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
impl_deserialize_num! {
f64, deserialize_f64
num_self!(f64:visit_f64);
num_as_self!(f32:visit_f32);
num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
}
serde_if_integer128! {
impl_deserialize_num! {
i128, deserialize_i128
num_self!(i128:visit_i128);
num_as_self!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
#[inline]
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: Error,
{
if v <= i128::max_value() as u128 {
Ok(v as i128)
} else {
Err(Error::invalid_value(Unexpected::Other("u128"), &self))
}
}
}
impl<'de> Deserialize<'de> for u128 {
impl_deserialize_num! {
u128, deserialize_u128
num_self!(u128:visit_u128);
num_as_self!(u8:visit_u8 u16:visit_u16 u32:visit_u32 u64:visit_u64);
int_to_uint!(i8:visit_i8 i16:visit_i16 i32:visit_i32 i64:visit_i64);
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
D: Deserializer<'de>,
E: Error,
{
struct PrimitiveVisitor;
impl<'de> Visitor<'de> for PrimitiveVisitor {
type Value = u128;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("u128")
}
impl_deserialize_num!(integer u128);
#[inline]
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: Error,
{
if v >= 0 {
Ok(v as u128)
} else {
Err(Error::invalid_value(Unexpected::Other("i128"), &self))
}
}
#[inline]
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v)
}
if 0 <= v {
Ok(v as u128)
} else {
Err(Error::invalid_value(Unexpected::Other("i128"), &self))
}
deserializer.deserialize_u128(PrimitiveVisitor)
}
}
}
@@ -1849,6 +1908,17 @@ impl<'de> Deserialize<'de> for Duration {
}
}
fn check_overflow<E>(secs: u64, nanos: u32) -> Result<(), E>
where
E: Error,
{
static NANOS_PER_SEC: u32 = 1_000_000_000;
match secs.checked_add((nanos / NANOS_PER_SEC) as u64) {
Some(_) => Ok(()),
None => Err(E::custom("overflow deserializing Duration")),
}
}
struct DurationVisitor;
impl<'de> Visitor<'de> for DurationVisitor {
@@ -1874,6 +1944,7 @@ impl<'de> Deserialize<'de> for Duration {
return Err(Error::invalid_length(1, &self));
}
};
try!(check_overflow(secs, nanos));
Ok(Duration::new(secs, nanos))
}
@@ -1907,6 +1978,7 @@ impl<'de> Deserialize<'de> for Duration {
Some(nanos) => nanos,
None => return Err(<A::Error as Error>::missing_field("nanos")),
};
try!(check_overflow(secs, nanos));
Ok(Duration::new(secs, nanos))
}
}
+1 -2
View File
@@ -118,7 +118,6 @@ use lib::*;
pub mod value;
mod from_primitive;
mod ignored_any;
mod impls;
mod utf8;
@@ -393,7 +392,7 @@ pub enum Unexpected<'a> {
}
impl<'a> fmt::Display for Unexpected<'a> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
use self::Unexpected::*;
match *self {
Bool(b) => write!(formatter, "boolean `{}`", b),
+19
View File
@@ -0,0 +1,19 @@
use de::{Deserialize, DeserializeSeed, Deserializer};
/// A DeserializeSeed helper for implementing deserialize_in_place Visitors.
///
/// Wraps a mutable reference and calls deserialize_in_place on it.
pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T);
impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
where
T: Deserialize<'de>,
{
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize_in_place(deserializer, self.0)
}
}
+170 -32
View File
@@ -24,8 +24,8 @@
use lib::*;
use self::private::{First, Second};
use __private::de::size_hint;
use de::{self, Expected, IntoDeserializer, SeqAccess};
use __private::size_hint;
use de::{self, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
use ser;
////////////////////////////////////////////////////////////////////////////////
@@ -48,7 +48,7 @@ macro_rules! impl_copy_clone {
/// A minimal representation of all possible errors that can occur using the
/// `IntoDeserializer` trait.
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, PartialEq)]
pub struct Error {
err: ErrorImpl,
}
@@ -93,16 +93,25 @@ impl ser::Error for Error {
impl Display for Error {
#[cfg(any(feature = "std", feature = "alloc"))]
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(&self.err)
}
#[cfg(not(any(feature = "std", feature = "alloc")))]
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Serde deserialization error")
}
}
impl Debug for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let mut debug = formatter.debug_tuple("Error");
#[cfg(any(feature = "std", feature = "alloc"))]
debug.field(&self.err);
debug.finish()
}
}
#[cfg(feature = "std")]
impl error::Error for Error {
fn description(&self) -> &str {
@@ -126,7 +135,6 @@ where
}
/// A deserializer holding a `()`.
#[derive(Debug)]
pub struct UnitDeserializer<E> {
marker: PhantomData<E>,
}
@@ -160,6 +168,12 @@ where
}
}
impl<E> Debug for UnitDeserializer<E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.debug_struct("UnitDeserializer").finish()
}
}
////////////////////////////////////////////////////////////////////////////////
/// A deserializer that cannot be instantiated.
@@ -208,7 +222,6 @@ macro_rules! primitive_deserializer {
($ty:ty, $doc:tt, $name:ident, $method:ident $($cast:tt)*) => {
#[doc = "A deserializer holding"]
#[doc = $doc]
#[derive(Debug)]
pub struct $name<E> {
value: $ty,
marker: PhantomData<E>
@@ -249,6 +262,15 @@ macro_rules! primitive_deserializer {
visitor.$method(self.value $($cast)*)
}
}
impl<E> Debug for $name<E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct(stringify!($name))
.field("value", &self.value)
.finish()
}
}
}
}
@@ -272,7 +294,6 @@ serde_if_integer128! {
}
/// A deserializer holding a `u32`.
#[derive(Debug)]
pub struct U32Deserializer<E> {
value: u32,
marker: PhantomData<E>,
@@ -343,10 +364,18 @@ where
}
}
impl<E> Debug for U32Deserializer<E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("U32Deserializer")
.field("value", &self.value)
.finish()
}
}
////////////////////////////////////////////////////////////////////////////////
/// A deserializer holding a `&str`.
#[derive(Debug)]
pub struct StrDeserializer<'a, E> {
value: &'a str,
marker: PhantomData<E>,
@@ -417,11 +446,19 @@ where
}
}
impl<'a, E> Debug for StrDeserializer<'a, E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("StrDeserializer")
.field("value", &self.value)
.finish()
}
}
////////////////////////////////////////////////////////////////////////////////
/// A deserializer holding a `&str` with a lifetime tied to another
/// deserializer.
#[derive(Debug)]
pub struct BorrowedStrDeserializer<'de, E> {
value: &'de str,
marker: PhantomData<E>,
@@ -488,11 +525,19 @@ where
}
}
impl<'de, E> Debug for BorrowedStrDeserializer<'de, E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("BorrowedStrDeserializer")
.field("value", &self.value)
.finish()
}
}
////////////////////////////////////////////////////////////////////////////////
/// A deserializer holding a `String`.
#[cfg(any(feature = "std", feature = "alloc"))]
#[derive(Debug)]
pub struct StringDeserializer<E> {
value: String,
marker: PhantomData<E>,
@@ -574,11 +619,20 @@ where
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<E> Debug for StringDeserializer<E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("StringDeserializer")
.field("value", &self.value)
.finish()
}
}
////////////////////////////////////////////////////////////////////////////////
/// A deserializer holding a `Cow<str>`.
#[cfg(any(feature = "std", feature = "alloc"))]
#[derive(Debug)]
pub struct CowStrDeserializer<'a, E> {
value: Cow<'a, str>,
marker: PhantomData<E>,
@@ -663,29 +717,48 @@ where
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, E> Debug for CowStrDeserializer<'a, E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("CowStrDeserializer")
.field("value", &self.value)
.finish()
}
}
////////////////////////////////////////////////////////////////////////////////
/// A deserializer holding a `&[u8]` with a lifetime tied to another
/// deserializer.
#[derive(Debug)]
pub struct BorrowedBytesDeserializer<'de, E> {
value: &'de [u8],
/// A deserializer holding a `&[u8]`. Always calls [`Visitor::visit_bytes`].
pub struct BytesDeserializer<'a, E> {
value: &'a [u8],
marker: PhantomData<E>,
}
impl_copy_clone!(BorrowedBytesDeserializer<'de>);
impl<'de, E> BorrowedBytesDeserializer<'de, E> {
/// Create a new borrowed deserializer from the given byte slice.
pub fn new(value: &'de [u8]) -> BorrowedBytesDeserializer<'de, E> {
BorrowedBytesDeserializer {
impl<'a, E> BytesDeserializer<'a, E> {
/// Create a new deserializer from the given bytes.
pub fn new(value: &'a [u8]) -> Self {
BytesDeserializer {
value: value,
marker: PhantomData,
}
}
}
impl<'de, E> de::Deserializer<'de> for BorrowedBytesDeserializer<'de, E>
impl_copy_clone!(BytesDeserializer<'a>);
impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a [u8]
where
E: de::Error,
{
type Deserializer = BytesDeserializer<'a, E>;
fn into_deserializer(self) -> BytesDeserializer<'a, E> {
BytesDeserializer::new(self)
}
}
impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
where
E: de::Error,
{
@@ -693,7 +766,55 @@ where
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
V: Visitor<'de>,
{
visitor.visit_bytes(self.value)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
impl<'a, E> Debug for BytesDeserializer<'a, E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("BytesDeserializer")
.field("value", &self.value)
.finish()
}
}
/// A deserializer holding a `&[u8]` with a lifetime tied to another
/// deserializer. Always calls [`Visitor::visit_borrowed_bytes`].
pub struct BorrowedBytesDeserializer<'de, E> {
value: &'de [u8],
marker: PhantomData<E>,
}
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,
marker: PhantomData,
}
}
}
impl_copy_clone!(BorrowedBytesDeserializer<'de>);
impl<'de, E> Deserializer<'de> for BorrowedBytesDeserializer<'de, E>
where
E: de::Error,
{
type Error = E;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_borrowed_bytes(self.value)
}
@@ -701,14 +822,23 @@ where
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct identifier ignored_any enum
tuple_struct map struct enum identifier ignored_any
}
}
impl<'de, E> Debug for BorrowedBytesDeserializer<'de, E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("BorrowedBytesDeserializer")
.field("value", &self.value)
.finish()
}
}
////////////////////////////////////////////////////////////////////////////////
/// A deserializer that iterates over a sequence.
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct SeqDeserializer<I, E> {
iter: iter::Fuse<I>,
count: usize,
@@ -813,6 +943,19 @@ impl Expected for ExpectedInSeq {
}
}
impl<I, E> Debug for SeqDeserializer<I, E>
where
I: Debug,
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("SeqDeserializer")
.field("iter", &self.iter)
.field("count", &self.count)
.finish()
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "alloc"))]
@@ -1108,7 +1251,6 @@ where
}
}
// Cannot #[derive(Debug)] because of the bound `Second<I::Item>: Debug`.
impl<'de, I, E> Debug for MapDeserializer<'de, I, E>
where
I: Iterator + Debug,
@@ -1121,8 +1263,6 @@ where
.field("iter", &self.iter)
.field("value", &self.value)
.field("count", &self.count)
.field("lifetime", &self.lifetime)
.field("error", &self.error)
.finish()
}
}
@@ -1331,7 +1471,6 @@ mod private {
use de::{self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor};
#[derive(Clone, Debug)]
pub struct UnitOnly<E> {
marker: PhantomData<E>,
}
@@ -1390,7 +1529,6 @@ mod private {
}
}
#[derive(Clone, Debug)]
pub struct MapAsEnum<A> {
map: A,
}
+1 -1
View File
@@ -10,7 +10,7 @@
/// bother with this macro and may assume support for 128-bit integers.
///
/// ```edition2018
/// # use serde::__private::ser::Error;
/// # use serde::__private::doc::Error;
/// #
/// # struct MySerializer;
/// #
+4 -1
View File
@@ -84,7 +84,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.120")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.123")]
// 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
@@ -276,6 +276,9 @@ use self::__private as export;
#[allow(unused_imports)]
use self::__private as private;
#[path = "de/seed.rs"]
mod seed;
#[cfg(not(feature = "std"))]
mod std_error;
+84 -88
View File
@@ -1,9 +1,10 @@
use lib::*;
use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor};
use de::value::{BorrowedBytesDeserializer, BytesDeserializer};
use de::{Deserialize, Deserializer, Error, IntoDeserializer, Visitor};
#[cfg(any(feature = "std", feature = "alloc"))]
use de::{MapAccess, Unexpected};
use de::{DeserializeSeed, MapAccess, Unexpected};
#[cfg(any(feature = "std", feature = "alloc"))]
pub use self::content::{
@@ -12,6 +13,8 @@ pub use self::content::{
TagOrContentField, TagOrContentFieldVisitor, TaggedContentVisitor, UntaggedUnitVisitor,
};
pub use seed::InPlaceSeed;
/// If the missing field is of type `Option<T>` then treat is as `None`,
/// otherwise it is an error.
pub fn missing_field<'de, V, E>(field: &'static str) -> Result<V, E>
@@ -188,29 +191,6 @@ where
.map(From::from)
}
pub mod size_hint {
use lib::*;
pub fn from_bounds<I>(iter: &I) -> Option<usize>
where
I: Iterator,
{
helper(iter.size_hint())
}
#[inline]
pub fn cautious(hint: Option<usize>) -> usize {
cmp::min(hint.unwrap_or(0), 4096)
}
fn helper(bounds: (usize, Option<usize>)) -> Option<usize> {
match bounds {
(lower, Some(upper)) if lower == upper => Some(upper),
_ => None,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
mod content {
// This module is private and nothing here should be used outside of
@@ -225,7 +205,7 @@ mod content {
use lib::*;
use super::size_hint;
use __private::size_hint;
use de::{
self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, IgnoredAny,
MapAccess, SeqAccess, Unexpected, Visitor,
@@ -824,15 +804,17 @@ mod content {
/// Not public API.
pub struct TaggedContentVisitor<'de, T> {
tag_name: &'static str,
expecting: &'static str,
value: PhantomData<TaggedContent<'de, T>>,
}
impl<'de, T> TaggedContentVisitor<'de, T> {
/// Visitor for the content of an internally tagged enum with the given
/// tag name.
pub fn new(name: &'static str) -> Self {
pub fn new(name: &'static str, expecting: &'static str) -> Self {
TaggedContentVisitor {
tag_name: name,
expecting: expecting,
value: PhantomData,
}
}
@@ -861,7 +843,7 @@ mod content {
type Value = TaggedContent<'de, T>;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("internally tagged enum")
fmt.write_str(self.expecting)
}
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
@@ -1040,6 +1022,25 @@ mod content {
_ => Err(self.invalid_type(&visitor)),
}
}
fn deserialize_float<V>(self, visitor: V) -> Result<V::Value, E>
where
V: Visitor<'de>,
{
match self.content {
Content::F32(v) => visitor.visit_f32(v),
Content::F64(v) => visitor.visit_f64(v),
Content::U8(v) => visitor.visit_u8(v),
Content::U16(v) => visitor.visit_u16(v),
Content::U32(v) => visitor.visit_u32(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I8(v) => visitor.visit_i8(v),
Content::I16(v) => visitor.visit_i16(v),
Content::I32(v) => visitor.visit_i32(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
}
}
fn visit_content_seq<'de, V, E>(content: Vec<Content<'de>>, visitor: V) -> Result<V::Value, E>
@@ -1179,25 +1180,14 @@ mod content {
where
V: Visitor<'de>,
{
match self.content {
Content::F32(v) => visitor.visit_f32(v),
Content::F64(v) => visitor.visit_f64(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
self.deserialize_float(visitor)
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
Content::F64(v) => visitor.visit_f64(v),
Content::U64(v) => visitor.visit_u64(v),
Content::I64(v) => visitor.visit_i64(v),
_ => Err(self.invalid_type(&visitor)),
}
self.deserialize_float(visitor)
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
@@ -2542,11 +2532,13 @@ pub trait IdentifierDeserializer<'de, E: Error> {
fn from(self) -> Self::Deserializer;
}
impl<'de, E> IdentifierDeserializer<'de, E> for u32
pub struct Borrowed<'de, T: 'de + ?Sized>(pub &'de T);
impl<'de, E> IdentifierDeserializer<'de, E> for u64
where
E: Error,
{
type Deserializer = <u32 as IntoDeserializer<'de, E>>::Deserializer;
type Deserializer = <u64 as IntoDeserializer<'de, E>>::Deserializer;
fn from(self) -> Self::Deserializer {
self.into_deserializer()
@@ -2558,20 +2550,6 @@ pub struct StrDeserializer<'a, E> {
marker: PhantomData<E>,
}
impl<'a, E> IdentifierDeserializer<'a, E> for &'a str
where
E: Error,
{
type Deserializer = StrDeserializer<'a, E>;
fn from(self) -> Self::Deserializer {
StrDeserializer {
value: self,
marker: PhantomData,
}
}
}
impl<'de, 'a, E> Deserializer<'de> for StrDeserializer<'a, E>
where
E: Error,
@@ -2592,26 +2570,12 @@ where
}
}
pub struct BytesDeserializer<'a, E> {
value: &'a [u8],
pub struct BorrowedStrDeserializer<'de, E> {
value: &'de str,
marker: PhantomData<E>,
}
impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8]
where
E: Error,
{
type Deserializer = BytesDeserializer<'a, E>;
fn from(self) -> Self::Deserializer {
BytesDeserializer {
value: self,
marker: PhantomData,
}
}
}
impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
impl<'de, E> Deserializer<'de> for BorrowedStrDeserializer<'de, E>
where
E: Error,
{
@@ -2621,7 +2585,7 @@ where
where
V: Visitor<'de>,
{
visitor.visit_bytes(self.value)
visitor.visit_borrowed_str(self.value)
}
forward_to_deserialize_any! {
@@ -2631,21 +2595,53 @@ where
}
}
/// A DeserializeSeed helper for implementing deserialize_in_place Visitors.
///
/// Wraps a mutable reference and calls deserialize_in_place on it.
pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T);
impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
impl<'a, E> IdentifierDeserializer<'a, E> for &'a str
where
T: Deserialize<'de>,
E: Error,
{
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize_in_place(deserializer, self.0)
type Deserializer = StrDeserializer<'a, E>;
fn from(self) -> Self::Deserializer {
StrDeserializer {
value: self,
marker: PhantomData,
}
}
}
impl<'de, E> IdentifierDeserializer<'de, E> for Borrowed<'de, str>
where
E: Error,
{
type Deserializer = BorrowedStrDeserializer<'de, E>;
fn from(self) -> Self::Deserializer {
BorrowedStrDeserializer {
value: self.0,
marker: PhantomData,
}
}
}
impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8]
where
E: Error,
{
type Deserializer = BytesDeserializer<'a, E>;
fn from(self) -> Self::Deserializer {
BytesDeserializer::new(self)
}
}
impl<'de, E> IdentifierDeserializer<'de, E> for Borrowed<'de, [u8]>
where
E: Error,
{
type Deserializer = BorrowedBytesDeserializer<'de, E>;
fn from(self) -> Self::Deserializer {
BorrowedBytesDeserializer::new(self.0)
}
}
@@ -1,3 +1,35 @@
// Used only by Serde doc tests. Not public API.
use lib::*;
use ser;
#[doc(hidden)]
#[derive(Debug)]
pub struct Error;
impl ser::Error for Error {
fn custom<T>(_: T) -> Self
where
T: Display,
{
unimplemented!()
}
}
#[cfg(feature = "std")]
impl error::Error for Error {
fn description(&self) -> &str {
unimplemented!()
}
}
impl Display for Error {
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __private_serialize {
@@ -10,19 +42,6 @@ macro_rules! __private_serialize {
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __private_deserialize {
() => {
trait Deserialize<'de>: Sized {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: $crate::Deserializer<'de>;
}
};
}
/// Used only by Serde doc tests. Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! __serialize_unimplemented {
+7 -2
View File
@@ -1,8 +1,13 @@
mod macros;
#[cfg(serde_derive)]
pub mod de;
#[cfg(serde_derive)]
pub mod ser;
pub mod size_hint;
// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed.
pub mod doc;
pub use lib::clone::Clone;
pub use lib::convert::{From, Into};
pub use lib::default::Default;
-28
View File
@@ -335,33 +335,6 @@ where
}
}
/// Used only by Serde doc tests. Not public API.
#[doc(hidden)]
#[derive(Debug)]
pub struct Error;
impl ser::Error for Error {
fn custom<T>(_: T) -> Self
where
T: Display,
{
unimplemented!()
}
}
#[cfg(feature = "std")]
impl error::Error for Error {
fn description(&self) -> &str {
unimplemented!()
}
}
impl Display for Error {
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
mod content {
use lib::*;
@@ -452,7 +425,6 @@ mod content {
}
}
#[derive(Debug)]
pub enum Content {
Bool(bool),
+21
View File
@@ -0,0 +1,21 @@
use lib::*;
pub fn from_bounds<I>(iter: &I) -> Option<usize>
where
I: Iterator,
{
helper(iter.size_hint())
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[inline]
pub fn cautious(hint: Option<usize>) -> usize {
cmp::min(hint.unwrap_or(0), 4096)
}
fn helper(bounds: (usize, Option<usize>)) -> Option<usize> {
match bounds {
(lower, Some(upper)) if lower == upper => Some(upper),
_ => None,
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ use ser::{
///
/// ```edition2018
/// # use serde::ser::{Serializer, Impossible};
/// # use serde::__private::ser::Error;
/// # use serde::__private::doc::Error;
/// #
/// # struct MySerializer;
/// #
+1 -1
View File
@@ -711,7 +711,7 @@ pub trait Serializer: Sized {
///
/// ```edition2018
/// # use serde::ser::{Serializer, SerializeSeq};
/// # use serde::__private::ser::Error;
/// # use serde::__private::doc::Error;
/// #
/// # struct MySerializer;
/// #
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.120" # remember to update html_root_url
version = "1.0.123" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT OR Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -22,7 +22,7 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0.58", features = ["visit"] }
syn = "1.0.60"
[dev-dependencies]
serde = { version = "1.0", path = "../serde" }
+94 -3
View File
@@ -2,7 +2,6 @@ use std::collections::HashSet;
use syn;
use syn::punctuated::{Pair, Punctuated};
use syn::visit::{self, Visit};
use internals::ast::{Container, Data};
use internals::{attr, ungroup};
@@ -112,7 +111,8 @@ pub fn with_bound(
// parameters.
associated_type_usage: Vec<&'ast syn::TypePath>,
}
impl<'ast> Visit<'ast> for FindTyParams<'ast> {
impl<'ast> FindTyParams<'ast> {
fn visit_field(&mut self, field: &'ast syn::Field) {
if let syn::Type::Path(ty) = ungroup(&field.ty) {
if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() {
@@ -138,7 +138,98 @@ pub fn with_bound(
self.relevant_type_params.insert(id.clone());
}
}
visit::visit_path(self, path);
for segment in &path.segments {
self.visit_path_segment(segment);
}
}
// Everything below is simply traversing the syntax tree.
fn visit_type(&mut self, ty: &'ast syn::Type) {
match ty {
syn::Type::Array(ty) => self.visit_type(&ty.elem),
syn::Type::BareFn(ty) => {
for arg in &ty.inputs {
self.visit_type(&arg.ty);
}
self.visit_return_type(&ty.output);
}
syn::Type::Group(ty) => self.visit_type(&ty.elem),
syn::Type::ImplTrait(ty) => {
for bound in &ty.bounds {
self.visit_type_param_bound(bound);
}
}
syn::Type::Macro(ty) => self.visit_macro(&ty.mac),
syn::Type::Paren(ty) => self.visit_type(&ty.elem),
syn::Type::Path(ty) => {
if let Some(qself) = &ty.qself {
self.visit_type(&qself.ty);
}
self.visit_path(&ty.path);
}
syn::Type::Ptr(ty) => self.visit_type(&ty.elem),
syn::Type::Reference(ty) => self.visit_type(&ty.elem),
syn::Type::Slice(ty) => self.visit_type(&ty.elem),
syn::Type::TraitObject(ty) => {
for bound in &ty.bounds {
self.visit_type_param_bound(bound);
}
}
syn::Type::Tuple(ty) => {
for elem in &ty.elems {
self.visit_type(elem);
}
}
syn::Type::Infer(_) | syn::Type::Never(_) | syn::Type::Verbatim(_) => {}
#[cfg(test)]
syn::Type::__TestExhaustive(_) => unimplemented!(),
#[cfg(not(test))]
_ => {}
}
}
fn visit_path_segment(&mut self, segment: &'ast syn::PathSegment) {
self.visit_path_arguments(&segment.arguments);
}
fn visit_path_arguments(&mut self, arguments: &'ast syn::PathArguments) {
match arguments {
syn::PathArguments::None => {}
syn::PathArguments::AngleBracketed(arguments) => {
for arg in &arguments.args {
match arg {
syn::GenericArgument::Type(arg) => self.visit_type(arg),
syn::GenericArgument::Binding(arg) => self.visit_type(&arg.ty),
syn::GenericArgument::Lifetime(_)
| syn::GenericArgument::Constraint(_)
| syn::GenericArgument::Const(_) => {}
}
}
}
syn::PathArguments::Parenthesized(arguments) => {
for argument in &arguments.inputs {
self.visit_type(argument);
}
self.visit_return_type(&arguments.output);
}
}
}
fn visit_return_type(&mut self, return_type: &'ast syn::ReturnType) {
match return_type {
syn::ReturnType::Default => {}
syn::ReturnType::Type(_, output) => self.visit_type(output),
}
}
fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) {
match bound {
syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
syn::TypeParamBound::Lifetime(_) => {}
}
}
// Type parameter should not be considered used by a macro path.
+119 -63
View File
@@ -8,13 +8,17 @@ use bound;
use dummy;
use fragment::{Expr, Fragment, Match, Stmts};
use internals::ast::{Container, Data, Field, Style, Variant};
use internals::{attr, ungroup, Ctxt, Derive};
use internals::{attr, replace_receiver, ungroup, Ctxt, Derive};
use pretend;
use std::collections::BTreeSet;
use std::ptr;
pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
pub fn expand_derive_deserialize(
input: &mut syn::DeriveInput,
) -> Result<TokenStream, Vec<syn::Error>> {
replace_receiver(input);
let ctxt = Ctxt::new();
let cont = match Container::from_ast(&ctxt, input, Derive::Deserialize) {
Some(cont) => cont,
@@ -402,6 +406,7 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
let type_name = cattrs.name().deserialize_name();
let expecting = format!("unit struct {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting);
quote_block! {
struct __Visitor;
@@ -459,6 +464,7 @@ fn deserialize_tuple(
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
None => format!("tuple struct {}", params.type_name()),
};
let expecting = cattrs.expecting().unwrap_or(&expecting);
let nfields = fields.len();
@@ -545,6 +551,7 @@ fn deserialize_tuple_in_place(
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
None => format!("tuple struct {}", params.type_name()),
};
let expecting = cattrs.expecting().unwrap_or(&expecting);
let nfields = fields.len();
@@ -633,6 +640,7 @@ fn deserialize_seq(
} else {
format!("{} with {} elements", expecting, deserialized_count)
};
let expecting = cattrs.expecting().unwrap_or(&expecting);
let mut index_in_seq = 0_usize;
let let_values = vars.clone().zip(fields).map(|(var, field)| {
@@ -735,6 +743,7 @@ fn deserialize_seq_in_place(
} else {
format!("{} with {} elements", expecting, deserialized_count)
};
let expecting = cattrs.expecting().unwrap_or(&expecting);
let mut index_in_seq = 0usize;
let write_values = fields.iter().map(|field| {
@@ -910,6 +919,7 @@ fn deserialize_struct(
Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident),
None => format!("struct {}", params.type_name()),
};
let expecting = cattrs.expecting().unwrap_or(&expecting);
let visit_seq = Stmts(deserialize_seq(
&type_path, params, fields, true, cattrs, &expecting,
@@ -1051,6 +1061,7 @@ fn deserialize_struct_in_place(
Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident),
None => format!("struct {}", params.type_name()),
};
let expecting = cattrs.expecting().unwrap_or(&expecting);
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting));
@@ -1203,6 +1214,7 @@ fn deserialize_externally_tagged_enum(
let type_name = cattrs.name().deserialize_name();
let expecting = format!("enum {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting);
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs);
@@ -1312,6 +1324,9 @@ fn deserialize_internally_tagged_enum(
}
});
let expecting = format!("internally tagged enum {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting);
quote_block! {
#variant_visitor
@@ -1319,7 +1334,7 @@ fn deserialize_internally_tagged_enum(
let __tagged = try!(_serde::Deserializer::deserialize_any(
__deserializer,
_serde::__private::de::TaggedContentVisitor::<__Field>::new(#tag)));
_serde::__private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting)));
match __tagged.tag {
#(#variant_arms)*
@@ -1362,6 +1377,7 @@ fn deserialize_adjacently_tagged_enum(
.collect();
let expecting = format!("adjacently tagged enum {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting);
let type_name = cattrs.name().deserialize_name();
let deny_unknown_fields = cattrs.deny_unknown_fields();
@@ -1653,6 +1669,7 @@ fn deserialize_untagged_enum(
"data did not match any variant of untagged enum {}",
params.type_name()
);
let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg);
quote_block! {
let __content = try!(<_serde::__private::de::Content as _serde::Deserialize>::deserialize(__deserializer));
@@ -1909,7 +1926,9 @@ fn deserialize_generated_identifier(
fields,
is_variant,
fallthrough,
None,
!is_variant && cattrs.has_flatten(),
None,
));
let lifetime = if !is_variant && cattrs.has_flatten() {
@@ -1945,6 +1964,8 @@ fn deserialize_generated_identifier(
}
}
// Generates `Deserialize::deserialize` body for an enum with
// `serde(field_identifier)` or `serde(variant_identifier)` attribute.
fn deserialize_custom_identifier(
params: &Parameters,
variants: &[Variant],
@@ -1959,26 +1980,38 @@ fn deserialize_custom_identifier(
let this = &params.this;
let this = quote!(#this);
let (ordinary, fallthrough) = if let Some(last) = variants.last() {
let (ordinary, fallthrough, fallthrough_borrowed) = if let Some(last) = variants.last() {
let last_ident = &last.ident;
if last.attrs.other() {
// Process `serde(other)` attribute. It would always be found on the
// last variant (checked in `check_identifier`), so all preceding
// are ordinary variants.
let ordinary = &variants[..variants.len() - 1];
let fallthrough = quote!(_serde::__private::Ok(#this::#last_ident));
(ordinary, Some(fallthrough))
(ordinary, Some(fallthrough), None)
} else if let Style::Newtype = last.style {
let ordinary = &variants[..variants.len() - 1];
let deserializer = quote!(_serde::__private::de::IdentifierDeserializer::from(__value));
let fallthrough = quote! {
_serde::__private::Result::map(
_serde::Deserialize::deserialize(#deserializer),
#this::#last_ident)
let fallthrough = |value| {
quote! {
_serde::__private::Result::map(
_serde::Deserialize::deserialize(
_serde::__private::de::IdentifierDeserializer::from(#value)
),
#this::#last_ident)
}
};
(ordinary, Some(fallthrough))
(
ordinary,
Some(fallthrough(quote!(__value))),
Some(fallthrough(quote!(_serde::__private::de::Borrowed(
__value
)))),
)
} else {
(variants, None)
(variants, None, None)
}
} else {
(variants, None)
(variants, None, None)
};
let names_idents: Vec<_> = ordinary
@@ -2016,7 +2049,9 @@ fn deserialize_custom_identifier(
&names_idents,
is_variant,
fallthrough,
fallthrough_borrowed,
false,
cattrs.expecting(),
));
quote_block! {
@@ -2046,21 +2081,20 @@ fn deserialize_identifier(
fields: &[(String, Ident, Vec<String>)],
is_variant: bool,
fallthrough: Option<TokenStream>,
fallthrough_borrowed: Option<TokenStream>,
collect_other_fields: bool,
expecting: Option<&str>,
) -> Fragment {
let mut flat_fields = Vec::new();
for (_, ident, aliases) in fields {
flat_fields.extend(aliases.iter().map(|alias| (alias, ident)))
}
let field_strs = flat_fields.iter().map(|(name, _)| name);
let field_borrowed_strs = flat_fields.iter().map(|(name, _)| name);
let field_bytes = flat_fields
let field_strs: &Vec<_> = &flat_fields.iter().map(|(name, _)| name).collect();
let field_bytes: &Vec<_> = &flat_fields
.iter()
.map(|(name, _)| Literal::byte_string(name.as_bytes()));
let field_borrowed_bytes = flat_fields
.iter()
.map(|(name, _)| Literal::byte_string(name.as_bytes()));
.map(|(name, _)| Literal::byte_string(name.as_bytes()))
.collect();
let constructors: &Vec<_> = &flat_fields
.iter()
@@ -2071,11 +2105,11 @@ fn deserialize_identifier(
.map(|(_, ident, _)| quote!(#this::#ident))
.collect();
let expecting = if is_variant {
let expecting = expecting.unwrap_or(if is_variant {
"variant identifier"
} else {
"field identifier"
};
});
let index_expecting = if is_variant { "variant" } else { "field" };
@@ -2111,20 +2145,36 @@ fn deserialize_identifier(
(None, None, None, None)
};
let fallthrough_arm = if let Some(fallthrough) = fallthrough {
let fallthrough_arm_tokens;
let fallthrough_arm = if let Some(fallthrough) = &fallthrough {
fallthrough
} else if is_variant {
quote! {
fallthrough_arm_tokens = quote! {
_serde::__private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS))
}
};
&fallthrough_arm_tokens
} else {
quote! {
fallthrough_arm_tokens = quote! {
_serde::__private::Err(_serde::de::Error::unknown_field(__value, FIELDS))
}
};
&fallthrough_arm_tokens
};
let u64_fallthrough_arm_tokens;
let u64_fallthrough_arm = if let Some(fallthrough) = &fallthrough {
fallthrough
} else {
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
u64_fallthrough_arm_tokens = quote! {
_serde::__private::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&#fallthrough_msg,
))
};
&u64_fallthrough_arm_tokens
};
let variant_indices = 0_u64..;
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
let visit_other = if collect_other_fields {
quote! {
fn visit_bool<__E>(self, __value: bool) -> _serde::__private::Result<Self::Value, __E>
@@ -2217,37 +2267,6 @@ fn deserialize_identifier(
{
_serde::__private::Ok(__Field::__other(_serde::__private::de::Content::Unit))
}
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(
#field_borrowed_strs => _serde::__private::Ok(#constructors),
)*
_ => {
#value_as_borrowed_str_content
#fallthrough_arm
}
}
}
fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::__private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(
#field_borrowed_bytes => _serde::__private::Ok(#constructors),
)*
_ => {
#bytes_to_str
#value_as_borrowed_bytes_content
#fallthrough_arm
}
}
}
}
} else {
quote! {
@@ -2259,15 +2278,50 @@ fn deserialize_identifier(
#(
#variant_indices => _serde::__private::Ok(#main_constructors),
)*
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&#fallthrough_msg,
))
_ => #u64_fallthrough_arm,
}
}
}
};
let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields {
let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(&fallthrough_arm);
Some(quote! {
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(
#field_strs => _serde::__private::Ok(#constructors),
)*
_ => {
#value_as_borrowed_str_content
#fallthrough_borrowed_arm
}
}
}
fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::__private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(
#field_bytes => _serde::__private::Ok(#constructors),
)*
_ => {
#bytes_to_str
#value_as_borrowed_bytes_content
#fallthrough_borrowed_arm
}
}
}
})
} else {
None
};
quote_block! {
fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result {
_serde::__private::Formatter::write_str(__formatter, #expecting)
@@ -2305,6 +2359,8 @@ fn deserialize_identifier(
}
}
}
#visit_borrowed
}
}
+56 -63
View File
@@ -1,10 +1,10 @@
use internals::respan::respan;
use internals::symbol::*;
use internals::{ungroup, Ctxt};
use proc_macro2::{Group, Span, TokenStream, TokenTree};
use proc_macro2::{Spacing, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::borrow::Cow;
use std::collections::BTreeSet;
use std::str::FromStr;
use syn;
use syn::parse::{self, Parse, ParseStream};
use syn::punctuated::Punctuated;
@@ -223,6 +223,8 @@ pub struct Container {
has_flatten: bool,
serde_path: Option<syn::Path>,
is_packed: bool,
/// Error message generated when type can't be deserialized
expecting: Option<String>,
}
/// Styles of representing an enum.
@@ -305,6 +307,7 @@ impl Container {
let mut field_identifier = BoolAttr::none(cx, FIELD_IDENTIFIER);
let mut variant_identifier = BoolAttr::none(cx, VARIANT_IDENTIFIER);
let mut serde_path = Attr::none(cx, CRATE);
let mut expecting = Attr::none(cx, EXPECTING);
for meta_item in item
.attrs
@@ -337,13 +340,7 @@ impl Container {
rename_all_ser_rule.set(&m.path, rename_rule);
rename_all_de_rule.set(&m.path, rename_rule);
}
Err(()) => cx.error_spanned_by(
s,
format!(
"unknown rename rule for #[serde(rename_all = {:?})]",
s.value(),
),
),
Err(err) => cx.error_spanned_by(s, err),
}
}
}
@@ -354,25 +351,13 @@ impl Container {
if let Some(ser) = ser {
match RenameRule::from_str(&ser.value()) {
Ok(rename_rule) => rename_all_ser_rule.set(&m.path, rename_rule),
Err(()) => cx.error_spanned_by(
ser,
format!(
"unknown rename rule for #[serde(rename_all = {:?})]",
ser.value(),
),
),
Err(err) => cx.error_spanned_by(ser, err),
}
}
if let Some(de) = de {
match RenameRule::from_str(&de.value()) {
Ok(rename_rule) => rename_all_de_rule.set(&m.path, rename_rule),
Err(()) => cx.error_spanned_by(
de,
format!(
"unknown rename rule for #[serde(rename_all = {:?})]",
de.value(),
),
),
Err(err) => cx.error_spanned_by(de, err),
}
}
}
@@ -575,6 +560,13 @@ impl Container {
}
}
// Parse `#[serde(expecting = "a message")]`
Meta(NameValue(m)) if m.path == EXPECTING => {
if let Ok(s) = get_lit_str(cx, EXPECTING, &m.lit) {
expecting.set(&m.path, s.value());
}
}
Meta(meta_item) => {
let path = meta_item
.path()
@@ -627,6 +619,7 @@ impl Container {
has_flatten: false,
serde_path: serde_path.get(),
is_packed,
expecting: expecting.get(),
}
}
@@ -702,6 +695,12 @@ impl Container {
self.custom_serde_path()
.map_or_else(|| Cow::Owned(parse_quote!(_serde)), Cow::Borrowed)
}
/// Error message generated when type can't be deserialized.
/// If `None`, default message will be used
pub fn expecting(&self) -> Option<&str> {
self.expecting.as_ref().map(String::as_ref)
}
}
fn decide_tag(
@@ -914,13 +913,7 @@ impl Variant {
rename_all_ser_rule.set(&m.path, rename_rule);
rename_all_de_rule.set(&m.path, rename_rule);
}
Err(()) => cx.error_spanned_by(
s,
format!(
"unknown rename rule for #[serde(rename_all = {:?})]",
s.value()
),
),
Err(err) => cx.error_spanned_by(s, err),
}
}
}
@@ -931,25 +924,13 @@ impl Variant {
if let Some(ser) = ser {
match RenameRule::from_str(&ser.value()) {
Ok(rename_rule) => rename_all_ser_rule.set(&m.path, rename_rule),
Err(()) => cx.error_spanned_by(
ser,
format!(
"unknown rename rule for #[serde(rename_all = {:?})]",
ser.value(),
),
),
Err(err) => cx.error_spanned_by(ser, err),
}
}
if let Some(de) = de {
match RenameRule::from_str(&de.value()) {
Ok(rename_rule) => rename_all_de_rule.set(&m.path, rename_rule),
Err(()) => cx.error_spanned_by(
de,
format!(
"unknown rename rule for #[serde(rename_all = {:?})]",
de.value(),
),
),
Err(err) => cx.error_spanned_by(de, err),
}
}
}
@@ -1921,14 +1902,41 @@ fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
syn::Type::Group(ty) => {
collect_lifetimes(&ty.elem, out);
}
syn::Type::Macro(ty) => {
collect_lifetimes_from_tokens(ty.mac.tokens.clone(), out);
}
syn::Type::BareFn(_)
| syn::Type::Never(_)
| syn::Type::TraitObject(_)
| syn::Type::ImplTrait(_)
| syn::Type::Infer(_)
| syn::Type::Macro(_)
| syn::Type::Verbatim(_)
| _ => {}
| syn::Type::Verbatim(_) => {}
#[cfg(test)]
syn::Type::__TestExhaustive(_) => unimplemented!(),
#[cfg(not(test))]
_ => {}
}
}
fn collect_lifetimes_from_tokens(tokens: TokenStream, out: &mut BTreeSet<syn::Lifetime>) {
let mut iter = tokens.into_iter();
while let Some(tt) = iter.next() {
match &tt {
TokenTree::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
if let Some(TokenTree::Ident(ident)) = iter.next() {
out.insert(syn::Lifetime {
apostrophe: op.span(),
ident,
});
}
}
TokenTree::Group(group) => {
let tokens = group.stream();
collect_lifetimes_from_tokens(tokens, out);
}
_ => {}
}
}
}
@@ -1942,20 +1950,5 @@ where
fn spanned_tokens(s: &syn::LitStr) -> parse::Result<TokenStream> {
let stream = syn::parse_str(&s.value())?;
Ok(respan_token_stream(stream, s.span()))
}
fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
stream
.into_iter()
.map(|token| respan_token_tree(token, span))
.collect()
}
fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
if let TokenTree::Group(g) = &mut token {
*g = Group::new(g.delimiter(), respan_token_stream(g.stream(), span));
}
token.set_span(span);
token
Ok(respan(stream, s.span()))
}
+42 -19
View File
@@ -5,7 +5,7 @@
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
use std::str::FromStr;
use std::fmt::{self, Debug, Display};
use self::RenameRule::*;
@@ -17,7 +17,7 @@ pub enum RenameRule {
/// Rename direct children to "lowercase" style.
LowerCase,
/// Rename direct children to "UPPERCASE" style.
UPPERCASE,
UpperCase,
/// Rename direct children to "PascalCase" style, as typically used for
/// enum variants.
PascalCase,
@@ -35,13 +35,35 @@ pub enum RenameRule {
ScreamingKebabCase,
}
static RENAME_RULES: &[(&str, RenameRule)] = &[
("lowercase", LowerCase),
("UPPERCASE", UpperCase),
("PascalCase", PascalCase),
("camelCase", CamelCase),
("snake_case", SnakeCase),
("SCREAMING_SNAKE_CASE", ScreamingSnakeCase),
("kebab-case", KebabCase),
("SCREAMING-KEBAB-CASE", ScreamingKebabCase),
];
impl RenameRule {
pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError> {
for (name, rule) in RENAME_RULES {
if rename_all_str == *name {
return Ok(*rule);
}
}
Err(ParseError {
unknown: rename_all_str,
})
}
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
pub fn apply_to_variant(&self, variant: &str) -> String {
match *self {
None | PascalCase => variant.to_owned(),
LowerCase => variant.to_ascii_lowercase(),
UPPERCASE => variant.to_ascii_uppercase(),
UpperCase => variant.to_ascii_uppercase(),
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
SnakeCase => {
let mut snake = String::new();
@@ -65,7 +87,7 @@ impl RenameRule {
pub fn apply_to_field(&self, field: &str) -> String {
match *self {
None | LowerCase | SnakeCase => field.to_owned(),
UPPERCASE => field.to_ascii_uppercase(),
UpperCase => field.to_ascii_uppercase(),
PascalCase => {
let mut pascal = String::new();
let mut capitalize = true;
@@ -92,21 +114,22 @@ impl RenameRule {
}
}
impl FromStr for RenameRule {
type Err = ();
pub struct ParseError<'a> {
unknown: &'a str,
}
fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> {
match rename_all_str {
"lowercase" => Ok(LowerCase),
"UPPERCASE" => Ok(UPPERCASE),
"PascalCase" => Ok(PascalCase),
"camelCase" => Ok(CamelCase),
"snake_case" => Ok(SnakeCase),
"SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
"kebab-case" => Ok(KebabCase),
"SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase),
_ => Err(()),
impl<'a> Display for ParseError<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("unknown rename rule `rename_all = ")?;
Debug::fmt(self.unknown, f)?;
f.write_str("`, expected one of ")?;
for (i, (name, _rule)) in RENAME_RULES.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
Debug::fmt(name, f)?;
}
Ok(())
}
}
@@ -131,7 +154,7 @@ fn rename_variants() {
] {
assert_eq!(None.apply_to_variant(original), original);
assert_eq!(LowerCase.apply_to_variant(original), lower);
assert_eq!(UPPERCASE.apply_to_variant(original), upper);
assert_eq!(UpperCase.apply_to_variant(original), upper);
assert_eq!(PascalCase.apply_to_variant(original), original);
assert_eq!(CamelCase.apply_to_variant(original), camel);
assert_eq!(SnakeCase.apply_to_variant(original), snake);
@@ -163,7 +186,7 @@ fn rename_fields() {
("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
] {
assert_eq!(None.apply_to_field(original), original);
assert_eq!(UPPERCASE.apply_to_field(original), upper);
assert_eq!(UpperCase.apply_to_field(original), upper);
assert_eq!(PascalCase.apply_to_field(original), pascal);
assert_eq!(CamelCase.apply_to_field(original), camel);
assert_eq!(SnakeCase.apply_to_field(original), original);
+4
View File
@@ -4,8 +4,12 @@ pub mod attr;
mod ctxt;
pub use self::ctxt::Ctxt;
mod receiver;
pub use self::receiver::replace_receiver;
mod case;
mod check;
mod respan;
mod symbol;
use syn::Type;
+287
View File
@@ -0,0 +1,287 @@
use internals::respan::respan;
use proc_macro2::Span;
use quote::ToTokens;
use std::mem;
use syn::punctuated::Punctuated;
use syn::{
parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro,
Path, PathArguments, QSelf, ReturnType, Type, TypeParamBound, TypePath, WherePredicate,
};
pub fn replace_receiver(input: &mut DeriveInput) {
let self_ty = {
let ident = &input.ident;
let ty_generics = input.generics.split_for_impl().1;
parse_quote!(#ident #ty_generics)
};
let mut visitor = ReplaceReceiver(&self_ty);
visitor.visit_generics_mut(&mut input.generics);
visitor.visit_data_mut(&mut input.data);
}
struct ReplaceReceiver<'a>(&'a TypePath);
impl ReplaceReceiver<'_> {
fn self_ty(&self, span: Span) -> TypePath {
let tokens = self.0.to_token_stream();
let respanned = respan(tokens, span);
syn::parse2(respanned).unwrap()
}
fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
if path.leading_colon.is_some() || path.segments[0].ident != "Self" {
return;
}
if path.segments.len() == 1 {
self.self_to_expr_path(path);
return;
}
let span = path.segments[0].ident.span();
*qself = Some(QSelf {
lt_token: Token![<](span),
ty: Box::new(Type::Path(self.self_ty(span))),
position: 0,
as_token: None,
gt_token: Token![>](span),
});
path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
let segments = mem::replace(&mut path.segments, Punctuated::new());
path.segments = segments.into_pairs().skip(1).collect();
}
fn self_to_expr_path(&self, path: &mut Path) {
let self_ty = self.self_ty(path.segments[0].ident.span());
let variant = mem::replace(path, self_ty.path);
for segment in &mut path.segments {
if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
bracketed.colon2_token = Some(<Token![::]>::default());
}
}
}
if variant.segments.len() > 1 {
path.segments.push_punct(<Token![::]>::default());
path.segments.extend(variant.segments.into_pairs().skip(1));
}
}
}
impl ReplaceReceiver<'_> {
// `Self` -> `Receiver`
fn visit_type_mut(&mut self, ty: &mut Type) {
let span = if let Type::Path(node) = ty {
if node.qself.is_none() && node.path.is_ident("Self") {
node.path.segments[0].ident.span()
} else {
self.visit_type_path_mut(node);
return;
}
} else {
self.visit_type_mut_impl(ty);
return;
};
*ty = self.self_ty(span).into();
}
// `Self::Assoc` -> `<Receiver>::Assoc`
fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
if ty.qself.is_none() {
self.self_to_qself(&mut ty.qself, &mut ty.path);
}
self.visit_type_path_mut_impl(ty);
}
// `Self::method` -> `<Receiver>::method`
fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
if expr.qself.is_none() {
self.self_to_qself(&mut expr.qself, &mut expr.path);
}
self.visit_expr_path_mut_impl(expr);
}
// Everything below is simply traversing the syntax tree.
fn visit_type_mut_impl(&mut self, ty: &mut Type) {
match ty {
Type::Array(ty) => {
self.visit_type_mut(&mut ty.elem);
self.visit_expr_mut(&mut ty.len);
}
Type::BareFn(ty) => {
for arg in &mut ty.inputs {
self.visit_type_mut(&mut arg.ty);
}
self.visit_return_type_mut(&mut ty.output);
}
Type::Group(ty) => self.visit_type_mut(&mut ty.elem),
Type::ImplTrait(ty) => {
for bound in &mut ty.bounds {
self.visit_type_param_bound_mut(bound);
}
}
Type::Macro(ty) => self.visit_macro_mut(&mut ty.mac),
Type::Paren(ty) => self.visit_type_mut(&mut ty.elem),
Type::Path(ty) => {
if let Some(qself) = &mut ty.qself {
self.visit_type_mut(&mut qself.ty);
}
self.visit_path_mut(&mut ty.path);
}
Type::Ptr(ty) => self.visit_type_mut(&mut ty.elem),
Type::Reference(ty) => self.visit_type_mut(&mut ty.elem),
Type::Slice(ty) => self.visit_type_mut(&mut ty.elem),
Type::TraitObject(ty) => {
for bound in &mut ty.bounds {
self.visit_type_param_bound_mut(bound);
}
}
Type::Tuple(ty) => {
for elem in &mut ty.elems {
self.visit_type_mut(elem);
}
}
Type::Infer(_) | Type::Never(_) | Type::Verbatim(_) => {}
#[cfg(test)]
Type::__TestExhaustive(_) => unimplemented!(),
#[cfg(not(test))]
_ => {}
}
}
fn visit_type_path_mut_impl(&mut self, ty: &mut TypePath) {
if let Some(qself) = &mut ty.qself {
self.visit_type_mut(&mut qself.ty);
}
self.visit_path_mut(&mut ty.path);
}
fn visit_expr_path_mut_impl(&mut self, expr: &mut ExprPath) {
if let Some(qself) = &mut expr.qself {
self.visit_type_mut(&mut qself.ty);
}
self.visit_path_mut(&mut expr.path);
}
fn visit_path_mut(&mut self, path: &mut Path) {
for segment in &mut path.segments {
self.visit_path_arguments_mut(&mut segment.arguments);
}
}
fn visit_path_arguments_mut(&mut self, arguments: &mut PathArguments) {
match arguments {
PathArguments::None => {}
PathArguments::AngleBracketed(arguments) => {
for arg in &mut arguments.args {
match arg {
GenericArgument::Type(arg) => self.visit_type_mut(arg),
GenericArgument::Binding(arg) => self.visit_type_mut(&mut arg.ty),
GenericArgument::Lifetime(_)
| GenericArgument::Constraint(_)
| GenericArgument::Const(_) => {}
}
}
}
PathArguments::Parenthesized(arguments) => {
for argument in &mut arguments.inputs {
self.visit_type_mut(argument);
}
self.visit_return_type_mut(&mut arguments.output);
}
}
}
fn visit_return_type_mut(&mut self, return_type: &mut ReturnType) {
match return_type {
ReturnType::Default => {}
ReturnType::Type(_, output) => self.visit_type_mut(output),
}
}
fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) {
match bound {
TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path),
TypeParamBound::Lifetime(_) => {}
}
}
fn visit_generics_mut(&mut self, generics: &mut Generics) {
for param in &mut generics.params {
match param {
GenericParam::Type(param) => {
for bound in &mut param.bounds {
self.visit_type_param_bound_mut(bound);
}
}
GenericParam::Lifetime(_) | GenericParam::Const(_) => {}
}
}
if let Some(where_clause) = &mut generics.where_clause {
for predicate in &mut where_clause.predicates {
match predicate {
WherePredicate::Type(predicate) => {
self.visit_type_mut(&mut predicate.bounded_ty);
for bound in &mut predicate.bounds {
self.visit_type_param_bound_mut(bound);
}
}
WherePredicate::Lifetime(_) | WherePredicate::Eq(_) => {}
}
}
}
}
fn visit_data_mut(&mut self, data: &mut Data) {
match data {
Data::Struct(data) => {
for field in &mut data.fields {
self.visit_type_mut(&mut field.ty);
}
}
Data::Enum(data) => {
for variant in &mut data.variants {
for field in &mut variant.fields {
self.visit_type_mut(&mut field.ty);
}
}
}
Data::Union(_) => {}
}
}
fn visit_expr_mut(&mut self, expr: &mut Expr) {
match expr {
Expr::Binary(expr) => {
self.visit_expr_mut(&mut expr.left);
self.visit_expr_mut(&mut expr.right);
}
Expr::Call(expr) => {
self.visit_expr_mut(&mut expr.func);
for arg in &mut expr.args {
self.visit_expr_mut(arg);
}
}
Expr::Cast(expr) => {
self.visit_expr_mut(&mut expr.expr);
self.visit_type_mut(&mut expr.ty);
}
Expr::Field(expr) => self.visit_expr_mut(&mut expr.base),
Expr::Index(expr) => {
self.visit_expr_mut(&mut expr.expr);
self.visit_expr_mut(&mut expr.index);
}
Expr::Paren(expr) => self.visit_expr_mut(&mut expr.expr),
Expr::Path(expr) => self.visit_expr_path_mut(expr),
Expr::Unary(expr) => self.visit_expr_mut(&mut expr.expr),
_ => {}
}
}
fn visit_macro_mut(&mut self, _mac: &mut Macro) {}
}
+16
View File
@@ -0,0 +1,16 @@
use proc_macro2::{Group, Span, TokenStream, TokenTree};
pub(crate) fn respan(stream: TokenStream, span: Span) -> TokenStream {
stream
.into_iter()
.map(|token| respan_token(token, span))
.collect()
}
fn respan_token(mut token: TokenTree, span: Span) -> TokenTree {
if let TokenTree::Group(g) = &mut token {
*g = Group::new(g.delimiter(), respan(g.stream(), span));
}
token.set_span(span);
token
}
+1
View File
@@ -35,6 +35,7 @@ pub const TRY_FROM: Symbol = Symbol("try_from");
pub const UNTAGGED: Symbol = Symbol("untagged");
pub const VARIANT_IDENTIFIER: Symbol = Symbol("variant_identifier");
pub const WITH: Symbol = Symbol("with");
pub const EXPECTING: Symbol = Symbol("expecting");
impl PartialEq<Symbol> for Ident {
fn eq(&self, word: &Symbol) -> bool {
+6 -5
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.120")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.123")]
#![allow(unknown_lints, bare_trait_objects)]
#![deny(clippy::all, clippy::pedantic)]
// Ignored clippy lints
@@ -48,6 +48,7 @@
clippy::struct_excessive_bools,
clippy::too_many_lines,
clippy::unseparated_literal_suffix,
clippy::unused_self,
clippy::use_self,
clippy::wildcard_imports
)]
@@ -78,16 +79,16 @@ mod try;
#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
ser::expand_derive_serialize(&input)
let mut input = parse_macro_input!(input as DeriveInput);
ser::expand_derive_serialize(&mut input)
.unwrap_or_else(to_compile_errors)
.into()
}
#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
de::expand_derive_deserialize(&input)
let mut input = parse_macro_input!(input as DeriveInput);
de::expand_derive_deserialize(&mut input)
.unwrap_or_else(to_compile_errors)
.into()
}
+6 -2
View File
@@ -6,10 +6,14 @@ use bound;
use dummy;
use fragment::{Fragment, Match, Stmts};
use internals::ast::{Container, Data, Field, Style, Variant};
use internals::{attr, Ctxt, Derive};
use internals::{attr, replace_receiver, Ctxt, Derive};
use pretend;
pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
pub fn expand_derive_serialize(
input: &mut syn::DeriveInput,
) -> Result<TokenStream, Vec<syn::Error>> {
replace_receiver(input);
let ctxt = Ctxt::new();
let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) {
Some(cont) => cont,
+1 -1
View File
@@ -16,7 +16,7 @@ path = "lib.rs"
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0.33", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
syn = { version = "1.0.60", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
+26 -12
View File
@@ -1,17 +1,31 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.25.0")]
#![allow(unknown_lints, bare_trait_objects)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(
feature = "cargo-clippy",
allow(
cognitive_complexity,
redundant_field_names,
result_unit_err,
trivially_copy_pass_by_ref,
wildcard_in_or_patterns,
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
unnested_or_patterns,
)
#![deny(clippy::all, clippy::pedantic)]
// Ignored clippy lints
#![allow(
clippy::cognitive_complexity,
clippy::redundant_field_names,
clippy::result_unit_err,
clippy::should_implement_trait,
clippy::trivially_copy_pass_by_ref,
clippy::wildcard_in_or_patterns,
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
clippy::unnested_or_patterns,
)]
// Ignored clippy_pedantic lints
#![allow(
clippy::doc_markdown,
clippy::enum_glob_use,
clippy::items_after_statements,
clippy::match_same_arms,
clippy::missing_errors_doc,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::similar_names,
clippy::struct_excessive_bools,
clippy::too_many_lines,
clippy::unused_self,
clippy::wildcard_imports
)]
#[macro_use]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "1.0.120" # remember to update html_root_url
version = "1.0.123" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT OR Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations"
+30
View File
@@ -0,0 +1,30 @@
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() {
let minor = match rustc_minor_version() {
Some(minor) => minor,
None => return,
};
// #[track_caller] stabilized in Rust 1.46:
// https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html#track_caller
if minor >= 46 {
println!("cargo:rustc-cfg=track_caller");
}
}
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()
}
+5
View File
@@ -28,6 +28,7 @@ use std::fmt::Debug;
/// Token::StructEnd,
/// ]);
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
T: Serialize + Deserialize<'de> + PartialEq + Debug,
@@ -58,6 +59,7 @@ where
/// Token::StructEnd,
/// ]);
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
where
T: Serialize,
@@ -110,6 +112,7 @@ where
/// assert_ser_tokens_error(&example, expected, error);
/// }
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: &str)
where
T: Serialize,
@@ -147,6 +150,7 @@ where
/// Token::StructEnd,
/// ]);
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
T: Deserialize<'de> + PartialEq + Debug,
@@ -199,6 +203,7 @@ where
/// "unknown field `x`, expected `a` or `b`",
/// );
/// ```
#[cfg_attr(track_caller, track_caller)]
pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str)
where
T: Deserialize<'de>,
+11
View File
@@ -777,6 +777,17 @@ macro_rules! impl_deserializer {
{
self.0.next_value_seed($wrapper(seed))
}
fn next_entry_seed<K, V>(
&mut self,
kseed: K,
vseed: V,
) -> Result<Option<(K::Value, V::Value)>, D::Error>
where
K: DeserializeSeed<'de>,
V: DeserializeSeed<'de>,
{
self.0.next_entry_seed($wrapper(kseed), $wrapper(vseed))
}
fn size_hint(&self) -> Option<usize> {
self.0.size_hint()
}
+29 -3
View File
@@ -168,14 +168,42 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
self.next_token();
visitor.visit_str(variant)
}
(Token::BorrowedStr(variant), Token::Unit) => {
self.next_token();
visitor.visit_borrowed_str(variant)
}
(Token::String(variant), Token::Unit) => {
self.next_token();
visitor.visit_string(variant.to_string())
}
(Token::Bytes(variant), Token::Unit) => {
self.next_token();
visitor.visit_bytes(variant)
}
(Token::BorrowedBytes(variant), Token::Unit) => {
self.next_token();
visitor.visit_borrowed_bytes(variant)
}
(Token::ByteBuf(variant), Token::Unit) => {
self.next_token();
visitor.visit_byte_buf(variant.to_vec())
}
(Token::U8(variant), Token::Unit) => {
self.next_token();
visitor.visit_u8(variant)
}
(Token::U16(variant), Token::Unit) => {
self.next_token();
visitor.visit_u16(variant)
}
(Token::U32(variant), Token::Unit) => {
self.next_token();
visitor.visit_u32(variant)
}
(Token::U64(variant), Token::Unit) => {
self.next_token();
visitor.visit_u64(variant)
}
(variant, Token::Unit) => unexpected!(variant),
(variant, _) => {
visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any))
@@ -250,9 +278,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
{
visitor.visit_enum(DeserializerEnumVisitor { de: self })
}
_ => {
unexpected!(self.next_token());
}
_ => self.deserialize_any(visitor),
}
}
+2 -1
View File
@@ -144,7 +144,7 @@
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.120")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.123")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Ignored clippy lints
@@ -158,6 +158,7 @@
module_name_repetitions,
must_use_candidate,
redundant_field_names,
too_many_lines,
use_debug,
use_self
)
+13 -13
View File
@@ -32,18 +32,18 @@ impl<'a> Serializer<'a> {
}
macro_rules! assert_next_token {
($ser:expr, $expected:ident) => {
assert_next_token!($ser, stringify!($expected), Token::$expected, true);
($ser:expr, $actual:ident) => {
assert_next_token!($ser, stringify!($actual), Token::$actual, true);
};
($ser:expr, $expected:ident($v:expr)) => {
($ser:expr, $actual:ident($v:expr)) => {
assert_next_token!(
$ser,
format_args!(concat!(stringify!($expected), "({:?})"), $v),
Token::$expected(v),
format_args!(concat!(stringify!($actual), "({:?})"), $v),
Token::$actual(v),
v == $v
);
};
($ser:expr, $expected:ident { $($k:ident),* }) => {
($ser:expr, $actual:ident { $($k:ident),* }) => {
let compare = ($($k,)*);
let field_format = || {
use std::fmt::Write;
@@ -55,21 +55,21 @@ macro_rules! assert_next_token {
};
assert_next_token!(
$ser,
format_args!(concat!(stringify!($expected), " {{ {}}}"), field_format()),
Token::$expected { $($k),* },
format_args!(concat!(stringify!($actual), " {{ {}}}"), field_format()),
Token::$actual { $($k),* },
($($k,)*) == compare
);
};
($ser:expr, $expected:expr, $pat:pat, $guard:expr) => {
($ser:expr, $actual:expr, $pat:pat, $guard:expr) => {
match $ser.next_token() {
Some($pat) if $guard => {}
Some(other) => {
Some(expected) => {
panic!("expected Token::{} but serialized as {}",
$expected, other);
expected, $actual);
}
None => {
panic!("expected Token::{} after end of serialized tokens",
$expected);
panic!("expected end of tokens, but {} was serialized",
$actual);
}
}
};
+2 -12
View File
@@ -573,12 +573,7 @@ const _: () = {
1u64 => _serde::__private::Ok(__Field::__field1),
2u64 => _serde::__private::Ok(__Field::__field2),
3u64 => _serde::__private::Ok(__Field::__field3),
_ => _serde::__private::Err(
_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 4",
),
),
_ => _serde::__private::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(
@@ -1081,12 +1076,7 @@ const _: () = {
1u64 => _serde::__private::Ok(__Field::__field1),
2u64 => _serde::__private::Ok(__Field::__field2),
3u64 => _serde::__private::Ok(__Field::__field3),
_ => _serde::__private::Err(
_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 4",
),
),
_ => _serde::__private::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(
@@ -77,10 +77,7 @@ const _: () = {
{
match __value {
0u64 => _serde::__private::Ok(__Field::__field0),
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 1",
)),
_ => _serde::__private::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(
@@ -260,10 +257,7 @@ const _: () = {
{
match __value {
0u64 => _serde::__private::Ok(__Field::__field0),
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 1",
)),
_ => _serde::__private::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(
@@ -357,12 +357,7 @@ const _: () = {
match __value {
0u64 => _serde::__private::Ok(__Field::__field0),
1u64 => _serde::__private::Ok(__Field::__field1),
_ => _serde::__private::Err(
_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 2",
),
),
_ => _serde::__private::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(
@@ -73,10 +73,7 @@ const _: () = {
{
match __value {
0u64 => _serde::__private::Ok(__Field::__field0),
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 1",
)),
_ => _serde::__private::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(
@@ -256,10 +253,7 @@ const _: () = {
{
match __value {
0u64 => _serde::__private::Ok(__Field::__field0),
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 1",
)),
_ => _serde::__private::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(
+2 -12
View File
@@ -244,12 +244,7 @@ const _: () = {
{
match __value {
0u64 => _serde::__private::Ok(__Field::__field0),
_ => _serde::__private::Err(
_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 1",
),
),
_ => _serde::__private::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(
@@ -433,12 +428,7 @@ const _: () = {
{
match __value {
0u64 => _serde::__private::Ok(__Field::__field0),
_ => _serde::__private::Err(
_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 1",
),
),
_ => _serde::__private::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(
@@ -100,10 +100,7 @@ const _: () = {
0u64 => _serde::__private::Ok(__Field::__field0),
1u64 => _serde::__private::Ok(__Field::__field1),
2u64 => _serde::__private::Ok(__Field::__field2),
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 3",
)),
_ => _serde::__private::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(
@@ -387,10 +384,7 @@ const _: () = {
0u64 => _serde::__private::Ok(__Field::__field0),
1u64 => _serde::__private::Ok(__Field::__field1),
2u64 => _serde::__private::Ok(__Field::__field2),
_ => _serde::__private::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 3",
)),
_ => _serde::__private::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(
+168
View File
@@ -2637,3 +2637,171 @@ fn test_flatten_any_after_flatten_struct() {
],
);
}
#[test]
fn test_expecting_message() {
#[derive(Deserialize, PartialEq, Debug)]
#[serde(expecting = "something strange...")]
struct Unit;
#[derive(Deserialize)]
#[serde(expecting = "something strange...")]
struct Newtype(bool);
#[derive(Deserialize)]
#[serde(expecting = "something strange...")]
struct Tuple(u32, bool);
#[derive(Deserialize)]
#[serde(expecting = "something strange...")]
struct Struct {
question: String,
answer: u32,
}
assert_de_tokens_error::<Unit>(
&[Token::Str("Unit")],
r#"invalid type: string "Unit", expected something strange..."#,
);
assert_de_tokens_error::<Newtype>(
&[Token::Str("Newtype")],
r#"invalid type: string "Newtype", expected something strange..."#,
);
assert_de_tokens_error::<Tuple>(
&[Token::Str("Tuple")],
r#"invalid type: string "Tuple", expected something strange..."#,
);
assert_de_tokens_error::<Struct>(
&[Token::Str("Struct")],
r#"invalid type: string "Struct", expected something strange..."#,
);
}
#[test]
fn test_expecting_message_externally_tagged_enum() {
#[derive(Deserialize)]
#[serde(expecting = "something strange...")]
enum Enum {
ExternallyTagged,
}
assert_de_tokens_error::<Enum>(
&[Token::Str("ExternallyTagged")],
r#"invalid type: string "ExternallyTagged", expected something strange..."#,
);
// Check that #[serde(expecting = "...")] doesn't affect variant identifier error message
assert_de_tokens_error::<Enum>(
&[Token::Enum { name: "Enum" }, Token::Unit],
r#"invalid type: unit value, expected variant identifier"#,
);
}
#[test]
fn test_expecting_message_internally_tagged_enum() {
#[derive(Deserialize)]
#[serde(tag = "tag")]
#[serde(expecting = "something strange...")]
enum Enum {
InternallyTagged,
}
assert_de_tokens_error::<Enum>(
&[Token::Str("InternallyTagged")],
r#"invalid type: string "InternallyTagged", expected something strange..."#,
);
// Check that #[serde(expecting = "...")] doesn't affect variant identifier error message
assert_de_tokens_error::<Enum>(
&[Token::Map { len: None }, Token::Str("tag"), Token::Unit],
r#"invalid type: unit value, expected variant identifier"#,
);
}
#[test]
fn test_expecting_message_adjacently_tagged_enum() {
#[derive(Deserialize)]
#[serde(tag = "tag", content = "content")]
#[serde(expecting = "something strange...")]
enum Enum {
AdjacentlyTagged,
}
assert_de_tokens_error::<Enum>(
&[Token::Str("AdjacentlyTagged")],
r#"invalid type: string "AdjacentlyTagged", expected something strange..."#,
);
assert_de_tokens_error::<Enum>(
&[Token::Map { len: None }, Token::Unit],
r#"invalid type: unit value, expected "tag", "content", or other ignored fields"#,
);
// Check that #[serde(expecting = "...")] doesn't affect variant identifier error message
assert_de_tokens_error::<Enum>(
&[Token::Map { len: None }, Token::Str("tag"), Token::Unit],
r#"invalid type: unit value, expected variant identifier"#,
);
}
#[test]
fn test_expecting_message_untagged_tagged_enum() {
#[derive(Deserialize)]
#[serde(untagged)]
#[serde(expecting = "something strange...")]
enum Enum {
Untagged,
}
assert_de_tokens_error::<Enum>(&[Token::Str("Untagged")], r#"something strange..."#);
}
#[test]
fn test_expecting_message_identifier_enum() {
#[derive(Deserialize)]
#[serde(field_identifier)]
#[serde(expecting = "something strange...")]
enum FieldEnum {
Field,
}
#[derive(Deserialize)]
#[serde(variant_identifier)]
#[serde(expecting = "something strange...")]
enum VariantEnum {
Variant,
}
assert_de_tokens_error::<FieldEnum>(
&[Token::Unit],
r#"invalid type: unit value, expected something strange..."#,
);
assert_de_tokens_error::<FieldEnum>(
&[
Token::Enum { name: "FieldEnum" },
Token::Str("Unknown"),
Token::None,
],
r#"invalid type: map, expected something strange..."#,
);
assert_de_tokens_error::<VariantEnum>(
&[Token::Unit],
r#"invalid type: unit value, expected something strange..."#,
);
assert_de_tokens_error::<VariantEnum>(
&[
Token::Enum {
name: "VariantEnum",
},
Token::Str("Unknown"),
Token::None,
],
r#"invalid type: map, expected something strange..."#,
);
}
+24
View File
@@ -90,6 +90,30 @@ fn test_struct() {
);
}
#[test]
fn test_field_identifier() {
#[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier)]
enum FieldStr<'a> {
#[serde(borrow)]
Str(&'a str),
}
assert_de_tokens(&FieldStr::Str("value"), &[Token::BorrowedStr("value")]);
#[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier)]
enum FieldBytes<'a> {
#[serde(borrow)]
Bytes(&'a [u8]),
}
assert_de_tokens(
&FieldBytes::Bytes(b"value"),
&[Token::BorrowedBytes(b"value")],
);
}
#[test]
fn test_cow() {
#[derive(Deserialize)]
+162
View File
@@ -622,6 +622,24 @@ declare_tests! {
Token::I32(2),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Map { len: Some(3) },
Token::U8(0),
Token::I32(1),
Token::U8(1),
Token::I32(2),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Map { len: Some(3) },
Token::U16(0),
Token::I32(1),
Token::U16(1),
Token::I32(2),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Map { len: Some(3) },
Token::U32(0),
@@ -631,6 +649,34 @@ declare_tests! {
Token::I32(2),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Map { len: Some(3) },
Token::U64(0),
Token::I32(1),
Token::U64(1),
Token::I32(2),
Token::MapEnd,
],
// Mixed key types
Struct { a: 1, b: 2, c: 0 } => &[
Token::Map { len: Some(3) },
Token::U8(0),
Token::I32(1),
Token::U64(1),
Token::I32(2),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Map { len: Some(3) },
Token::U8(0),
Token::I32(1),
Token::Str("b"),
Token::I32(2),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Struct { name: "Struct", len: 2 },
Token::Str("a"),
@@ -647,6 +693,46 @@ declare_tests! {
Token::SeqEnd,
],
}
test_struct_borrowed_keys {
Struct { a: 1, b: 2, c: 0 } => &[
Token::Map { len: Some(3) },
Token::BorrowedStr("a"),
Token::I32(1),
Token::BorrowedStr("b"),
Token::I32(2),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Struct { name: "Struct", len: 2 },
Token::BorrowedStr("a"),
Token::I32(1),
Token::BorrowedStr("b"),
Token::I32(2),
Token::StructEnd,
],
}
test_struct_owned_keys {
Struct { a: 1, b: 2, c: 0 } => &[
Token::Map { len: Some(3) },
Token::String("a"),
Token::I32(1),
Token::String("b"),
Token::I32(2),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Struct { name: "Struct", len: 2 },
Token::String("a"),
Token::I32(1),
Token::String("b"),
Token::I32(2),
Token::StructEnd,
],
}
test_struct_with_skip {
Struct { a: 1, b: 2, c: 0 } => &[
Token::Map { len: Some(3) },
@@ -663,6 +749,21 @@ declare_tests! {
Token::I32(4),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Map { len: Some(3) },
Token::U8(0),
Token::I32(1),
Token::U16(1),
Token::I32(2),
Token::U32(2),
Token::I32(3),
Token::U64(3),
Token::I32(4),
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Struct { name: "Struct", len: 2 },
Token::Str("a"),
@@ -780,6 +881,26 @@ declare_tests! {
Token::Str("Unit"),
Token::Unit,
],
EnumOther::Unit => &[
Token::Enum { name: "EnumOther" },
Token::U8(0),
Token::Unit,
],
EnumOther::Unit => &[
Token::Enum { name: "EnumOther" },
Token::U16(0),
Token::Unit,
],
EnumOther::Unit => &[
Token::Enum { name: "EnumOther" },
Token::U32(0),
Token::Unit,
],
EnumOther::Unit => &[
Token::Enum { name: "EnumOther" },
Token::U64(0),
Token::Unit,
],
}
test_enum_other {
EnumOther::Other => &[
@@ -787,6 +908,26 @@ declare_tests! {
Token::Str("Foo"),
Token::Unit,
],
EnumOther::Other => &[
Token::Enum { name: "EnumOther" },
Token::U8(42),
Token::Unit,
],
EnumOther::Other => &[
Token::Enum { name: "EnumOther" },
Token::U16(42),
Token::Unit,
],
EnumOther::Other => &[
Token::Enum { name: "EnumOther" },
Token::U32(42),
Token::Unit,
],
EnumOther::Other => &[
Token::Enum { name: "EnumOther" },
Token::U64(42),
Token::Unit,
],
}
test_box {
Box::new(0i32) => &[Token::I32(0)],
@@ -1452,4 +1593,25 @@ declare_error_tests! {
],
"invalid value: integer `65536`, expected u16",
}
test_duration_overflow_seq<Duration> {
&[
Token::Seq { len: Some(2) },
Token::U64(u64::max_value()),
Token::U32(1_000_000_000),
Token::SeqEnd,
],
"overflow deserializing Duration",
}
test_duration_overflow_struct<Duration> {
&[
Token::Struct { name: "Duration", len: 2 },
Token::Str("secs"),
Token::U64(u64::max_value()),
Token::Str("nanos"),
Token::U32(1_000_000_000),
Token::StructEnd,
],
"overflow deserializing Duration",
}
}
+27
View File
@@ -7,6 +7,7 @@
#![allow(
unknown_lints,
mixed_script_confusables,
clippy::ptr_arg,
clippy::trivially_copy_pass_by_ref
)]
@@ -723,6 +724,24 @@ fn test_gen() {
}
deriving!(&'a str);
macro_rules! mac {
($($tt:tt)*) => {
$($tt)*
};
}
#[derive(Deserialize)]
struct BorrowLifetimeInsideMacro<'a> {
#[serde(borrow = "'a")]
f: mac!(Cow<'a, str>),
}
#[derive(Serialize)]
struct Struct {
#[serde(serialize_with = "vec_first_element")]
vec: Vec<Self>,
}
}
//////////////////////////////////////////////////////////////////////////
@@ -796,3 +815,11 @@ where
pub fn is_zero(n: &u8) -> bool {
*n == 0
}
fn vec_first_element<T, S>(vec: &Vec<T>, serializer: S) -> StdResult<S::Ok, S::Error>
where
T: Serialize,
S: Serializer,
{
vec.first().serialize(serializer)
}
+13
View File
@@ -1,3 +1,4 @@
//! Tests for `#[serde(field_identifier)]` and `#[serde(variant_identifier)]`
use serde::Deserialize;
use serde_test::{assert_de_tokens, Token};
@@ -27,6 +28,10 @@ fn test_field_identifier() {
Bbb,
}
assert_de_tokens(&F::Aaa, &[Token::U8(0)]);
assert_de_tokens(&F::Aaa, &[Token::U16(0)]);
assert_de_tokens(&F::Aaa, &[Token::U32(0)]);
assert_de_tokens(&F::Aaa, &[Token::U64(0)]);
assert_de_tokens(&F::Aaa, &[Token::Str("aaa")]);
assert_de_tokens(&F::Aaa, &[Token::Bytes(b"aaa")]);
}
@@ -42,6 +47,10 @@ fn test_unit_fallthrough() {
Other,
}
assert_de_tokens(&F::Other, &[Token::U8(42)]);
assert_de_tokens(&F::Other, &[Token::U16(42)]);
assert_de_tokens(&F::Other, &[Token::U32(42)]);
assert_de_tokens(&F::Other, &[Token::U64(42)]);
assert_de_tokens(&F::Other, &[Token::Str("x")]);
}
@@ -68,5 +77,9 @@ fn test_newtype_fallthrough_generic() {
Other(T),
}
assert_de_tokens(&F::Other(42u8), &[Token::U8(42)]);
assert_de_tokens(&F::Other(42u16), &[Token::U16(42)]);
assert_de_tokens(&F::Other(42u32), &[Token::U32(42)]);
assert_de_tokens(&F::Other(42u64), &[Token::U64(42)]);
assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]);
}
+86
View File
@@ -0,0 +1,86 @@
use serde::{Deserialize, Serialize};
#[test]
fn test_self() {
pub trait Trait {
type Assoc;
}
#[derive(Deserialize, Serialize)]
pub struct Generics<T: Trait<Assoc = Self>>
where
Self: Trait<Assoc = Self>,
<Self as Trait>::Assoc: Sized,
{
_f: T,
}
impl<T: Trait<Assoc = Self>> Trait for Generics<T> {
type Assoc = Self;
}
#[derive(Deserialize, Serialize)]
pub struct Struct {
_f1: Box<Self>,
_f2: Box<<Self as Trait>::Assoc>,
_f4: [(); Self::ASSOC],
_f5: [(); Self::assoc()],
}
impl Struct {
const ASSOC: usize = 1;
const fn assoc() -> usize {
0
}
}
impl Trait for Struct {
type Assoc = Self;
}
#[derive(Deserialize, Serialize)]
struct Tuple(
Box<Self>,
Box<<Self as Trait>::Assoc>,
[(); Self::ASSOC],
[(); Self::assoc()],
);
impl Tuple {
const ASSOC: usize = 1;
const fn assoc() -> usize {
0
}
}
impl Trait for Tuple {
type Assoc = Self;
}
#[derive(Deserialize, Serialize)]
enum Enum {
Struct {
_f1: Box<Self>,
_f2: Box<<Self as Trait>::Assoc>,
_f4: [(); Self::ASSOC],
_f5: [(); Self::assoc()],
},
Tuple(
Box<Self>,
Box<<Self as Trait>::Assoc>,
[(); Self::ASSOC],
[(); Self::assoc()],
),
}
impl Enum {
const ASSOC: usize = 1;
const fn assoc() -> usize {
0
}
}
impl Trait for Enum {
type Assoc = Self;
}
}
@@ -1,4 +1,4 @@
error: unknown rename rule for #[serde(rename_all = "abc")]
error: unknown rename rule `rename_all = "abc"`, expected one of "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE"
--> $DIR/container_unknown_rename_rule.rs:4:22
|
4 | #[serde(rename_all = "abc")]
@@ -1,4 +1,4 @@
error: unknown rename rule for #[serde(rename_all = "abc")]
error: unknown rename rule `rename_all = "abc"`, expected one of "lowercase", "UPPERCASE", "PascalCase", "camelCase", "snake_case", "SCREAMING_SNAKE_CASE", "kebab-case", "SCREAMING-KEBAB-CASE"
--> $DIR/variant_unknown_rename_rule.rs:5:26
|
5 | #[serde(rename_all = "abc")]