Compare commits

...

164 Commits

Author SHA1 Message Date
David Tolnay 7c04c98e0e Release 1.0.36 2018-03-27 11:35:45 +02:00
David Tolnay a2fa4c2570 Merge pull request #1196 from serde-rs/self
Special case remote = "Self"
2018-03-27 11:12:04 +02:00
David Tolnay 42430902e2 Special case remote = "Self" 2018-03-27 10:56:05 +02:00
David Tolnay 23e2e92237 Release 1.0.35 2018-03-25 12:59:02 +02:00
David Tolnay 273b2c11c6 Keep using deprecated AsciiExt on old compilers 2018-03-25 12:45:31 +02:00
David Tolnay c1602a4d76 Deserialize map in place cannot have flatten attributes 2018-03-25 12:42:36 +02:00
David Tolnay c23be3f855 Revert flatten change in deserialize in place 2018-03-25 12:39:20 +02:00
David Tolnay 5c9c97c0ce Remove test that fails to parse flatten attribute 2018-03-25 12:33:50 +02:00
David Tolnay e5ed440136 Always check flatten assertions 2018-03-25 12:32:06 +02:00
David Tolnay d45ca2f5e4 Re-export NonZero* types from ::lib 2018-03-25 12:30:35 +02:00
David Tolnay d7f9f8209d Indicate that NonZero<T> is deprecated 2018-03-25 12:26:06 +02:00
David Tolnay 4a2612ecff Merge pull request #1191 from SimonSapin/nonzero
impl Serialize and Deserialize for std::num::NonZero*
2018-03-25 03:24:51 -07:00
Simon Sapin 05b22a06d7 impl Serialize and Deserialize for std::num::NonZero*
… gated on the `unstable` Cargo feature.

These are new standard library types.
2018-03-25 12:23:55 +02:00
David Tolnay 3145bcc46e Merge pull request 1159 from niklasad1/patch-1 2018-03-24 19:42:14 +01:00
David Tolnay 2b18b57d84 Release 1.0.34 2018-03-22 15:06:21 -07:00
David Tolnay 5520202262 Merge pull request #1179 from mitsuhiko/feature/flatten
Support for Flattening
2018-03-22 14:14:23 -07:00
Armin Ronacher 3d647f4063 Fixed a compilefail test for flatten on enums 2018-03-20 23:26:22 +01:00
Armin Ronacher 0fde3c2ee8 Fix a warning caused by no-default-features 2018-03-20 23:06:55 +01:00
Armin Ronacher 27f935f036 Correctly serialize newtype variants for flatten 2018-03-20 23:05:05 +01:00
Armin Ronacher 99614c7266 Added flatten on enum compile fail test 2018-03-20 22:15:47 +01:00
Armin Ronacher bb2ecb3bc4 Added compilefail tests for flatten conflicts 2018-03-20 22:04:12 +01:00
Armin Ronacher 96393bfcc7 Added checks for flatten attribute 2018-03-20 21:48:25 +01:00
Armin Ronacher 1d92569abc Added explanatory comment about fetching data from buffered content 2018-03-20 21:24:00 +01:00
Armin Ronacher e4ef087735 Added support for borrowing when flattening 2018-03-20 15:19:36 +01:00
Armin Ronacher 695c3eedcb Do not imply flatten from skip_serialize 2018-03-20 14:45:14 +01:00
Armin Ronacher 50c636a923 Remove now dead as_map detection (can be cattrs.has_flatten) 2018-03-20 13:43:23 +01:00
Armin Ronacher 5b884b5bf9 Added some missing UFCs 2018-03-20 13:38:22 +01:00
Armin Ronacher 8637dda60f Refactored a test 2018-03-20 13:38:08 +01:00
Armin Ronacher abeea89147 Fully qualify some calls in generated code and fix a bad comment 2018-03-20 13:35:16 +01:00
Armin Ronacher 6e324e887d Some refactoring to use a bit less unwrap() 2018-03-20 13:20:56 +01:00
Armin Ronacher 7c596c7136 Remove unnecessary as_str 2018-03-20 13:11:17 +01:00
Armin Ronacher f02dbf381b Added non string key support for flattening 2018-03-19 00:57:58 +01:00
Armin Ronacher 7cf184624a Use more consistent error messages for bad flattening 2018-03-18 23:46:28 +01:00
Armin Ronacher c5a3128492 Added a more complex flattening test 2018-03-18 23:01:13 +01:00
Armin Ronacher 205f606962 Various clippy fixes 2018-03-18 22:59:27 +01:00
Armin Ronacher ad40f976db Switch to using Content keys internally for flattening to later support arbitrary keys 2018-03-18 21:07:08 +01:00
Armin Ronacher 58d52e784b Remove #[serde(repr = "map")] 2018-03-18 18:30:46 +01:00
Armin Ronacher d44f12907b Do not emit an in-place deserialization path for struct as map 2018-03-18 18:27:35 +01:00
Armin Ronacher 61b167be9a Attempted support for in_place deserialization for structs as map 2018-03-18 18:22:06 +01:00
Armin Ronacher f1af2dc5ab Added support for newtype variant serialization 2018-03-18 13:10:54 +01:00
Armin Ronacher ebc61baab2 Added newtype struct support for flattening 2018-03-18 13:02:00 +01:00
Armin Ronacher ffcde25b6e Fixed some clippy warnings 2018-03-17 00:49:00 +01:00
Armin Ronacher 2f57cecf13 format! -> format_args! for an error message 2018-03-16 23:38:50 +01:00
Armin Ronacher bfdcbae9db Fixed an unused import error 2018-03-16 23:30:55 +01:00
Armin Ronacher ca41e16e92 Added some missing conditionals for feature compilation 2018-03-16 23:20:14 +01:00
Armin Ronacher 352fe7b451 Removed an unused field that was left over from a merge conflict 2018-03-16 23:07:31 +01:00
Armin Ronacher 49e302d17d Improved error message for flattening on unsupported types 2018-03-16 23:05:48 +01:00
Armin Ronacher b8602a7e43 Added test for tag/content enum flattening 2018-03-16 23:05:48 +01:00
Armin Ronacher a8c8c2028e Added support for struct variant enum serialization 2018-03-16 23:05:48 +01:00
Armin Ronacher d1833c5602 Added support for basic enums in flatten 2018-03-16 23:05:48 +01:00
Armin Ronacher b4ef7ac323 Updated tests for flatten 2018-03-16 23:05:48 +01:00
Armin Ronacher ebf80ac965 Implement deserialization support for flatten 2018-03-16 23:05:48 +01:00
Armin Ronacher 112dfd7428 Correctly suppress the end() call for flattened serialization 2018-03-16 23:05:48 +01:00
Armin Ronacher b692923321 Non working changes to the flatten serializer 2018-03-16 23:05:48 +01:00
Armin Ronacher 9e8cda4c37 Added basic not fully working FlatMapSerializer 2018-03-16 23:05:48 +01:00
Jan Michael Auer 5457394f5b Fixed various issues with combinding flatten and deny_unknown_fields 2018-03-16 23:05:48 +01:00
Jan Michael Auer 6627540dd6 Added support basic deserialization in derive 2018-03-16 23:05:48 +01:00
Jan Michael Auer 5ae06bba49 Store flatten flag in container attributes 2018-03-16 23:05:47 +01:00
Jan Michael Auer 571bb8caed Derive serialization for serde(flatten) 2018-03-16 23:05:47 +01:00
Jan Michael Auer 299cd2dbd0 Replace unknown_fields_into with serde(flatten) 2018-03-16 23:05:47 +01:00
Armin Ronacher 583c0d8d14 Make proc-macro2/nightly happy 2018-03-16 23:05:22 +01:00
Armin Ronacher 07d07347b3 Make clippy happy 2018-03-16 23:05:22 +01:00
Armin Ronacher 77b07f3fbf Added tests for unknown_fields_into 2018-03-16 23:05:22 +01:00
Armin Ronacher 1bd2c6129c Explicitly pass value requirements for the capture path 2018-03-16 23:05:22 +01:00
Armin Ronacher 39413c8ce7 Implement deserializer for map mode and collection fields 2018-03-16 23:05:22 +01:00
Armin Ronacher b4dbae250b Added support for serialization of structs as maps 2018-03-16 23:05:22 +01:00
Armin Ronacher 5a91ac5ba5 Initial work on supporting structs as map with unknown field collection 2018-03-16 23:05:22 +01:00
David Tolnay 7ad836e6a9 Release 1.0.33 2018-03-15 10:03:42 -07:00
David Tolnay 72ecb9064c Fix parsing of qself in paths in attributes 2018-03-15 10:02:40 -07:00
David Tolnay 23c6eb3b40 Release 1.0.32 2018-03-13 11:31:26 -07:00
David Tolnay b8c9a66d75 Release 1.0.31 2018-03-13 10:18:35 -07:00
David Tolnay 56b2e39dda Fix panic when a reference has unspecified lifetime
This will fail later in compilation anyway, but serde_derive needs to
not crash before then.

    #[derive(Deserialize)]
    struct A {
        field: &str,
    }

    error[E0106]: missing lifetime specifier
      --> src/main.rs
       |
       |     field: &str,
       |            ^ expected lifetime parameter
2018-03-13 09:56:38 -07:00
David Tolnay 5bc805329e Drop impl should only panic if not already panicking 2018-03-13 09:42:07 -07:00
David Tolnay 69dd3215f4 Release 1.0.30 2018-03-12 11:44:50 -07:00
David Tolnay a7a7a31809 Merge pull request #1175 from daboross/fix-borrowed-cow-bytes
Fix borrowed Cow<'_, [u8]> deserializing as str.
2018-03-12 11:44:14 -07:00
David Ross af9996aa9a Fix borrowed Cow<'_, [u8]> deserializing as str.
This changes the deserialize implementation for a borrowed Cow<[u8]>
to specifically request a byte slice, rather than a borrowed string.

The old behavior breaks any program which relies on data being
deserialized the same way as it was serialized and uses Cow<[u8]>.
In serde_json, it just wouldn't deserialize. In bincode, it
deserialized normally unless the bytes were invalid UTF8.

Fixes https://github.com/TyOverby/bincode/issues/231.
2018-03-12 11:26:11 -07:00
David Tolnay 0d4d47c398 Release 1.0.29 2018-03-09 00:24:08 -08:00
David Tolnay 30361ac6d0 Clean up workaround that required too many parentheses
The issue has been fixed in the compiler and these extra call site parentheses
are no longer required.
2018-03-09 00:22:27 -08:00
David Tolnay 3f75239bfb Release 1.0.28 2018-03-08 11:39:32 -08:00
David Tolnay 8dd5605a40 Merge pull request #1170 from H2CO3/disallow_internal_tag_conflict
Disallow variant field names to conflict with tag of internally-tagged enum
2018-03-08 09:34:27 -08:00
David Tolnay f288a41768 Test the new errors on conflicting enum tags 2018-03-08 09:31:25 -08:00
Árpád Goretity f4b78e202a add a check for conflicting adjacent tags as well 2018-03-08 09:57:05 +01:00
Árpád Goretity 0ddebe0317 More descriptive function name; add doc comment to function 2018-03-08 01:05:19 +01:00
Árpád Goretity 9fc526b788 be more explicit in match for future-proofing code via exhaustiveness check 2018-03-08 00:53:56 +01:00
Árpád Goretity a799ea171c Disallow variant field names to conflict with tag of internally-tagged enum 2018-03-08 00:43:35 +01:00
David Tolnay d6f07f2f47 Ignore redundant_field_names lint 2018-02-27 11:13:26 -08:00
niklasad1 f9946ee0ca add some comments about alloc in no_std 2018-02-17 10:03:21 +01:00
Niklas Adolfsson a164f52315 Update README.md
Add some information about ```no_std``` because it was not obvious to me
2018-02-16 19:59:28 +01:00
David Tolnay 8bba8447ef Whitelist some new clippy lints 2018-02-05 10:27:04 -08:00
David Tolnay 9db784bccd Ignore decimal_literal_representation in test suite 2018-01-29 21:52:21 -08:00
David Tolnay 9317bc5afa Address clippy lints in serde_derive_internals 2018-01-26 00:22:38 -08:00
David Tolnay a185df1e77 Ignore decimal_literal_representation lint
The number 4096 is used to cap the size of collections that we preallocate.

    cmp::min(hint.unwrap_or(0), 4096)

I find this number more understandable than 0x1000.
2018-01-26 00:19:26 -08:00
David Tolnay 1bdf5ecec4 Ignore unused_parens warning on the proc macro workaround 2018-01-21 17:54:06 -08:00
David Tolnay 59017aa19b Follow clippy's replace_consts lint 2018-01-15 17:40:32 -08:00
David Tolnay 6b4625dcbb Ignore warning in no_std test 2018-01-13 14:43:34 -08:00
David Tolnay 6e01f220b1 Ignore clippy flagging our workaround 2018-01-13 14:28:12 -08:00
David Tolnay 64573319f9 Meaningful spans when invoking deserializer trait methods 2018-01-10 20:59:48 -08:00
David Tolnay 3d64df6e87 Meaningful span for attrs parsed from string literal 2018-01-10 19:59:49 -08:00
David Tolnay cc2558b0dc Meaningful spans when invoking serializer trait methods 2018-01-10 19:22:07 -08:00
David Tolnay 5c41661bce Merge pull request #1140 from serde-rs/hygiene
Hygiene fixes
2018-01-09 22:39:23 -08:00
David Tolnay dd6914a203 Build the test suite in CI using proc-macro2/nightly 2018-01-09 22:23:19 -08:00
David Tolnay 63623eb3b3 Hygiene fixes 2018-01-09 22:22:08 -08:00
David Tolnay ddc4b50d4d Use call_site in 'with' attribute 2018-01-09 20:34:29 -08:00
David Tolnay b313f947dc Use call_site as the span of unnamed member access 2018-01-09 20:28:23 -08:00
David Tolnay 16bc9fb99e Address clippy lints in serde_derive 2018-01-09 19:40:34 -08:00
David Tolnay 34eaab00f7 Address clippy lints in serde_derive_internals 2018-01-09 19:40:33 -08:00
David Tolnay 6024e717fb Merge pull request #1138 from serde-rs/syn
Update to syn 0.12
2018-01-09 19:23:19 -08:00
David Tolnay ef4dd6c0ec Update to syn 0.12 2018-01-09 19:05:08 -08:00
David Tolnay f7ed967db1 Merge pull request #1135 from mcgoo/appveyor-tls
get rustup-init with curl to avoid tls failures
2018-01-04 20:55:53 -08:00
mcgoo 613e46b0ee get rustup-init with curl to avoid tls failures 2018-01-04 22:04:16 -06:00
David Tolnay b2d2e96267 Merge pull request #1133 from martinlindhe/master
fix some typos
2018-01-03 07:44:40 -08:00
Martin Lindhe ae0373643c fix some typos 2018-01-03 15:16:45 +01:00
David Tolnay 7aeabddd2f Release 1.0.27 2017-12-30 22:19:41 -05:00
David Tolnay 9df8f5ecc0 Merge pull request #1132 from Lireer/uppercase
Add UPPERCASE to rename_all
2017-12-30 22:18:20 -05:00
Carl Scherer c4fad2883b Add UPPERCASE to rename_all 2017-12-31 03:12:00 +01:00
David Tolnay 9cfcd78c87 Release 1.0.26 2017-12-27 17:33:32 -05:00
David Tolnay 4751627f1c Implement De/Serialize for PhantomData where T: ?Sized 2017-12-27 17:32:49 -05:00
David Tolnay ae59c6b6d2 Release 1.0.25 2017-12-23 23:33:59 -05:00
David Tolnay 4973d7a62d Suppress errors on rustfmt line overflow
Some of the serde_derive lines inside of quote!(...) are too long. Rustfmt
cannot fix these. Will need to follow up.
2017-12-23 20:27:56 -08:00
David Tolnay ed6a1de311 Auto format attributes on their own line 2017-12-23 20:24:57 -08:00
David Tolnay ab234be025 The rustfmt rfc style is now the default 2017-12-23 20:21:52 -08:00
David Tolnay ee75e6c0e9 Format with rustfmt-nightly 0.3.4 2017-12-23 20:17:52 -08:00
David Tolnay c2b390fe63 Merge pull request #1124 from serde-rs/in-place
Rename deserialize_from to deserialize_in_place
2017-12-23 19:56:29 -08:00
David Tolnay 56d5d7f761 Rename deserialize_from to deserialize_in_place 2017-12-17 10:46:44 -08:00
David Tolnay 0b89bc920e Merge pull request #1094 from Gankro/deserialize_from
Add and derive deserialize_from
2017-12-11 21:29:15 -08:00
David Tolnay 0dac13e4db Resolve conflict with pr 1115 2017-12-11 20:59:54 -08:00
David Tolnay 0c2e91f28a Merge branch serde-rs/master into Gankro/deserialize_from 2017-12-11 20:49:23 -08:00
David Tolnay 13e7bee0e6 Eliminate need for unwrap in deserialize_from_seq 2017-12-11 18:13:13 -08:00
David Tolnay 65104aca9c Remove need for allow(unreachable_code) 2017-12-11 17:55:23 -08:00
David Tolnay 9360094ba7 Revert main_body naming change
The naming here isn't great but no need to change it in this PR.
2017-12-10 23:19:31 -08:00
David Tolnay 3700779bfa More meaningful names and types for nop_reserve 2017-12-10 23:18:08 -08:00
David Tolnay d9e894911f Move all the deserialize_from derive code behind flag 2017-12-10 23:15:14 -08:00
David Tolnay 85e3ddc2b8 Less indentiation in deserialize_from_body 2017-12-10 23:04:44 -08:00
David Tolnay ccae35d92a Do not emit deserialize_from if every field has deserialize_with 2017-12-10 22:55:28 -08:00
David Tolnay 61ca928325 Can never see getters in a deserialize_from 2017-12-10 22:46:46 -08:00
David Tolnay a93f2ebff0 Enable deserialize_from in the test suite 2017-12-10 22:46:25 -08:00
David Tolnay a45f1ae915 Remove unused dev-dependency of serde_test on deserialize_from 2017-12-10 22:02:11 -08:00
David Tolnay 9641978481 Hide deserialize_from 2017-12-10 21:55:07 -08:00
David Tolnay ffd2017c6f Use the default deserialize_from for Option<T>
The custom one was functionally identical to the default implementation given by
the Deserialize trait. If someone has benchmarks that the custom one performs
better, we can put it back.
2017-12-10 21:27:44 -08:00
David Tolnay b7eb42aa6b Release 1.0.24 2017-12-09 14:43:55 -08:00
David Tolnay 750f8ba299 Clean up trailing whitespace 2017-12-09 14:42:59 -08:00
David Tolnay 49cdef074d Merge pull request #1115 from Binero/master
Solved #1105.
2017-12-08 08:57:31 -08:00
Jeroen Bollen aa86b04714 Adressed concerns raised by @oli-obk.
Specifically:
 - Change identation in `de.rs`.
 - Make `attr::Field` take a `attr::Default` as opposed to the entire parent `attr::Container`.
2017-12-08 15:13:05 +01:00
Jeroen Bollen c887a0b472 Solved #1105.
When a field should be skipped during deserialization, it will not use its own Default implementation
when the container structure has `#[serde(default)]` set.
2017-12-06 21:14:02 +01:00
Alexis Beingessner 34936be574 test deserialize_from 2017-12-04 13:29:03 -05:00
Alexis Beingessner e354dd0c7f Derive deserialize_from for tuples and structs
This adds a new "deserialize_from" feature (default off) that opts into
deriving deserialize_from with #[derive(Deserialize)].
2017-12-04 13:23:26 -05:00
Alexis Beingessner bc221abb04 Augment builtin std/core Deserialize impls to implement deserialize_from 2017-12-04 13:23:26 -05:00
Alexis Beingessner ab5e8780ab Add deserialize_from to Deserialize 2017-12-04 13:23:26 -05:00
David Tolnay 0c34e06e51 Merge pull request #1106 from khuey/inlines
Inline various deserialization helper methods.
2017-12-02 15:57:07 -08:00
Kyle Huey 4a0c4e0c25 Mark size_hint::cautious as inline. 2017-12-01 14:31:52 -08:00
David Tolnay 8c34e0940f Release 1.0.23 2017-11-29 22:26:32 -08:00
David Tolnay eb6bf16a51 Revert "Catch wrong field names length in serde_test"
There are at least two reasonable things to expect the len field to
check: the length of the fields array passed to deserialize_struct, or
the number of field tokens. Even beyond these, in some cases it can be
useful to test deserialization with a bogus len to test how the
Deserialize impl reacts to an incorrect size_hint.

This reverts commit 436cafb0a3 which was
released in serde_test 1.0.20.
2017-11-29 22:21:05 -08:00
David Tolnay 797d049db5 Release 1.0.22 2017-11-29 20:01:43 -08:00
David Tolnay d61a373f12 Merge pull request #1104 from serde-rs/abs
Fix missing absolute paths in deserialize_seq
2017-11-29 19:58:21 -08:00
David Tolnay e0eea551b4 Fix missing absolute paths in deserialize_seq 2017-11-29 19:45:22 -08:00
David Tolnay c650a92bf7 Update to compiletest-rs 0.3 to fix "every suggestion should have at least one span" 2017-11-24 17:12:58 -08:00
David Tolnay f218f4d7bf Release 1.0.21 2017-11-15 22:24:18 -08:00
Alex Shapiro 8c0a2015be Fix error when deserializing untagged enum
Serde's `ContentDeserializer` and `ContentRefDeserializer`
cannot deserialize struct enum variant associated data when
that data is encoded as a sequence. This failure leads to
errors when decoding an enum nested in another untagged
enum. For example:

    #[derive(Serialize, Deserialize)]
    #[serde(untagged)]
    enum Foo {
        A(Bar),
    }

    #[derive(Serialize, Deserialize)]
    enum Bar {
        B{f1: String},
    }

    let data1 = Foo::A(Bar::B{f1: "Hello".into()});
    let bytes = rmp_serde::to_vec(&data1).unwrap();
    let data2 = rmp_serde::from_slice::<Foo>(&bytes).unwrap();

Deserializing fails with the error `Syntax("data did not
match any variant of untagged enum Foo")`, but the
underlying failure occurs when decoding the associated data
of `Bar::B`.

This pull request fixes the issue by allowing
`ContentDeserializer` and `ContentRefDeserializer` to
deserialize sequence-encoded struct enum variant data.
2017-11-15 21:56:33 -08:00
David Tolnay 4773863e3a Release 1.0.20 2017-11-12 10:29:08 -08:00
David Tolnay 80cd9c7617 Merge pull request #1091 from serde-rs/fields-len
Catch wrong field names length in serde_test
2017-11-12 10:28:26 -08:00
David Tolnay 436cafb0a3 Catch wrong field names length in serde_test 2017-11-12 10:16:43 -08:00
David Tolnay 98bb02e9b4 Whitelist use of Debug in serde_test 2017-11-07 10:00:18 -08:00
David Tolnay 142439088c Merge pull request #1086 from Marwes/better_errors
Print the contents of the expected token when a serialize assert fails
2017-11-07 09:53:58 -08:00
Markus Westerlind ce81288235 Print the contents of the expected token when a serialize assert fails
Before
```
expected Token::Str but serialized as Str(“F9168C5E-CEB2-4FAA-B6BF-329BF39FA1E4")
```
After
```
expected Token::Str(“f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4”) but serialized as Str(“F9168C5E-CEB2-4FAA-B6BF-329BF39FA1E4")
```
2017-11-07 14:22:42 +01:00
52 changed files with 5547 additions and 2329 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ environment:
install:
# Install rust, x86_64-pc-windows-msvc host
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
- rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain %APPVEYOR_RUST_CHANNEL%
- set PATH=C:\msys64\usr\bin;%PATH%;C:\Users\appveyor\.cargo\bin
- rustc -vV
+2 -5
View File
@@ -1,5 +1,2 @@
fn_args_layout = "Block"
array_layout = "Block"
where_style = "Rfc"
generics_indent = "Block"
fn_call_style = "Block"
error_on_line_overflow = false
same_line_attributes = false
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.19" # remember to update html_root_url
version = "1.0.36" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"
+3 -3
View File
@@ -10,7 +10,7 @@ use lib::*;
macro_rules! int_to_int {
($dst:ident, $n:ident) => (
if $dst::MIN as i64 <= $n as i64 && $n as i64 <= $dst::MAX as i64 {
if $dst::min_value() as i64 <= $n as i64 && $n as i64 <= $dst::max_value() as i64 {
Some($n as $dst)
} else {
None
@@ -20,7 +20,7 @@ macro_rules! int_to_int {
macro_rules! int_to_uint {
($dst:ident, $n:ident) => (
if 0 <= $n && $n as u64 <= $dst::MAX as u64 {
if 0 <= $n && $n as u64 <= $dst::max_value() as u64 {
Some($n as $dst)
} else {
None
@@ -30,7 +30,7 @@ macro_rules! int_to_uint {
macro_rules! uint_to {
($dst:ident, $n:ident) => (
if $n as u64 <= $dst::MAX as u64 {
if $n as u64 <= $dst::max_value() as u64 {
Some($n as $dst)
} else {
None
+1 -1
View File
@@ -8,7 +8,7 @@
use lib::*;
use de::{Deserialize, Deserializer, Visitor, SeqAccess, MapAccess, Error};
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
/// An efficient way of discarding data from a deserializer.
///
+333 -83
View File
@@ -15,6 +15,7 @@ use de::{Deserialize, Deserializer, EnumAccess, Error, SeqAccess, Unexpected, Va
use de::MapAccess;
use de::from_primitive::FromPrimitive;
use private::de::InPlaceSeed;
#[cfg(any(feature = "std", feature = "alloc"))]
use private::de::size_hint;
@@ -210,6 +211,8 @@ impl<'de> Deserialize<'de> for char {
#[cfg(any(feature = "std", feature = "alloc"))]
struct StringVisitor;
#[cfg(any(feature = "std", feature = "alloc"))]
struct StringInPlaceVisitor<'a>(&'a mut String);
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Visitor<'de> for StringVisitor {
@@ -249,7 +252,66 @@ impl<'de> Visitor<'de> for StringVisitor {
{
match String::from_utf8(v) {
Ok(s) => Ok(s),
Err(e) => Err(Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self),),
Err(e) => Err(Error::invalid_value(
Unexpected::Bytes(&e.into_bytes()),
&self,
)),
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string")
}
fn visit_str<E>(self, v: &str) -> Result<(), E>
where
E: Error,
{
self.0.clear();
self.0.push_str(v);
Ok(())
}
fn visit_string<E>(self, v: String) -> Result<(), E>
where
E: Error,
{
*self.0 = v;
Ok(())
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<(), E>
where
E: Error,
{
match str::from_utf8(v) {
Ok(s) => {
self.0.clear();
self.0.push_str(s);
Ok(())
}
Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)),
}
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<(), E>
where
E: Error,
{
match String::from_utf8(v) {
Ok(s) => {
*self.0 = s;
Ok(())
}
Err(e) => Err(Error::invalid_value(
Unexpected::Bytes(&e.into_bytes()),
&self,
)),
}
}
}
@@ -262,6 +324,13 @@ impl<'de> Deserialize<'de> for String {
{
deserializer.deserialize_string(StringVisitor)
}
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_string(StringInPlaceVisitor(place))
}
}
////////////////////////////////////////////////////////////////////////////////
@@ -465,17 +534,25 @@ where
where
D: Deserializer<'de>,
{
deserializer.deserialize_option(OptionVisitor { marker: PhantomData })
deserializer.deserialize_option(OptionVisitor {
marker: PhantomData,
})
}
// The Some variant's repr is opaque, so we can't play cute tricks with its
// tag to have deserialize_in_place build the content in place unconditionally.
//
// FIXME: investigate whether branching on the old value being Some to
// deserialize_in_place the value is profitable (probably data-dependent?)
}
////////////////////////////////////////////////////////////////////////////////
struct PhantomDataVisitor<T> {
struct PhantomDataVisitor<T: ?Sized> {
marker: PhantomData<T>,
}
impl<'de, T> Visitor<'de> for PhantomDataVisitor<T> {
impl<'de, T: ?Sized> Visitor<'de> for PhantomDataVisitor<T> {
type Value = PhantomData<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
@@ -491,12 +568,14 @@ impl<'de, T> Visitor<'de> for PhantomDataVisitor<T> {
}
}
impl<'de, T> Deserialize<'de> for PhantomData<T> {
impl<'de, T: ?Sized> Deserialize<'de> for PhantomData<T> {
fn deserialize<D>(deserializer: D) -> Result<PhantomData<T>, D::Error>
where
D: Deserializer<'de>,
{
let visitor = PhantomDataVisitor { marker: PhantomData };
let visitor = PhantomDataVisitor {
marker: PhantomData,
};
deserializer.deserialize_unit_struct("PhantomData", visitor)
}
}
@@ -509,7 +588,9 @@ macro_rules! seq_impl {
$ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >,
$access:ident,
$ctor:expr,
$clear:expr,
$with_capacity:expr,
$reserve:expr,
$insert:expr
) => {
impl<'de, T $(, $typaram)*> Deserialize<'de> for $ty<T $(, $typaram)*>
@@ -554,16 +635,59 @@ macro_rules! seq_impl {
let visitor = SeqVisitor { marker: PhantomData };
deserializer.deserialize_seq(visitor)
}
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
struct SeqInPlaceVisitor<'a, T: 'a $(, $typaram: 'a)*>(&'a mut $ty<T $(, $typaram)*>);
impl<'a, 'de, T $(, $typaram)*> Visitor<'de> for SeqInPlaceVisitor<'a, T $(, $typaram)*>
where
T: Deserialize<'de> $(+ $tbound1 $(+ $tbound2)*)*,
$($typaram: $bound1 $(+ $bound2)*,)*
{
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a sequence")
}
#[inline]
fn visit_seq<A>(mut self, mut $access: A) -> Result<(), A::Error>
where
A: SeqAccess<'de>,
{
$clear(&mut self.0);
$reserve(&mut self.0, size_hint::cautious($access.size_hint()));
// FIXME: try to overwrite old values here? (Vec, VecDeque, LinkedList)
while let Some(value) = try!($access.next_element()) {
$insert(&mut self.0, value);
}
Ok(())
}
}
deserializer.deserialize_seq(SeqInPlaceVisitor(place))
}
}
}
}
// Dummy impl of reserve
#[cfg(any(feature = "std", feature = "alloc"))]
fn nop_reserve<T>(_seq: T, _n: usize) {}
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
BinaryHeap<T: Ord>,
seq,
BinaryHeap::new(),
BinaryHeap::clear,
BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())),
BinaryHeap::reserve,
BinaryHeap::push);
#[cfg(any(feature = "std", feature = "alloc"))]
@@ -571,7 +695,9 @@ seq_impl!(
BTreeSet<T: Eq + Ord>,
seq,
BTreeSet::new(),
BTreeSet::clear,
BTreeSet::new(),
nop_reserve,
BTreeSet::insert);
#[cfg(any(feature = "std", feature = "alloc"))]
@@ -579,15 +705,20 @@ seq_impl!(
LinkedList<T>,
seq,
LinkedList::new(),
LinkedList::clear,
LinkedList::new(),
LinkedList::push_back);
nop_reserve,
LinkedList::push_back
);
#[cfg(feature = "std")]
seq_impl!(
HashSet<T: Eq + Hash, S: BuildHasher + Default>,
seq,
HashSet::with_hasher(S::default()),
HashSet::clear,
HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()),
HashSet::reserve,
HashSet::insert);
#[cfg(any(feature = "std", feature = "alloc"))]
@@ -595,26 +726,35 @@ seq_impl!(
Vec<T>,
seq,
Vec::new(),
Vec::clear,
Vec::with_capacity(size_hint::cautious(seq.size_hint())),
Vec::push);
Vec::reserve,
Vec::push
);
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
VecDeque<T>,
seq,
VecDeque::new(),
VecDeque::clear,
VecDeque::with_capacity(size_hint::cautious(seq.size_hint())),
VecDeque::push_back);
VecDeque::reserve,
VecDeque::push_back
);
////////////////////////////////////////////////////////////////////////////////
struct ArrayVisitor<A> {
marker: PhantomData<A>,
}
struct ArrayInPlaceVisitor<'a, A: 'a>(&'a mut A);
impl<A> ArrayVisitor<A> {
fn new() -> Self {
ArrayVisitor { marker: PhantomData }
ArrayVisitor {
marker: PhantomData,
}
}
}
@@ -673,6 +813,35 @@ macro_rules! array_impls {
}
}
impl<'a, 'de, T> Visitor<'de> for ArrayInPlaceVisitor<'a, [T; $len]>
where
T: Deserialize<'de>,
{
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("an array of length ", $len))
}
#[inline]
fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>
where
A: SeqAccess<'de>,
{
let mut fail_idx = None;
for (idx, dest) in self.0[..].iter_mut().enumerate() {
if try!(seq.next_element_seed(InPlaceSeed(dest))).is_none() {
fail_idx = Some(idx);
break;
}
}
if let Some(idx) = fail_idx {
return Err(Error::invalid_length(idx, &self));
}
Ok(())
}
}
impl<'de, T> Deserialize<'de> for [T; $len]
where
T: Deserialize<'de>,
@@ -683,6 +852,13 @@ macro_rules! array_impls {
{
deserializer.deserialize_tuple($len, ArrayVisitor::<[T; $len]>::new())
}
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_tuple($len, ArrayInPlaceVisitor(place))
}
}
)+
}
@@ -726,49 +902,76 @@ array_impls! {
////////////////////////////////////////////////////////////////////////////////
macro_rules! tuple_impls {
($($len:tt $visitor:ident => ($($n:tt $name:ident)+))+) => {
($($len:tt => ($($n:tt $name:ident)+))+) => {
$(
struct $visitor<$($name,)+> {
marker: PhantomData<($($name,)+)>,
}
impl<$($name,)+> $visitor<$($name,)+> {
fn new() -> Self {
$visitor { marker: PhantomData }
}
}
impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for $visitor<$($name,)+> {
type Value = ($($name,)+);
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a tuple of size ", $len))
}
#[inline]
#[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<($($name,)+), A::Error>
where
A: SeqAccess<'de>,
{
$(
let $name = match try!(seq.next_element()) {
Some(value) => value,
None => return Err(Error::invalid_length($n, &self)),
};
)+
Ok(($($name,)+))
}
}
impl<'de, $($name: Deserialize<'de>),+> Deserialize<'de> for ($($name,)+) {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<($($name,)+), D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_tuple($len, $visitor::new())
struct TupleVisitor<$($name,)+> {
marker: PhantomData<($($name,)+)>,
}
impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleVisitor<$($name,)+> {
type Value = ($($name,)+);
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a tuple of size ", $len))
}
#[inline]
#[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<($($name,)+), A::Error>
where
A: SeqAccess<'de>,
{
$(
let $name = match try!(seq.next_element()) {
Some(value) => value,
None => return Err(Error::invalid_length($n, &self)),
};
)+
Ok(($($name,)+))
}
}
deserializer.deserialize_tuple($len, TupleVisitor { marker: PhantomData })
}
#[inline]
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
struct TupleInPlaceVisitor<'a, $($name: 'a,)+>(&'a mut ($($name,)+));
impl<'a, 'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleInPlaceVisitor<'a, $($name,)+> {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("a tuple of size ", $len))
}
#[inline]
#[allow(non_snake_case)]
fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>
where
A: SeqAccess<'de>,
{
$(
if try!(seq.next_element_seed(InPlaceSeed(&mut (self.0).$n))).is_none() {
return Err(Error::invalid_length($n, &self));
}
)+
Ok(())
}
}
deserializer.deserialize_tuple($len, TupleInPlaceVisitor(place))
}
}
)+
@@ -776,22 +979,22 @@ macro_rules! tuple_impls {
}
tuple_impls! {
1 TupleVisitor1 => (0 T0)
2 TupleVisitor2 => (0 T0 1 T1)
3 TupleVisitor3 => (0 T0 1 T1 2 T2)
4 TupleVisitor4 => (0 T0 1 T1 2 T2 3 T3)
5 TupleVisitor5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
6 TupleVisitor6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
7 TupleVisitor7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
8 TupleVisitor8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
9 TupleVisitor9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
10 TupleVisitor10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
11 TupleVisitor11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
12 TupleVisitor12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
13 TupleVisitor13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
14 TupleVisitor14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
15 TupleVisitor15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
16 TupleVisitor16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
1 => (0 T0)
2 => (0 T0 1 T1)
3 => (0 T0 1 T1 2 T2)
4 => (0 T0 1 T1 2 T2 3 T3)
5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
}
////////////////////////////////////////////////////////////////////////////////
@@ -1068,7 +1271,12 @@ impl<'de> Deserialize<'de> for net::SocketAddr {
parse_socket_impl!(net::SocketAddrV4, net::SocketAddrV4::new);
#[cfg(feature = "std")]
parse_socket_impl!(net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(ip, port, 0, 0));
parse_socket_impl!(net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(
ip,
port,
0,
0
));
////////////////////////////////////////////////////////////////////////////////
@@ -1179,7 +1387,9 @@ impl<'de> Visitor<'de> for OsStringVisitor {
match try!(data.variant()) {
(OsStringKind::Unix, v) => v.newtype_variant().map(OsString::from_vec),
(OsStringKind::Windows, _) => Err(Error::custom("cannot deserialize Windows OS string on Unix",),),
(OsStringKind::Windows, _) => Err(Error::custom(
"cannot deserialize Windows OS string on Unix",
)),
}
}
@@ -1191,11 +1401,11 @@ impl<'de> Visitor<'de> for OsStringVisitor {
use std::os::windows::ffi::OsStringExt;
match try!(data.variant()) {
(OsStringKind::Windows, v) => {
v.newtype_variant::<Vec<u16>>()
.map(|vec| OsString::from_wide(&vec))
}
(OsStringKind::Unix, _) => Err(Error::custom("cannot deserialize Unix OS string on Windows",),),
(OsStringKind::Windows, v) => v.newtype_variant::<Vec<u16>>()
.map(|vec| OsString::from_wide(&vec)),
(OsStringKind::Unix, _) => Err(Error::custom(
"cannot deserialize Unix OS string on Windows",
)),
}
}
}
@@ -1521,13 +1731,17 @@ impl<'de> Deserialize<'de> for SystemTime {
match key {
Field::Secs => {
if secs.is_some() {
return Err(<A::Error as Error>::duplicate_field("secs_since_epoch"));
return Err(<A::Error as Error>::duplicate_field(
"secs_since_epoch",
));
}
secs = Some(try!(map.next_value()));
}
Field::Nanos => {
if nanos.is_some() {
return Err(<A::Error as Error>::duplicate_field("nanos_since_epoch"));
return Err(<A::Error as Error>::duplicate_field(
"nanos_since_epoch",
));
}
nanos = Some(try!(map.next_value()));
}
@@ -1691,13 +1905,20 @@ where
}
const FIELDS: &'static [&'static str] = &["start", "end"];
deserializer.deserialize_struct("Range", FIELDS, RangeVisitor { phantom: PhantomData })
deserializer.deserialize_struct(
"Range",
FIELDS,
RangeVisitor {
phantom: PhantomData,
},
)
}
}
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")]
#[allow(deprecated)]
impl<'de, T> Deserialize<'de> for NonZero<T>
where
T: Deserialize<'de> + Zeroable,
@@ -1714,6 +1935,36 @@ where
}
}
macro_rules! nonzero_integers {
( $( $T: ty, )+ ) => {
$(
#[cfg(feature = "unstable")]
impl<'de> Deserialize<'de> for $T {
fn deserialize<D>(deserializer: D) -> Result<$T, D::Error>
where
D: Deserializer<'de>,
{
let value = try!(Deserialize::deserialize(deserializer));
match <$T>::new(value) {
Some(nonzero) => Ok(nonzero),
None => Err(Error::custom("expected a non-zero value")),
}
}
}
)+
};
}
nonzero_integers! {
// Not including signed NonZeroI* since they might be removed
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
// FIXME: https://github.com/serde-rs/serde/issues/1136 NonZeroU128,
NonZeroUsize,
}
////////////////////////////////////////////////////////////////////////////////
impl<'de, T, E> Deserialize<'de> for Result<T, E>
@@ -1756,9 +2007,10 @@ where
match value {
0 => Ok(Field::Ok),
1 => Ok(Field::Err),
_ => {
Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),)
}
_ => Err(Error::invalid_value(
Unexpected::Unsigned(value as u64),
&self,
)),
}
}
@@ -1780,14 +2032,12 @@ where
match value {
b"Ok" => Ok(Field::Ok),
b"Err" => Ok(Field::Err),
_ => {
match str::from_utf8(value) {
Ok(value) => Err(Error::unknown_variant(value, VARIANTS)),
Err(_) => {
Err(Error::invalid_value(Unexpected::Bytes(value), &self))
}
_ => match str::from_utf8(value) {
Ok(value) => Err(Error::unknown_variant(value, VARIANTS)),
Err(_) => {
Err(Error::invalid_value(Unexpected::Bytes(value), &self))
}
}
},
}
}
}
@@ -1831,7 +2081,7 @@ where
#[cfg(feature = "std")]
impl<'de, T> Deserialize<'de> for Wrapping<T>
where
T: Deserialize<'de>
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Wrapping<T>, D::Error>
where
+34 -2
View File
@@ -98,7 +98,8 @@
//! - Path
//! - PathBuf
//! - Range\<T\>
//! - NonZero\<T\> (unstable)
//! - NonZero\<T\> (unstable, deprecated)
//! - num::NonZero* (unstable)
//! - **Net types**:
//! - IpAddr
//! - Ipv4Addr
@@ -504,6 +505,35 @@ pub trait Deserialize<'de>: Sized {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>;
/// Deserializes a value into `self` from the given Deserializer.
///
/// The purpose of this method is to allow the deserializer to reuse
/// resources and avoid copies. As such, if this method returns an error,
/// `self` will be in an indeterminate state where some parts of the struct
/// have been overwritten. Although whatever state that is will be
/// memory-safe.
///
/// This is generally useful when repeatedly deserializing values that
/// are processed one at a time, where the value of `self` doesn't matter
/// when the next deserialization occurs.
///
/// If you manually implement this, your recursive deserializations should
/// use `deserialize_in_place`.
///
/// This method is stable and an official public API, but hidden from the
/// documentation because it is almost never what newbies are looking for.
/// Showing it in rustdoc would cause it to be featured more prominently
/// than it deserves.
#[doc(hidden)]
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
// Default implementation just delegates to `deserialize` impl.
*place = Deserialize::deserialize(deserializer)?;
Ok(())
}
}
/// A data structure that can be deserialized without borrowing any data from
@@ -1078,7 +1108,9 @@ pub trait Deserializer<'de>: Sized {
/// change, as a value serialized in human-readable mode is not required to
/// deserialize from the same data in compact mode.
#[inline]
fn is_human_readable(&self) -> bool { true }
fn is_human_readable(&self) -> bool {
true
}
}
////////////////////////////////////////////////////////////////////////////////
+34 -14
View File
@@ -37,7 +37,7 @@
use lib::*;
use de::{self, IntoDeserializer, Expected, SeqAccess};
use de::{self, Expected, IntoDeserializer, SeqAccess};
use private::de::size_hint;
use ser;
use self::private::{First, Second};
@@ -62,7 +62,9 @@ impl de::Error for Error {
where
T: Display,
{
Error { err: msg.to_string().into_boxed_str() }
Error {
err: msg.to_string().into_boxed_str(),
}
}
#[cfg(not(any(feature = "std", feature = "alloc")))]
@@ -112,7 +114,9 @@ where
type Deserializer = UnitDeserializer<E>;
fn into_deserializer(self) -> UnitDeserializer<E> {
UnitDeserializer { marker: PhantomData }
UnitDeserializer {
marker: PhantomData,
}
}
}
@@ -658,7 +662,10 @@ where
} else {
// First argument is the number of elements in the data, second
// argument is the number of elements expected by the Deserialize.
Err(de::Error::invalid_length(self.count + remaining, &ExpectedInSeq(self.count)),)
Err(de::Error::invalid_length(
self.count + remaining,
&ExpectedInSeq(self.count),
))
}
}
}
@@ -852,7 +859,10 @@ where
} else {
// First argument is the number of elements in the data, second
// argument is the number of elements expected by the Deserialize.
Err(de::Error::invalid_length(self.count + remaining, &ExpectedInMap(self.count)),)
Err(de::Error::invalid_length(
self.count + remaining,
&ExpectedInMap(self.count),
))
}
}
}
@@ -901,11 +911,7 @@ where
Ok(value)
}
fn deserialize_tuple<V>(
self,
len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
@@ -1223,7 +1229,12 @@ mod private {
}
pub fn unit_only<T, E>(t: T) -> (T, UnitOnly<E>) {
(t, UnitOnly { marker: PhantomData })
(
t,
UnitOnly {
marker: PhantomData,
},
)
}
impl<'de, E> de::VariantAccess<'de> for UnitOnly<E>
@@ -1240,14 +1251,20 @@ mod private {
where
T: de::DeserializeSeed<'de>,
{
Err(de::Error::invalid_type(Unexpected::UnitVariant, &"newtype variant"),)
Err(de::Error::invalid_type(
Unexpected::UnitVariant,
&"newtype variant",
))
}
fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
Err(de::Error::invalid_type(Unexpected::UnitVariant, &"tuple variant"),)
Err(de::Error::invalid_type(
Unexpected::UnitVariant,
&"tuple variant",
))
}
fn struct_variant<V>(
@@ -1258,7 +1275,10 @@ mod private {
where
V: de::Visitor<'de>,
{
Err(de::Error::invalid_type(Unexpected::UnitVariant, &"struct variant"),)
Err(de::Error::invalid_type(
Unexpected::UnitVariant,
&"struct variant",
))
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ pub use lib::default::Default;
pub use lib::fmt::{self, Formatter};
pub use lib::marker::PhantomData;
pub use lib::option::Option::{self, None, Some};
pub use lib::result::Result::{self, Ok, Err};
pub use lib::result::Result::{self, Err, Ok};
pub use self::string::from_utf8_lossy;
+18 -21
View File
@@ -79,30 +79,21 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.19")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.36")]
// 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
// discussion of these features please refer to this issue:
//
// https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(nonzero, specialization))]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(
cast_lossless,
const_static_lifetime,
doc_markdown,
linkedlist,
needless_pass_by_value,
type_complexity,
unreadable_literal,
zero_prefixed_literal,
))]
#![cfg_attr(feature = "cargo-clippy",
allow(cast_lossless, const_static_lifetime, doc_markdown, linkedlist,
needless_pass_by_value, redundant_field_names, type_complexity,
unreadable_literal, zero_prefixed_literal))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
// integer and float ser/de requires these sorts of casts
@@ -113,6 +104,7 @@
// simplifies some macros
invalid_upcast_comparisons,
// things are often more readable this way
decimal_literal_representation,
option_unwrap_used,
result_unwrap_used,
shadow_reuse,
@@ -120,12 +112,13 @@
stutter,
use_self,
// not practical
many_single_char_names,
missing_docs_in_private_items,
similar_names,
// alternative is not stable
empty_enum,
use_debug,
))]
// Blacklisted Rust lints.
#![deny(missing_docs, unused_imports)]
@@ -149,8 +142,8 @@ mod lib {
}
pub use self::core::{cmp, iter, mem, ops, slice, str};
pub use self::core::{i8, i16, i32, i64, isize};
pub use self::core::{u8, u16, u32, u64, usize};
pub use self::core::{isize, i16, i32, i64, i8};
pub use self::core::{usize, u16, u32, u64, u8};
pub use self::core::{f32, f64};
pub use self::core::cell::{Cell, RefCell};
@@ -193,9 +186,9 @@ mod lib {
pub use alloc::arc::Arc;
#[cfg(feature = "std")]
pub use std::collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(all(feature = "alloc", not(feature = "std")))]
pub use alloc::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
pub use alloc::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(feature = "std")]
pub use std::{error, net};
@@ -203,9 +196,9 @@ mod lib {
#[cfg(feature = "std")]
pub use std::collections::{HashMap, HashSet};
#[cfg(feature = "std")]
pub use std::ffi::{CString, CStr, OsString, OsStr};
pub use std::ffi::{CStr, CString, OsStr, OsString};
#[cfg(feature = "std")]
pub use std::hash::{Hash, BuildHasher};
pub use std::hash::{BuildHasher, Hash};
#[cfg(feature = "std")]
pub use std::io::Write;
#[cfg(feature = "std")]
@@ -218,7 +211,11 @@ mod lib {
pub use std::sync::{Mutex, RwLock};
#[cfg(feature = "unstable")]
#[allow(deprecated)]
pub use core::nonzero::{NonZero, Zeroable};
#[cfg(feature = "unstable")]
pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize};
}
////////////////////////////////////////////////////////////////////////////////
+341 -106
View File
@@ -8,16 +8,16 @@
use lib::*;
use de::{Deserialize, Deserializer, IntoDeserializer, Error, Visitor};
use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor};
#[cfg(any(feature = "std", feature = "alloc"))]
use de::Unexpected;
use de::{Unexpected, MapAccess};
#[cfg(any(feature = "std", feature = "alloc"))]
pub use self::content::{Content, ContentRefDeserializer, ContentDeserializer,
TaggedContentVisitor, TagOrContentField, TagOrContentFieldVisitor,
TagContentOtherField, TagContentOtherFieldVisitor,
InternallyTaggedUnitVisitor, UntaggedUnitVisitor};
pub use self::content::{Content, ContentDeserializer, ContentRefDeserializer,
InternallyTaggedUnitVisitor, TagContentOtherField,
TagContentOtherFieldVisitor, TagOrContentField, TagOrContentFieldVisitor,
TaggedContentVisitor, UntaggedUnitVisitor, EnumDeserializer};
/// If the missing field is of type `Option<T>` then treat is as `None`,
/// otherwise it is an error.
@@ -120,7 +120,10 @@ where
{
match String::from_utf8(v) {
Ok(s) => Ok(Cow::Owned(s)),
Err(e) => Err(Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self),),
Err(e) => Err(Error::invalid_value(
Unexpected::Bytes(&e.into_bytes()),
&self,
)),
}
}
}
@@ -185,7 +188,7 @@ where
}
}
deserializer.deserialize_str(CowBytesVisitor)
deserializer.deserialize_bytes(CowBytesVisitor)
}
pub mod size_hint {
@@ -198,6 +201,7 @@ pub mod size_hint {
helper(iter.size_hint())
}
#[inline]
pub fn cautious(hint: Option<usize>) -> usize {
cmp::min(hint.unwrap_or(0), 4096)
}
@@ -224,8 +228,8 @@ mod content {
use lib::*;
use de::{self, Deserialize, DeserializeSeed, Deserializer, Visitor, SeqAccess, MapAccess,
EnumAccess, Unexpected};
use de::{self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, MapAccess, SeqAccess,
Unexpected, Visitor};
use super::size_hint;
/// Used from generated code to buffer the contents of the Deserializer when
@@ -265,6 +269,14 @@ mod content {
}
impl<'de> Content<'de> {
pub fn as_str(&self) -> Option<&str> {
match *self {
Content::Str(x) => Some(x),
Content::String(ref x) => Some(x),
_ => None,
}
}
fn unexpected(&self) -> Unexpected {
match *self {
Content::Bool(b) => Unexpected::Bool(b),
@@ -501,7 +513,9 @@ mod content {
where
V: EnumAccess<'de>,
{
Err(de::Error::custom("untagged and internally tagged enums do not support enum input",),)
Err(de::Error::custom(
"untagged and internally tagged enums do not support enum input",
))
}
}
@@ -520,7 +534,10 @@ mod content {
impl<'de> TagOrContentVisitor<'de> {
fn new(name: &'static str) -> Self {
TagOrContentVisitor { name: name, value: PhantomData }
TagOrContentVisitor {
name: name,
value: PhantomData,
}
}
}
@@ -557,7 +574,9 @@ mod content {
where
F: de::Error,
{
ContentVisitor::new().visit_i8(value).map(TagOrContent::Content)
ContentVisitor::new()
.visit_i8(value)
.map(TagOrContent::Content)
}
fn visit_i16<F>(self, value: i16) -> Result<Self::Value, F>
@@ -591,7 +610,9 @@ mod content {
where
F: de::Error,
{
ContentVisitor::new().visit_u8(value).map(TagOrContent::Content)
ContentVisitor::new()
.visit_u8(value)
.map(TagOrContent::Content)
}
fn visit_u16<F>(self, value: u16) -> Result<Self::Value, F>
@@ -730,14 +751,18 @@ mod content {
where
F: de::Error,
{
ContentVisitor::new().visit_unit().map(TagOrContent::Content)
ContentVisitor::new()
.visit_unit()
.map(TagOrContent::Content)
}
fn visit_none<F>(self) -> Result<Self::Value, F>
where
F: de::Error,
{
ContentVisitor::new().visit_none().map(TagOrContent::Content)
ContentVisitor::new()
.visit_none()
.map(TagOrContent::Content)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
@@ -860,8 +885,7 @@ mod content {
{
let mut tag = None;
let mut vec = Vec::with_capacity(size_hint::cautious(map.size_hint()));
while let Some(k) =
try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
while let Some(k) = try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
match k {
TagOrContent::Tag => {
if tag.is_some() {
@@ -877,14 +901,10 @@ mod content {
}
match tag {
None => Err(de::Error::missing_field(self.tag_name)),
Some(tag) => {
Ok(
TaggedContent {
tag: tag,
content: Content::Map(vec),
},
)
}
Some(tag) => Ok(TaggedContent {
tag: tag,
content: Content::Map(vec),
}),
}
}
}
@@ -966,7 +986,11 @@ mod content {
type Value = TagContentOtherField;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "{:?}, {:?}, or other ignored fields", self.tag, self.content)
write!(
formatter,
"{:?}, {:?}, or other ignored fields",
self.tag, self.content
)
}
fn visit_str<E>(self, field: &str) -> Result<Self::Value, E>
@@ -1030,10 +1054,8 @@ mod content {
Ok(value)
}
Content::Map(v) => {
let map = v.into_iter().map(|(k, v)| {
(ContentDeserializer::new(k),
ContentDeserializer::new(v))
});
let map = v.into_iter()
.map(|(k, v)| (ContentDeserializer::new(k), ContentDeserializer::new(v)));
let mut map_visitor = de::value::MapDeserializer::new(map);
let value = try!(visitor.visit_map(&mut map_visitor));
try!(map_visitor.end());
@@ -1080,44 +1102,37 @@ mod content {
let (variant, value) = match iter.next() {
Some(v) => v,
None => {
return Err(
de::Error::invalid_value(
de::Unexpected::Map,
&"map with a single key",
),
);
return Err(de::Error::invalid_value(
de::Unexpected::Map,
&"map with a single key",
));
}
};
// enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() {
return Err(
de::Error::invalid_value(
de::Unexpected::Map,
&"map with a single key",
),
);
return Err(de::Error::invalid_value(
de::Unexpected::Map,
&"map with a single key",
));
}
(variant, Some(value))
}
s @ Content::String(_) | s @ Content::Str(_) => (s, None),
other => {
return Err(de::Error::invalid_type(other.unexpected(), &"string or map"),);
return Err(de::Error::invalid_type(
other.unexpected(),
&"string or map",
));
}
};
visitor.visit_enum(
EnumDeserializer {
variant: variant,
value: value,
err: PhantomData,
},
)
visitor.visit_enum(EnumDeserializer::new(variant, value))
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
@@ -1159,7 +1174,7 @@ mod content {
}
}
struct EnumDeserializer<'de, E>
pub struct EnumDeserializer<'de, E>
where
E: de::Error,
{
@@ -1168,6 +1183,18 @@ mod content {
err: PhantomData<E>,
}
impl<'de, E> EnumDeserializer<'de, E>
where E: de::Error
{
pub fn new(variant: Content<'de>, value: Option<Content<'de>>) -> EnumDeserializer<'de, E> {
EnumDeserializer {
variant: variant,
value: value,
err: PhantomData,
}
}
}
impl<'de, E> de::EnumAccess<'de> for EnumDeserializer<'de, E>
where
E: de::Error,
@@ -1188,7 +1215,7 @@ mod content {
}
}
struct VariantDeserializer<'de, E>
pub struct VariantDeserializer<'de, E>
where
E: de::Error,
{
@@ -1215,9 +1242,10 @@ mod content {
{
match self.value {
Some(value) => seed.deserialize(ContentDeserializer::new(value)),
None => {
Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"newtype variant"),)
}
None => Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
&"newtype variant",
)),
}
}
@@ -1229,8 +1257,14 @@ mod content {
Some(Content::Seq(v)) => {
de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"tuple variant"),),
None => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"tuple variant"),),
Some(other) => Err(de::Error::invalid_type(
other.unexpected(),
&"tuple variant",
)),
None => Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
&"tuple variant",
)),
}
}
@@ -1246,8 +1280,17 @@ mod content {
Some(Content::Map(v)) => {
de::Deserializer::deserialize_any(MapDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"struct variant"),),
_ => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"struct variant"),),
Some(Content::Seq(v)) => {
de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(
other.unexpected(),
&"struct variant",
)),
_ => Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
&"struct variant",
)),
}
}
}
@@ -1315,10 +1358,7 @@ mod content {
T: de::DeserializeSeed<'de>,
{
match self.iter.next() {
Some(value) => {
seed.deserialize(ContentDeserializer::new(value))
.map(Some)
}
Some(value) => seed.deserialize(ContentDeserializer::new(value)).map(Some),
None => Ok(None),
}
}
@@ -1454,12 +1494,12 @@ mod content {
Ok(value)
}
Content::Map(ref v) => {
let map = v.into_iter()
.map(
|&(ref k, ref v)| {
(ContentRefDeserializer::new(k), ContentRefDeserializer::new(v))
},
);
let map = v.into_iter().map(|&(ref k, ref v)| {
(
ContentRefDeserializer::new(k),
ContentRefDeserializer::new(v),
)
});
let mut map_visitor = de::value::MapDeserializer::new(map);
let value = try!(visitor.visit_map(&mut map_visitor));
try!(map_visitor.end());
@@ -1502,38 +1542,35 @@ mod content {
let &(ref variant, ref value) = match iter.next() {
Some(v) => v,
None => {
return Err(
de::Error::invalid_value(
de::Unexpected::Map,
&"map with a single key",
),
);
return Err(de::Error::invalid_value(
de::Unexpected::Map,
&"map with a single key",
));
}
};
// enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() {
return Err(
de::Error::invalid_value(
de::Unexpected::Map,
&"map with a single key",
),
);
return Err(de::Error::invalid_value(
de::Unexpected::Map,
&"map with a single key",
));
}
(variant, Some(value))
}
ref s @ Content::String(_) | ref s @ Content::Str(_) => (s, None),
ref other => {
return Err(de::Error::invalid_type(other.unexpected(), &"string or map"),);
return Err(de::Error::invalid_type(
other.unexpected(),
&"string or map",
));
}
};
visitor.visit_enum(
EnumRefDeserializer {
variant: variant,
value: value,
err: PhantomData,
},
)
visitor.visit_enum(EnumRefDeserializer {
variant: variant,
value: value,
err: PhantomData,
})
}
forward_to_deserialize_any! {
@@ -1609,9 +1646,10 @@ mod content {
{
match self.value {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => {
Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"newtype variant"),)
}
None => Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
&"newtype variant",
)),
}
}
@@ -1623,8 +1661,14 @@ mod content {
Some(&Content::Seq(ref v)) => {
de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"tuple variant"),),
None => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"tuple variant"),),
Some(other) => Err(de::Error::invalid_type(
other.unexpected(),
&"tuple variant",
)),
None => Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
&"tuple variant",
)),
}
}
@@ -1640,8 +1684,17 @@ mod content {
Some(&Content::Map(ref v)) => {
de::Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"struct variant"),),
_ => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"struct variant"),),
Some(&Content::Seq(ref v)) => {
de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(
other.unexpected(),
&"struct variant",
)),
_ => Err(de::Error::invalid_type(
de::Unexpected::UnitVariant,
&"struct variant",
)),
}
}
}
@@ -1709,10 +1762,8 @@ mod content {
T: de::DeserializeSeed<'de>,
{
match self.iter.next() {
Some(value) => {
seed.deserialize(ContentRefDeserializer::new(value))
.map(Some)
}
Some(value) => seed.deserialize(ContentRefDeserializer::new(value))
.map(Some),
None => Ok(None),
}
}
@@ -1757,8 +1808,7 @@ mod content {
match self.iter.next() {
Some(&(ref key, ref value)) => {
self.value = Some(value);
seed.deserialize(ContentRefDeserializer::new(key))
.map(Some)
seed.deserialize(ContentRefDeserializer::new(key)).map(Some)
}
None => Ok(None),
}
@@ -1844,7 +1894,11 @@ mod content {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name)
write!(
formatter,
"unit variant {}::{}",
self.type_name, self.variant_name
)
}
fn visit_seq<S>(self, _: S) -> Result<(), S::Error>
@@ -1884,7 +1938,11 @@ mod content {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name)
write!(
formatter,
"unit variant {}::{}",
self.type_name, self.variant_name
)
}
fn visit_unit<E>(self) -> Result<(), E>
@@ -2002,3 +2060,180 @@ where
map struct enum identifier ignored_any
}
}
/// 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)
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapDeserializer<'a, 'de: 'a, E>(
pub &'a mut Vec<Option<(Content<'de>, Content<'de>)>>,
pub PhantomData<E>
);
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
where E: Error
{
type Error = E;
fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(Error::custom("can only flatten structs and maps"))
}
fn deserialize_enum<V>(
self,
name: &'static str,
variants: &'static [&'static str],
visitor: V
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
for item in self.0.iter_mut() {
// items in the vector are nulled out when used. So we can only use
// an item if it's still filled in and if the field is one we care
// about.
let use_item = match *item {
None => false,
Some((ref c, _)) => c.as_str().map_or(false, |x| variants.contains(&x))
};
if use_item {
let (key, value) = item.take().unwrap();
return visitor.visit_enum(EnumDeserializer::new(
key,
Some(value)
));
}
}
Err(Error::custom(format_args!(
"no variant of enum {} not found in flattened data",
name
)))
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_map(FlatMapAccess::new(self.0.iter_mut(), None))
}
fn deserialize_struct<V>(
self,
_: &'static str,
fields: &'static [&'static str],
visitor: V
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_map(FlatMapAccess::new(self.0.iter_mut(), Some(fields)))
}
fn deserialize_newtype_struct<V>(
self,
_name: &str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct seq tuple tuple_struct identifier
ignored_any
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapAccess<'a, 'de: 'a, E> {
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<Content<'de>>,
fields: Option<&'static [&'static str]>,
_marker: PhantomData<E>,
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> {
fn new(
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
fields: Option<&'static [&'static str]>
) -> FlatMapAccess<'a, 'de, E> {
FlatMapAccess {
iter: iter,
pending_content: None,
fields: fields,
_marker: PhantomData,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
where E: Error
{
type Error = E;
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
while let Some(item) = self.iter.next() {
// items in the vector are nulled out when used. So we can only use
// an item if it's still filled in and if the field is one we care
// about. In case we do not know which fields we want, we take them all.
let use_item = match *item {
None => false,
Some((ref c, _)) => {
c.as_str().map_or(self.fields.is_none(), |key| {
match self.fields {
None => true,
Some(fields) if fields.contains(&key) => true,
_ => false
}
})
}
};
if use_item {
let (key, content) = item.take().unwrap();
self.pending_content = Some(content);
return seed.deserialize(ContentDeserializer::new(key)).map(Some);
}
}
Ok(None)
}
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.pending_content.take() {
Some(value) => seed.deserialize(ContentDeserializer::new(value)),
None => Err(Error::custom("value is missing")),
}
}
}
+394 -96
View File
@@ -8,10 +8,15 @@
use lib::*;
use ser::{self, Serialize, Serializer, SerializeMap, SerializeStruct, Impossible};
use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
#[cfg(any(feature = "std", feature = "alloc"))]
use self::content::{SerializeTupleVariantAsMapValue, SerializeStructVariantAsMapValue};
use self::content::{
SerializeStructVariantAsMapValue,
SerializeTupleVariantAsMapValue,
ContentSerializer,
Content,
};
/// Used to check that serde(getter) attributes return the expected type.
/// Not public API.
@@ -32,15 +37,13 @@ where
S: Serializer,
T: Serialize,
{
value.serialize(
TaggedSerializer {
type_ident: type_ident,
variant_ident: variant_ident,
tag: tag,
variant_name: variant_name,
delegate: serializer,
},
)
value.serialize(TaggedSerializer {
type_ident: type_ident,
variant_ident: variant_ident,
tag: tag,
variant_name: variant_name,
delegate: serializer,
})
}
struct TaggedSerializer<S> {
@@ -60,10 +63,11 @@ enum Unsupported {
ByteArray,
Optional,
Unit,
#[cfg(any(feature = "std", feature = "alloc"))]
UnitStruct,
Sequence,
Tuple,
TupleStruct,
#[cfg(not(any(feature = "std", feature = "alloc")))]
Enum,
}
@@ -78,10 +82,11 @@ impl Display for Unsupported {
Unsupported::ByteArray => formatter.write_str("a byte array"),
Unsupported::Optional => formatter.write_str("an optional"),
Unsupported::Unit => formatter.write_str("unit"),
#[cfg(any(feature = "std", feature = "alloc"))]
Unsupported::UnitStruct => formatter.write_str("unit struct"),
Unsupported::Sequence => formatter.write_str("a sequence"),
Unsupported::Tuple => formatter.write_str("a tuple"),
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
#[cfg(not(any(feature = "std", feature = "alloc")))]
Unsupported::Enum => formatter.write_str("an enum"),
}
}
@@ -92,13 +97,10 @@ where
S: Serializer,
{
fn bad_type(self, what: Unsupported) -> S::Error {
ser::Error::custom(
format_args!(
ser::Error::custom(format_args!(
"cannot serialize tagged newtype variant {}::{} containing {}",
self.type_ident,
self.variant_ident,
what),
)
self.type_ident, self.variant_ident, what
))
}
}
@@ -281,7 +283,11 @@ where
let mut map = try!(self.delegate.serialize_map(Some(2)));
try!(map.serialize_entry(self.tag, self.variant_name));
try!(map.serialize_key(inner_variant));
Ok(SerializeTupleVariantAsMapValue::new(map, inner_variant, len),)
Ok(SerializeTupleVariantAsMapValue::new(
map,
inner_variant,
len,
))
}
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
@@ -324,7 +330,11 @@ where
let mut map = try!(self.delegate.serialize_map(Some(2)));
try!(map.serialize_entry(self.tag, self.variant_name));
try!(map.serialize_key(inner_variant));
Ok(SerializeStructVariantAsMapValue::new(map, inner_variant, len),)
Ok(SerializeStructVariantAsMapValue::new(
map,
inner_variant,
len,
))
}
#[cfg(not(any(feature = "std", feature = "alloc")))]
@@ -402,7 +412,10 @@ mod content {
}
fn end(mut self) -> Result<M::Ok, M::Error> {
try!(self.map.serialize_value(&Content::TupleStruct(self.name, self.fields)));
try!(
self.map
.serialize_value(&Content::TupleStruct(self.name, self.fields))
);
self.map.end()
}
}
@@ -444,13 +457,16 @@ mod content {
}
fn end(mut self) -> Result<M::Ok, M::Error> {
try!(self.map.serialize_value(&Content::Struct(self.name, self.fields)));
try!(
self.map
.serialize_value(&Content::Struct(self.name, self.fields))
);
self.map.end()
}
}
#[derive(Debug)]
enum Content {
pub enum Content {
Bool(bool),
U8(u8),
@@ -485,7 +501,12 @@ mod content {
TupleVariant(&'static str, u32, &'static str, Vec<Content>),
Map(Vec<(Content, Content)>),
Struct(&'static str, Vec<(&'static str, Content)>),
StructVariant(&'static str, u32, &'static str, Vec<(&'static str, Content)>),
StructVariant(
&'static str,
u32,
&'static str,
Vec<(&'static str, Content)>,
),
}
impl Serialize for Content {
@@ -570,12 +591,12 @@ mod content {
}
}
struct ContentSerializer<E> {
pub struct ContentSerializer<E> {
error: PhantomData<E>,
}
impl<E> ContentSerializer<E> {
fn new() -> Self {
pub fn new() -> Self {
ContentSerializer { error: PhantomData }
}
}
@@ -687,7 +708,10 @@ mod content {
where
T: Serialize,
{
Ok(Content::NewtypeStruct(name, Box::new(try!(value.serialize(self)))),)
Ok(Content::NewtypeStruct(
name,
Box::new(try!(value.serialize(self))),
))
}
fn serialize_newtype_variant<T: ?Sized>(
@@ -700,32 +724,26 @@ mod content {
where
T: Serialize,
{
Ok(
Content::NewtypeVariant(
name,
variant_index,
variant,
Box::new(try!(value.serialize(self))),
),
)
Ok(Content::NewtypeVariant(
name,
variant_index,
variant,
Box::new(try!(value.serialize(self))),
))
}
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, E> {
Ok(
SerializeSeq {
elements: Vec::with_capacity(len.unwrap_or(0)),
error: PhantomData,
},
)
Ok(SerializeSeq {
elements: Vec::with_capacity(len.unwrap_or(0)),
error: PhantomData,
})
}
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, E> {
Ok(
SerializeTuple {
elements: Vec::with_capacity(len),
error: PhantomData,
},
)
Ok(SerializeTuple {
elements: Vec::with_capacity(len),
error: PhantomData,
})
}
fn serialize_tuple_struct(
@@ -733,13 +751,11 @@ mod content {
name: &'static str,
len: usize,
) -> Result<Self::SerializeTupleStruct, E> {
Ok(
SerializeTupleStruct {
name: name,
fields: Vec::with_capacity(len),
error: PhantomData,
},
)
Ok(SerializeTupleStruct {
name: name,
fields: Vec::with_capacity(len),
error: PhantomData,
})
}
fn serialize_tuple_variant(
@@ -749,25 +765,21 @@ mod content {
variant: &'static str,
len: usize,
) -> Result<Self::SerializeTupleVariant, E> {
Ok(
SerializeTupleVariant {
name: name,
variant_index: variant_index,
variant: variant,
fields: Vec::with_capacity(len),
error: PhantomData,
},
)
Ok(SerializeTupleVariant {
name: name,
variant_index: variant_index,
variant: variant,
fields: Vec::with_capacity(len),
error: PhantomData,
})
}
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, E> {
Ok(
SerializeMap {
entries: Vec::with_capacity(len.unwrap_or(0)),
key: None,
error: PhantomData,
},
)
Ok(SerializeMap {
entries: Vec::with_capacity(len.unwrap_or(0)),
key: None,
error: PhantomData,
})
}
fn serialize_struct(
@@ -775,13 +787,11 @@ mod content {
name: &'static str,
len: usize,
) -> Result<Self::SerializeStruct, E> {
Ok(
SerializeStruct {
name: name,
fields: Vec::with_capacity(len),
error: PhantomData,
},
)
Ok(SerializeStruct {
name: name,
fields: Vec::with_capacity(len),
error: PhantomData,
})
}
fn serialize_struct_variant(
@@ -791,19 +801,17 @@ mod content {
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, E> {
Ok(
SerializeStructVariant {
name: name,
variant_index: variant_index,
variant: variant,
fields: Vec::with_capacity(len),
error: PhantomData,
},
)
Ok(SerializeStructVariant {
name: name,
variant_index: variant_index,
variant: variant,
fields: Vec::with_capacity(len),
error: PhantomData,
})
}
}
struct SerializeSeq<E> {
pub struct SerializeSeq<E> {
elements: Vec<Content>,
error: PhantomData<E>,
}
@@ -829,7 +837,7 @@ mod content {
}
}
struct SerializeTuple<E> {
pub struct SerializeTuple<E> {
elements: Vec<Content>,
error: PhantomData<E>,
}
@@ -855,7 +863,7 @@ mod content {
}
}
struct SerializeTupleStruct<E> {
pub struct SerializeTupleStruct<E> {
name: &'static str,
fields: Vec<Content>,
error: PhantomData<E>,
@@ -882,7 +890,7 @@ mod content {
}
}
struct SerializeTupleVariant<E> {
pub struct SerializeTupleVariant<E> {
name: &'static str,
variant_index: u32,
variant: &'static str,
@@ -907,11 +915,16 @@ mod content {
}
fn end(self) -> Result<Content, E> {
Ok(Content::TupleVariant(self.name, self.variant_index, self.variant, self.fields),)
Ok(Content::TupleVariant(
self.name,
self.variant_index,
self.variant,
self.fields,
))
}
}
struct SerializeMap<E> {
pub struct SerializeMap<E> {
entries: Vec<(Content, Content)>,
key: Option<Content>,
error: PhantomData<E>,
@@ -961,7 +974,7 @@ mod content {
}
}
struct SerializeStruct<E> {
pub struct SerializeStruct<E> {
name: &'static str,
fields: Vec<(&'static str, Content)>,
error: PhantomData<E>,
@@ -988,7 +1001,7 @@ mod content {
}
}
struct SerializeStructVariant<E> {
pub struct SerializeStructVariant<E> {
name: &'static str,
variant_index: u32,
variant: &'static str,
@@ -1013,7 +1026,292 @@ mod content {
}
fn end(self) -> Result<Content, E> {
Ok(Content::StructVariant(self.name, self.variant_index, self.variant, self.fields),)
Ok(Content::StructVariant(
self.name,
self.variant_index,
self.variant,
self.fields,
))
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapSerializer<'a, M: 'a>(pub &'a mut M);
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> FlatMapSerializer<'a, M>
where
M: SerializeMap + 'a
{
fn bad_type(self, what: Unsupported) -> M::Error {
ser::Error::custom(format_args!("can only flatten structs and maps (got {})", what))
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> Serializer for FlatMapSerializer<'a, M>
where M: SerializeMap + 'a
{
type Ok = ();
type Error = M::Error;
type SerializeSeq = Impossible<Self::Ok, M::Error>;
type SerializeTuple = Impossible<Self::Ok, M::Error>;
type SerializeTupleStruct = Impossible<Self::Ok, M::Error>;
type SerializeMap = FlatMapSerializeMap<'a, M>;
type SerializeStruct = FlatMapSerializeStruct<'a, M>;
type SerializeTupleVariant = Impossible<Self::Ok, M::Error>;
type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>;
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Boolean))
}
fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Integer))
}
fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Float))
}
fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Float))
}
fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Char))
}
fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::String))
}
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::ByteArray))
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Optional))
}
fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
where
T: Serialize,
{
Err(self.bad_type(Unsupported::Optional))
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Unit))
}
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::UnitStruct))
}
fn serialize_unit_variant(
self,
_: &'static str,
_: u32,
_: &'static str,
) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Enum))
}
fn serialize_newtype_struct<T: ?Sized>(
self,
_: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: Serialize,
{
value.serialize(self)
}
fn serialize_newtype_variant<T: ?Sized>(
self,
_: &'static str,
_: u32,
variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: Serialize,
{
try!(self.0.serialize_key(variant));
self.0.serialize_value(value)
}
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Err(self.bad_type(Unsupported::Sequence))
}
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
Err(self.bad_type(Unsupported::Tuple))
}
fn serialize_tuple_struct(
self,
_: &'static str,
_: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Err(self.bad_type(Unsupported::TupleStruct))
}
fn serialize_tuple_variant(
self,
_: &'static str,
_: u32,
_: &'static str,
_: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
Err(self.bad_type(Unsupported::Enum))
}
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Ok(FlatMapSerializeMap(self.0))
}
fn serialize_struct(
self,
_: &'static str,
_: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Ok(FlatMapSerializeStruct(self.0))
}
fn serialize_struct_variant(
self,
_: &'static str,
_: u32,
inner_variant: &'static str,
_: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
try!(self.0.serialize_key(inner_variant));
Ok(FlatMapSerializeStructVariantAsMapValue::new(self.0, inner_variant))
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapSerializeMap<'a, M: 'a>(&'a mut M);
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> ser::SerializeMap for FlatMapSerializeMap<'a, M>
where M: SerializeMap + 'a
{
type Ok = ();
type Error = M::Error;
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
where
T: Serialize,
{
self.0.serialize_key(key)
}
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: Serialize,
{
self.0.serialize_value(value)
}
fn end(self) -> Result<(), Self::Error> {
Ok(())
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapSerializeStruct<'a, M: 'a>(&'a mut M);
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> ser::SerializeStruct for FlatMapSerializeStruct<'a, M>
where M: SerializeMap + 'a
{
type Ok = ();
type Error = M::Error;
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: Serialize,
{
self.0.serialize_entry(key, value)
}
fn end(self) -> Result<(), Self::Error> {
Ok(())
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapSerializeStructVariantAsMapValue<'a, M: 'a> {
map: &'a mut M,
name: &'static str,
fields: Vec<(&'static str, Content)>,
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> FlatMapSerializeStructVariantAsMapValue<'a, M>
where M: SerializeMap + 'a
{
fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> {
FlatMapSerializeStructVariantAsMapValue {
map: map,
name: name,
fields: Vec::new(),
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> ser::SerializeStructVariant for FlatMapSerializeStructVariantAsMapValue<'a, M>
where M: SerializeMap + 'a
{
type Ok = ();
type Error = M::Error;
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: Serialize,
{
let value = try!(value.serialize(ContentSerializer::<M::Error>::new()));
self.fields.push((key, value));
Ok(())
}
fn end(self) -> Result<(), Self::Error> {
try!(self.map.serialize_value(&Content::Struct(self.name, self.fields)));
Ok(())
}
}
+46 -11
View File
@@ -111,7 +111,7 @@ where
////////////////////////////////////////////////////////////////////////////////
impl<T> Serialize for PhantomData<T> {
impl<T: ?Sized> Serialize for PhantomData<T> {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@@ -351,6 +351,7 @@ deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwne
////////////////////////////////////////////////////////////////////////////////
#[cfg(feature = "unstable")]
#[allow(deprecated)]
impl<T> Serialize for NonZero<T>
where
T: Serialize + Zeroable + Clone,
@@ -363,6 +364,32 @@ where
}
}
macro_rules! nonzero_integers {
( $( $T: ident, )+ ) => {
$(
#[cfg(feature = "unstable")]
impl Serialize for $T {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.get().serialize(serializer)
}
}
)+
}
}
nonzero_integers! {
// Not including signed NonZeroI* since they might be removed
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
// FIXME: https://github.com/serde-rs/serde/issues/1136 NonZeroU128,
NonZeroUsize,
}
impl<T> Serialize for Cell<T>
where
T: Serialize + Copy,
@@ -464,7 +491,8 @@ impl Serialize for SystemTime {
S: Serializer,
{
use super::SerializeStruct;
let duration_since_epoch = self.duration_since(UNIX_EPOCH).expect("SystemTime must be later than UNIX_EPOCH");
let duration_since_epoch = self.duration_since(UNIX_EPOCH)
.expect("SystemTime must be later than UNIX_EPOCH");
let mut state = try!(serializer.serialize_struct("SystemTime", 2));
try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs()));
try!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos()));
@@ -513,10 +541,12 @@ impl Serialize for net::IpAddr {
}
} else {
match *self {
net::IpAddr::V4(ref a) =>
serializer.serialize_newtype_variant("IpAddr", 0, "V4", a),
net::IpAddr::V6(ref a) =>
serializer.serialize_newtype_variant("IpAddr", 1, "V6", a),
net::IpAddr::V4(ref a) => {
serializer.serialize_newtype_variant("IpAddr", 0, "V4", a)
}
net::IpAddr::V6(ref a) => {
serializer.serialize_newtype_variant("IpAddr", 1, "V6", a)
}
}
}
}
@@ -567,10 +597,12 @@ impl Serialize for net::SocketAddr {
}
} else {
match *self {
net::SocketAddr::V4(ref addr) =>
serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr),
net::SocketAddr::V6(ref addr) =>
serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr),
net::SocketAddr::V4(ref addr) => {
serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr)
}
net::SocketAddr::V6(ref addr) => {
serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr)
}
}
}
}
@@ -600,7 +632,10 @@ impl Serialize for net::SocketAddrV6 {
{
if serializer.is_human_readable() {
const MAX_LEN: usize = 47;
debug_assert_eq!(MAX_LEN, "[1001:1002:1003:1004:1005:1006:1007:1008]:65000".len());
debug_assert_eq!(
MAX_LEN,
"[1001:1002:1003:1004:1005:1006:1007:1008]:65000".len()
);
serialize_display_bounded_length!(self, MAX_LEN, serializer)
} else {
(self.ip(), self.port()).serialize(serializer)
+2 -2
View File
@@ -10,8 +10,8 @@
use lib::*;
use ser::{self, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct,
SerializeTupleVariant, SerializeMap, SerializeStruct, SerializeStructVariant};
use ser::{self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant};
/// Helper type for implementing a `Serializer` that does not support
/// serializing one of the compound types.
+5 -2
View File
@@ -93,7 +93,8 @@
//! - Path
//! - PathBuf
//! - Range\<T\>
//! - NonZero\<T\> (unstable)
//! - NonZero\<T\> (unstable, deprecated)
//! - num::NonZero* (unstable)
//! - **Net types**:
//! - IpAddr
//! - Ipv4Addr
@@ -1412,7 +1413,9 @@ pub trait Serializer: Sized {
/// change, as a value serialized in human-readable mode is not required to
/// deserialize from the same data in compact mode.
#[inline]
fn is_human_readable(&self) -> bool { true }
fn is_human_readable(&self) -> bool {
true
}
}
/// Returned from `Serializer::serialize_seq`.
+9 -4
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.19" # remember to update html_root_url
version = "1.0.36" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -14,14 +14,19 @@ include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-
[badges]
travis-ci = { repository = "serde-rs/serde" }
[features]
default = []
deserialize_in_place = []
[lib]
name = "serde_derive"
proc-macro = true
[dependencies]
quote = "0.3.8"
serde_derive_internals = { version = "=0.17.0", default-features = false, path = "../serde_derive_internals" }
syn = { version = "0.11", features = ["visit"] }
proc-macro2 = "0.2"
quote = "0.4"
serde_derive_internals = { version = "=0.22.2", default-features = false, path = "../serde_derive_internals" }
syn = { version = "0.12", features = ["visit"] }
[dev-dependencies]
serde = { version = "1.0", path = "../serde" }
+174 -126
View File
@@ -9,32 +9,31 @@
use std::collections::HashSet;
use syn::{self, visit};
use syn::punctuated::Punctuated;
use internals::ast::{Body, Container};
use internals::ast::{Data, Container};
use internals::attr;
macro_rules! path {
($($path:tt)+) => {
syn::parse_path(quote!($($path)+).as_str()).unwrap()
};
}
use proc_macro2::{Span, Term};
// Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not
// allowed here".
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
syn::Generics {
ty_params: generics
.ty_params
params: generics
.params
.iter()
.map(
|ty_param| {
syn::TyParam {
.map(|param| match *param {
syn::GenericParam::Type(ref param) => {
syn::GenericParam::Type(syn::TypeParam {
eq_token: None,
default: None,
..ty_param.clone()
}
},
)
..param.clone()
})
}
_ => param.clone(),
})
.collect(),
..generics.clone()
}
@@ -45,10 +44,17 @@ pub fn with_where_predicates(
predicates: &[syn::WherePredicate],
) -> syn::Generics {
let mut generics = generics.clone();
generics
.where_clause
if generics.where_clause.is_none() {
generics.where_clause = Some(syn::WhereClause {
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates
.extend_from_slice(predicates);
.extend(predicates.into_iter().cloned());
generics
}
@@ -60,13 +66,23 @@ pub fn with_where_predicates_from_fields<F>(
where
F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
{
let predicates = cont.body
let predicates = cont.data
.all_fields()
.flat_map(|field| from_field(&field.attrs))
.flat_map(|predicates| predicates.to_vec());
let mut generics = generics.clone();
generics.where_clause.predicates.extend(predicates);
if generics.where_clause.is_none() {
generics.where_clause = Some(syn::WhereClause {
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates
.extend(predicates);
generics
}
@@ -99,22 +115,22 @@ where
// them.
relevant_ty_params: HashSet<syn::Ident>,
}
impl visit::Visitor for FindTyParams {
impl<'ast> visit::Visit<'ast> for FindTyParams {
fn visit_path(&mut self, path: &syn::Path) {
if let Some(seg) = path.segments.last() {
if seg.ident == "PhantomData" {
if seg.into_value().ident == "PhantomData" {
// Hardcoded exception, because PhantomData<T> implements
// Serialize and Deserialize whether or not T implements it.
return;
}
}
if !path.global && path.segments.len() == 1 {
let id = path.segments[0].ident.clone();
if path.leading_colon.is_none() && path.segments.len() == 1 {
let id = path.segments[0].ident;
if self.all_ty_params.contains(&id) {
self.relevant_ty_params.insert(id);
}
}
visit::walk_path(self, path);
visit::visit_path(self, path);
}
// Type parameter should not be considered used by a macro path.
@@ -123,67 +139,79 @@ where
// mac: T!(),
// marker: PhantomData<T>,
// }
fn visit_mac(&mut self, _mac: &syn::Mac) {}
fn visit_macro(&mut self, _mac: &syn::Macro) {}
}
let all_ty_params: HashSet<_> = generics
.ty_params
.params
.iter()
.map(|ty_param| ty_param.ident.clone())
.filter_map(|param| match *param {
syn::GenericParam::Type(ref param) => Some(param.ident),
_ => None,
})
.collect();
let mut visitor = FindTyParams {
all_ty_params: all_ty_params,
relevant_ty_params: HashSet::new(),
};
match cont.body {
Body::Enum(ref variants) => {
for variant in variants.iter() {
let relevant_fields = variant
.fields
.iter()
.filter(|field| filter(&field.attrs, Some(&variant.attrs)));
for field in relevant_fields {
visit::walk_ty(&mut visitor, field.ty);
}
match cont.data {
Data::Enum(ref variants) => for variant in variants.iter() {
let relevant_fields = variant
.fields
.iter()
.filter(|field| filter(&field.attrs, Some(&variant.attrs)));
for field in relevant_fields {
visit::visit_type(&mut visitor, field.ty);
}
}
Body::Struct(_, ref fields) => {
},
Data::Struct(_, ref fields) => {
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
visit::walk_ty(&mut visitor, field.ty);
visit::visit_type(&mut visitor, field.ty);
}
}
}
let new_predicates = generics
.ty_params
.params
.iter()
.map(|ty_param| ty_param.ident.clone())
.filter_map(|param| match *param {
syn::GenericParam::Type(ref param) => Some(param.ident),
_ => None,
})
.filter(|id| visitor.relevant_ty_params.contains(id))
.map(
|id| {
syn::WherePredicate::BoundPredicate(
syn::WhereBoundPredicate {
bound_lifetimes: Vec::new(),
// the type parameter that is being bounded e.g. T
bounded_ty: syn::Ty::Path(None, id.into()),
// the bound e.g. Serialize
bounds: vec![
syn::TyParamBound::Trait(
syn::PolyTraitRef {
bound_lifetimes: Vec::new(),
trait_ref: bound.clone(),
},
syn::TraitBoundModifier::None,
),
],
},
)
},
);
.map(|id| {
syn::WherePredicate::Type(syn::PredicateType {
lifetimes: None,
// the type parameter that is being bounded e.g. T
bounded_ty: syn::Type::Path(syn::TypePath {
qself: None,
path: id.into(),
}),
colon_token: Default::default(),
// the bound e.g. Serialize
bounds: vec![
syn::TypeParamBound::Trait(syn::TraitBound {
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: bound.clone(),
}),
].into_iter().collect(),
})
});
let mut generics = generics.clone();
generics.where_clause.predicates.extend(new_predicates);
if generics.where_clause.is_none() {
generics.where_clause = Some(syn::WhereClause {
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates
.extend(new_predicates);
generics
}
@@ -193,82 +221,102 @@ pub fn with_self_bound(
bound: &syn::Path,
) -> syn::Generics {
let mut generics = generics.clone();
generics
.where_clause
if generics.where_clause.is_none() {
generics.where_clause = Some(syn::WhereClause {
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates
.push(
syn::WherePredicate::BoundPredicate(
syn::WhereBoundPredicate {
bound_lifetimes: Vec::new(),
// the type that is being bounded e.g. MyStruct<'a, T>
bounded_ty: type_of_item(cont),
// the bound e.g. Default
bounds: vec![
syn::TyParamBound::Trait(
syn::PolyTraitRef {
bound_lifetimes: Vec::new(),
trait_ref: bound.clone(),
},
syn::TraitBoundModifier::None,
),
],
},
),
);
.push(syn::WherePredicate::Type(syn::PredicateType {
lifetimes: None,
// the type that is being bounded e.g. MyStruct<'a, T>
bounded_ty: type_of_item(cont),
colon_token: Default::default(),
// the bound e.g. Default
bounds: vec![
syn::TypeParamBound::Trait(syn::TraitBound {
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: bound.clone(),
}),
].into_iter().collect(),
}));
generics
}
pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
let mut generics = generics.clone();
let bound = syn::Lifetime::new(Term::intern(lifetime), Span::def_site());
let def = syn::LifetimeDef {
attrs: Vec::new(),
lifetime: bound,
colon_token: None,
bounds: Punctuated::new(),
};
for lifetime_def in &mut generics.lifetimes {
lifetime_def.bounds.push(syn::Lifetime::new(lifetime));
let params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params
.iter()
.cloned()
.map(|mut param| {
match param {
syn::GenericParam::Lifetime(ref mut param) => {
param.bounds.push(bound);
}
syn::GenericParam::Type(ref mut param) => {
param.bounds.push(syn::TypeParamBound::Lifetime(bound));
}
syn::GenericParam::Const(_) => {}
}
param
}))
.collect();
syn::Generics {
params: params,
..generics.clone()
}
for ty_param in &mut generics.ty_params {
ty_param
.bounds
.push(syn::TyParamBound::Region(syn::Lifetime::new(lifetime)));
}
generics
.lifetimes
.push(
syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new(lifetime),
bounds: Vec::new(),
},
);
generics
}
fn type_of_item(cont: &Container) -> syn::Ty {
syn::Ty::Path(
None,
syn::Path {
global: false,
fn type_of_item(cont: &Container) -> syn::Type {
syn::Type::Path(syn::TypePath {
qself: None,
path: syn::Path {
leading_colon: None,
segments: vec![
syn::PathSegment {
ident: cont.ident.clone(),
parameters: syn::PathParameters::AngleBracketed(
syn::AngleBracketedParameterData {
lifetimes: cont.generics
.lifetimes
ident: cont.ident,
arguments: syn::PathArguments::AngleBracketed(
syn::AngleBracketedGenericArguments {
colon2_token: None,
lt_token: Default::default(),
args: cont.generics
.params
.iter()
.map(|def| def.lifetime.clone())
.map(|param| match *param {
syn::GenericParam::Type(ref param) => {
syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
qself: None,
path: param.ident.into(),
}))
}
syn::GenericParam::Lifetime(ref param) => {
syn::GenericArgument::Lifetime(param.lifetime)
}
syn::GenericParam::Const(_) => {
panic!("Serde does not support const generics yet");
}
})
.collect(),
types: cont.generics
.ty_params
.iter()
.map(|param| syn::Ty::Path(None, param.ident.clone().into()))
.collect(),
bindings: Vec::new(),
gt_token: Default::default(),
},
),
},
],
].into_iter().collect(),
},
)
})
}
+1273 -394
View File
File diff suppressed because it is too large Load Diff
+14 -8
View File
@@ -6,7 +6,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use quote::{Tokens, ToTokens};
use quote::{ToTokens, Tokens};
use syn::token;
pub enum Fragment {
/// Tokens that can be used as an expression.
@@ -36,9 +37,7 @@ impl ToTokens for Expr {
match self.0 {
Fragment::Expr(ref expr) => expr.to_tokens(out),
Fragment::Block(ref block) => {
out.append("{");
block.to_tokens(out);
out.append("}");
token::Brace::default().surround(out, |out| block.to_tokens(out));
}
}
}
@@ -63,13 +62,20 @@ impl ToTokens for Match {
match self.0 {
Fragment::Expr(ref expr) => {
expr.to_tokens(out);
out.append(",");
<Token![,]>::default().to_tokens(out);
}
Fragment::Block(ref block) => {
out.append("{");
block.to_tokens(out);
out.append("}");
token::Brace::default().surround(out, |out| block.to_tokens(out));
}
}
}
}
impl AsRef<Tokens> for Fragment {
fn as_ref(&self) -> &Tokens {
match *self {
Fragment::Expr(ref expr) => expr,
Fragment::Block(ref block) => block,
}
}
}
+13 -11
View File
@@ -22,22 +22,24 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.19")]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.36")]
#![cfg_attr(feature = "cargo-clippy", allow(enum_variant_names, redundant_field_names,
too_many_arguments, used_underscore_binding))]
// The `quote!` macro requires deep recursion.
#![recursion_limit = "192"]
#![recursion_limit = "512"]
extern crate syn;
#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;
extern crate serde_derive_internals as internals;
extern crate proc_macro;
extern crate proc_macro2;
use proc_macro::TokenStream;
use syn::DeriveInput;
#[macro_use]
mod bound;
@@ -49,18 +51,18 @@ mod de;
#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&input.to_string()).unwrap();
let input: DeriveInput = syn::parse(input).unwrap();
match ser::expand_derive_serialize(&input) {
Ok(expanded) => expanded.parse().unwrap(),
Ok(expanded) => expanded.into(),
Err(msg) => panic!(msg),
}
}
#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&input.to_string()).unwrap();
let input: DeriveInput = syn::parse(input).unwrap();
match de::expand_derive_deserialize(&input) {
Ok(expanded) => expanded.parse().unwrap(),
Ok(expanded) => expanded.into(),
Err(msg) => panic!(msg),
}
}
+371 -287
View File
@@ -6,12 +6,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use syn::{self, Ident};
use syn::{self, Ident, Index, Member};
use syn::spanned::Spanned;
use quote::Tokens;
use proc_macro2::Span;
use bound;
use fragment::{Fragment, Stmts, Match};
use internals::ast::{Body, Container, Field, Style, Variant};
use fragment::{Fragment, Match, Stmts};
use internals::ast::{Data, Container, Field, Style, Variant};
use internals::{attr, Ctxt};
use std::u32;
@@ -25,14 +27,15 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, Strin
let ident = &cont.ident;
let params = Parameters::new(&cont);
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
let dummy_const = Ident::new(format!("_IMPL_SERIALIZE_FOR_{}", ident));
let dummy_const = Ident::new(&format!("_IMPL_SERIALIZE_FOR_{}", ident), Span::def_site());
let body = Stmts(serialize_body(&cont, &params));
let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis;
let fun = quote_spanned!(Span::call_site()=> serialize);
quote! {
impl #impl_generics #ident #ty_generics #where_clause {
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
#vis fn #fun<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
where __S: _serde::Serializer
{
#body
@@ -95,14 +98,14 @@ impl Parameters {
fn new(cont: &Container) -> Self {
let is_remote = cont.attrs.remote().is_some();
let self_var = if is_remote {
Ident::new("__self")
Ident::new("__self", Span::def_site())
} else {
Ident::new("self")
Ident::new("self", Span::def_site())
};
let this = match cont.attrs.remote() {
Some(remote) => remote.clone(),
None => cont.ident.clone().into(),
None => cont.ident.into(),
};
let generics = build_generics(cont);
@@ -118,7 +121,7 @@ impl Parameters {
/// Type name to use in error messages and `&'static str` arguments to
/// various Serializer methods.
fn type_name(&self) -> &str {
self.this.segments.last().unwrap().ident.as_ref()
self.this.segments.last().unwrap().value().ident.as_ref()
}
}
@@ -132,14 +135,12 @@ fn build_generics(cont: &Container) -> syn::Generics {
match cont.attrs.ser_bound() {
Some(predicates) => bound::with_where_predicates(&generics, predicates),
None => {
bound::with_bound(
cont,
&generics,
needs_serialize_bound,
&path!(_serde::Serialize),
)
}
None => bound::with_bound(
cont,
&generics,
needs_serialize_bound,
&parse_quote!(_serde::Serialize),
),
}
}
@@ -149,43 +150,41 @@ fn build_generics(cont: &Container) -> syn::Generics {
// their own bound so we do not generate one. All other fields may need a `T:
// Serialize` bound where T is the type of the field.
fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
!field.skip_serializing() &&
field.serialize_with().is_none() &&
field.ser_bound().is_none() &&
variant.map_or(true, |variant| variant.serialize_with().is_none())
!field.skip_serializing() && field.serialize_with().is_none() && field.ser_bound().is_none()
&& variant.map_or(true, |variant| variant.serialize_with().is_none())
}
fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
if let Some(into_type) = cont.attrs.into_type() {
serialize_into(params, into_type)
if let Some(type_into) = cont.attrs.type_into() {
serialize_into(params, type_into)
} else {
match cont.body {
Body::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs),
Body::Struct(Style::Struct, ref fields) => {
match cont.data {
Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs),
Data::Struct(Style::Struct, ref fields) => {
if fields.iter().any(|field| field.ident.is_none()) {
panic!("struct has unnamed fields");
}
serialize_struct(params, fields, &cont.attrs)
}
Body::Struct(Style::Tuple, ref fields) => {
Data::Struct(Style::Tuple, ref fields) => {
if fields.iter().any(|field| field.ident.is_some()) {
panic!("tuple struct has named fields");
}
serialize_tuple_struct(params, fields, &cont.attrs)
}
Body::Struct(Style::Newtype, ref fields) => {
Data::Struct(Style::Newtype, ref fields) => {
serialize_newtype_struct(params, &fields[0], &cont.attrs)
}
Body::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs),
Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs),
}
}
}
fn serialize_into(params: &Parameters, into_type: &syn::Ty) -> Fragment {
fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment {
let self_var = &params.self_var;
quote_block! {
_serde::Serialize::serialize(
&_serde::export::Into::<#into_type>::into(_serde::export::Clone::clone(#self_var)),
&_serde::export::Into::<#type_into>::into(_serde::export::Clone::clone(#self_var)),
__serializer)
}
}
@@ -205,13 +204,18 @@ fn serialize_newtype_struct(
) -> Fragment {
let type_name = cattrs.name().serialize_name();
let mut field_expr = get_field(params, field, 0);
let mut field_expr = get_member(params, field, &Member::Unnamed(Index {
index: 0,
span: Span::call_site(),
}));
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
}
let span = Span::def_site().located_at(field.original.span());
let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_struct);
quote_expr! {
_serde::Serializer::serialize_newtype_struct(__serializer, #type_name, #field_expr)
#func(__serializer, #type_name, #field_expr)
}
}
@@ -224,7 +228,7 @@ fn serialize_tuple_struct(
fields,
params,
false,
quote!(_serde::ser::SerializeTupleStruct::serialize_field),
&TupleTrait::SerializeTupleStruct,
);
let type_name = cattrs.name().serialize_name();
@@ -239,14 +243,21 @@ fn serialize_tuple_struct(
}
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
assert!(fields.len() as u64 <= u32::MAX as u64);
assert!(fields.len() as u64 <= u64::from(u32::MAX));
if cattrs.has_flatten() {
serialize_struct_as_map(params, fields, cattrs)
} else {
serialize_struct_as_struct(params, fields, cattrs)
}
}
fn serialize_struct_as_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
let serialize_fields = serialize_struct_visitor(
fields,
params,
false,
quote!(_serde::ser::SerializeStruct::serialize_field),
quote!(_serde::ser::SerializeStruct::skip_field),
&StructTrait::SerializeStruct,
);
let type_name = cattrs.name().serialize_name();
@@ -259,16 +270,14 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
let let_mut = mut_if(serialized_fields.peek().is_some());
let len = serialized_fields
.map(
|field| match field.attrs.skip_serializing_if() {
None => quote!(1),
Some(path) => {
let ident = field.ident.clone().expect("struct has unnamed fields");
let field_expr = get_field(params, field, ident);
quote!(if #path(#field_expr) { 0 } else { 1 })
}
},
)
.map(|field| match field.attrs.skip_serializing_if() {
None => quote!(1),
Some(path) => {
let ident = field.ident.expect("struct has unnamed fields");
let field_expr = get_member(params, field, &Member::Named(ident));
quote!(if #path(#field_expr) { 0 } else { 1 })
}
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
quote_block! {
@@ -278,19 +287,55 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
}
}
fn serialize_struct_as_map(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
let serialize_fields = serialize_struct_visitor(
fields,
params,
false,
&StructTrait::SerializeMap,
);
let mut serialized_fields = fields
.iter()
.filter(|&field| !field.attrs.skip_serializing())
.peekable();
let let_mut = mut_if(serialized_fields.peek().is_some());
let len = if cattrs.has_flatten() {
quote!(_serde::export::None)
} else {
let len = serialized_fields
.map(|field| match field.attrs.skip_serializing_if() {
None => quote!(1),
Some(path) => {
let ident = field.ident.expect("struct has unnamed fields");
let field_expr = get_member(params, field, &Member::Named(ident));
quote!(if #path(#field_expr) { 0 } else { 1 })
}
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
quote!(_serde::export::Some(#len))
};
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(__serializer, #len));
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
}
}
fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment {
assert!(variants.len() as u64 <= u32::MAX as u64);
assert!(variants.len() as u64 <= u64::from(u32::MAX));
let self_var = &params.self_var;
let arms: Vec<_> = variants
.iter()
.enumerate()
.map(
|(variant_index, variant)| {
serialize_variant(params, variant, variant_index as u32, cattrs)
},
)
.map(|(variant_index, variant)| {
serialize_variant(params, variant, variant_index as u32, cattrs)
})
.collect();
quote_expr! {
@@ -307,7 +352,7 @@ fn serialize_variant(
cattrs: &attr::Container,
) -> Tokens {
let this = &params.this;
let variant_ident = variant.ident.clone();
let variant_ident = variant.ident;
if variant.attrs.skip_serializing() {
let skipped_msg = format!(
@@ -321,13 +366,7 @@ fn serialize_variant(
let fields_pat = match variant.style {
Style::Unit => quote!(),
Style::Newtype | Style::Tuple => quote!((..)),
Style::Struct => {
quote!(
{
..
}
)
}
Style::Struct => quote!({ .. }),
};
quote! {
#this::#variant_ident #fields_pat => #skipped_err,
@@ -347,7 +386,7 @@ fn serialize_variant(
}
Style::Tuple => {
let field_names =
(0..variant.fields.len()).map(|i| Ident::new(format!("__field{}", i)));
(0..variant.fields.len()).map(|i| Ident::new(&format!("__field{}", i), Span::def_site()));
quote! {
#this::#variant_ident(#(ref #field_names),*)
}
@@ -356,34 +395,26 @@ fn serialize_variant(
let fields = variant
.fields
.iter()
.map(
|f| {
f.ident
.clone()
.expect("struct variant has unnamed fields")
},
);
.map(|f| f.ident.expect("struct variant has unnamed fields"));
quote! {
#this::#variant_ident { #(ref #fields),* }
}
}
};
let body = Match(
match *cattrs.tag() {
attr::EnumTag::External => {
serialize_externally_tagged_variant(params, variant, variant_index, cattrs)
}
attr::EnumTag::Internal { ref tag } => {
serialize_internally_tagged_variant(params, variant, cattrs, tag)
}
attr::EnumTag::Adjacent {
ref tag,
ref content,
} => serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content),
attr::EnumTag::None => serialize_untagged_variant(params, variant, cattrs),
},
);
let body = Match(match *cattrs.tag() {
attr::EnumTag::External => {
serialize_externally_tagged_variant(params, variant, variant_index, cattrs)
}
attr::EnumTag::Internal { ref tag } => {
serialize_internally_tagged_variant(params, variant, cattrs, tag)
}
attr::EnumTag::Adjacent {
ref tag,
ref content,
} => serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content),
attr::EnumTag::None => serialize_untagged_variant(params, variant, cattrs),
});
quote! {
#case => #body
@@ -401,7 +432,7 @@ fn serialize_externally_tagged_variant(
let variant_name = variant.attrs.name().serialize_name();
if let Some(path) = variant.attrs.serialize_with() {
let ser = wrap_serialize_variant_with(params, path, &variant);
let ser = wrap_serialize_variant_with(params, path, variant);
return quote_expr! {
_serde::Serializer::serialize_newtype_variant(
__serializer,
@@ -428,7 +459,7 @@ fn serialize_externally_tagged_variant(
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
}
quote_expr! {
@@ -441,28 +472,24 @@ fn serialize_externally_tagged_variant(
)
}
}
Style::Tuple => {
serialize_tuple_variant(
TupleVariant::ExternallyTagged {
type_name: type_name,
variant_index: variant_index,
variant_name: variant_name,
},
params,
&variant.fields,
)
}
Style::Struct => {
serialize_struct_variant(
StructVariant::ExternallyTagged {
variant_index: variant_index,
variant_name: variant_name,
},
params,
&variant.fields,
&type_name,
)
}
Style::Tuple => serialize_tuple_variant(
TupleVariant::ExternallyTagged {
type_name: type_name,
variant_index: variant_index,
variant_name: variant_name,
},
params,
&variant.fields,
),
Style::Struct => serialize_struct_variant(
StructVariant::ExternallyTagged {
variant_index: variant_index,
variant_name: variant_name,
},
params,
&variant.fields,
&type_name,
),
}
}
@@ -479,7 +506,7 @@ fn serialize_internally_tagged_variant(
let variant_ident_str = variant.ident.as_ref();
if let Some(path) = variant.attrs.serialize_with() {
let ser = wrap_serialize_variant_with(params, path, &variant);
let ser = wrap_serialize_variant_with(params, path, variant);
return quote_expr! {
_serde::private::ser::serialize_tagged_newtype(
__serializer,
@@ -506,7 +533,7 @@ fn serialize_internally_tagged_variant(
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
}
quote_expr! {
@@ -520,17 +547,15 @@ fn serialize_internally_tagged_variant(
)
}
}
Style::Struct => {
serialize_struct_variant(
StructVariant::InternallyTagged {
tag: tag,
variant_name: variant_name,
},
params,
&variant.fields,
&type_name,
)
}
Style::Struct => serialize_struct_variant(
StructVariant::InternallyTagged {
tag: tag,
variant_name: variant_name,
},
params,
&variant.fields,
&type_name,
),
Style::Tuple => unreachable!("checked in serde_derive_internals"),
}
}
@@ -546,51 +571,47 @@ fn serialize_adjacently_tagged_variant(
let type_name = cattrs.name().serialize_name();
let variant_name = variant.attrs.name().serialize_name();
let inner = Stmts(
if let Some(path) = variant.attrs.serialize_with() {
let ser = wrap_serialize_variant_with(params, path, &variant);
quote_expr! {
_serde::Serialize::serialize(#ser, __serializer)
let inner = Stmts(if let Some(path) = variant.attrs.serialize_with() {
let ser = wrap_serialize_variant_with(params, path, variant);
quote_expr! {
_serde::Serialize::serialize(#ser, __serializer)
}
} else {
match variant.style {
Style::Unit => {
return quote_block! {
let mut __struct = try!(_serde::Serializer::serialize_struct(
__serializer, #type_name, 1));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name));
_serde::ser::SerializeStruct::end(__struct)
};
}
} else {
match variant.style {
Style::Unit => {
return quote_block! {
let mut __struct = try!(_serde::Serializer::serialize_struct(
__serializer, #type_name, 1));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name));
_serde::ser::SerializeStruct::end(__struct)
};
Style::Newtype => {
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
}
Style::Newtype => {
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
}
quote_expr! {
_serde::Serialize::serialize(#field_expr, __serializer)
}
}
Style::Tuple => {
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
}
Style::Struct => {
serialize_struct_variant(
StructVariant::Untagged,
params,
&variant.fields,
&variant_name,
)
quote_expr! {
_serde::Serialize::serialize(#field_expr, __serializer)
}
}
},
);
Style::Tuple => {
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
}
Style::Struct => serialize_struct_variant(
StructVariant::Untagged,
params,
&variant.fields,
&variant_name,
),
}
});
let fields_ty = variant.fields.iter().map(|f| &f.ty);
let ref fields_ident: Vec<_> = match variant.style {
let fields_ident: &Vec<_> = &match variant.style {
Style::Unit => {
if variant.attrs.serialize_with().is_some() {
vec![]
@@ -598,25 +619,15 @@ fn serialize_adjacently_tagged_variant(
unreachable!()
}
}
Style::Newtype => vec![Ident::new("__field0")],
Style::Tuple => {
(0..variant.fields.len())
.map(|i| Ident::new(format!("__field{}", i)))
.collect()
}
Style::Struct => {
variant
.fields
.iter()
.map(
|f| {
f.ident
.clone()
.expect("struct variant has unnamed fields")
},
)
.collect()
}
Style::Newtype => vec![Ident::new("__field0", Span::def_site())],
Style::Tuple => (0..variant.fields.len())
.map(|i| Ident::new(&format!("__field{}", i), Span::def_site()))
.collect(),
Style::Struct => variant
.fields
.iter()
.map(|f| f.ident.expect("struct variant has unnamed fields"))
.collect(),
};
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
@@ -662,7 +673,7 @@ fn serialize_untagged_variant(
cattrs: &attr::Container,
) -> Fragment {
if let Some(path) = variant.attrs.serialize_with() {
let ser = wrap_serialize_variant_with(params, path, &variant);
let ser = wrap_serialize_variant_with(params, path, variant);
return quote_expr! {
_serde::Serialize::serialize(#ser, __serializer)
};
@@ -678,7 +689,7 @@ fn serialize_untagged_variant(
let field = &variant.fields[0];
let mut field_expr = quote!(__field0);
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
}
quote_expr! {
@@ -707,14 +718,12 @@ fn serialize_tuple_variant(
params: &Parameters,
fields: &[Field],
) -> Fragment {
let method = match context {
TupleVariant::ExternallyTagged { .. } => {
quote!(_serde::ser::SerializeTupleVariant::serialize_field)
}
TupleVariant::Untagged => quote!(_serde::ser::SerializeTuple::serialize_element),
let tuple_trait = match context {
TupleVariant::ExternallyTagged { .. } => TupleTrait::SerializeTupleVariant,
TupleVariant::Untagged => TupleTrait::SerializeTuple,
};
let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, method);
let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, &tuple_trait);
let len = serialize_stmts.len();
let let_mut = mut_if(len > 0);
@@ -753,7 +762,10 @@ enum StructVariant<'a> {
variant_index: u32,
variant_name: String,
},
InternallyTagged { tag: &'a str, variant_name: String },
InternallyTagged {
tag: &'a str,
variant_name: String,
},
Untagged,
}
@@ -763,23 +775,16 @@ fn serialize_struct_variant<'a>(
fields: &[Field],
name: &str,
) -> Fragment {
let (method, skip_method) = match context {
StructVariant::ExternallyTagged { .. } => {
(
quote!(_serde::ser::SerializeStructVariant::serialize_field),
quote!(_serde::ser::SerializeStructVariant::skip_field),
)
}
StructVariant::InternallyTagged { .. } |
StructVariant::Untagged => {
(
quote!(_serde::ser::SerializeStruct::serialize_field),
quote!(_serde::ser::SerializeStruct::skip_field),
)
}
let struct_trait = match context {
StructVariant::ExternallyTagged { .. } => (
StructTrait::SerializeStructVariant
),
StructVariant::InternallyTagged { .. } | StructVariant::Untagged => (
StructTrait::SerializeStruct
),
};
let serialize_fields = serialize_struct_visitor(fields, params, true, method, skip_method);
let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait);
let mut serialized_fields = fields
.iter()
@@ -789,16 +794,14 @@ fn serialize_struct_variant<'a>(
let let_mut = mut_if(serialized_fields.peek().is_some());
let len = serialized_fields
.map(
|field| {
let ident = field.ident.clone().expect("struct has unnamed fields");
.map(|field| {
let ident = field.ident.expect("struct has unnamed fields");
match field.attrs.skip_serializing_if() {
Some(path) => quote!(if #path(#ident) { 0 } else { 1 }),
None => quote!(1),
}
},
)
match field.attrs.skip_serializing_if() {
Some(path) => quote!(if #path(#ident) { 0 } else { 1 }),
None => quote!(1),
}
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
match context {
@@ -852,39 +855,42 @@ fn serialize_tuple_struct_visitor(
fields: &[Field],
params: &Parameters,
is_enum: bool,
func: Tokens,
tuple_trait: &TupleTrait,
) -> Vec<Tokens> {
fields
.iter()
.enumerate()
.map(
|(i, field)| {
let mut field_expr = if is_enum {
let id = Ident::new(format!("__field{}", i));
quote!(#id)
} else {
get_field(params, field, i)
};
.map(|(i, field)| {
let mut field_expr = if is_enum {
let id = Ident::new(&format!("__field{}", i), Span::def_site());
quote!(#id)
} else {
get_member(params, field, &Member::Unnamed(Index {
index: i as u32,
span: Span::call_site(),
}))
};
let skip = field
.attrs
.skip_serializing_if()
.map(|path| quote!(#path(#field_expr)));
let skip = field
.attrs
.skip_serializing_if()
.map(|path| quote!(#path(#field_expr)));
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
}
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
}
let ser = quote! {
try!(#func(&mut __serde_state, #field_expr));
};
let span = Span::def_site().located_at(field.original.span());
let func = tuple_trait.serialize_element(span);
let ser = quote! {
try!(#func(&mut __serde_state, #field_expr));
};
match skip {
None => ser,
Some(skip) => quote!(if !#skip { #ser }),
}
},
)
match skip {
None => ser,
Some(skip) => quote!(if !#skip { #ser }),
}
})
.collect()
}
@@ -892,39 +898,47 @@ fn serialize_struct_visitor(
fields: &[Field],
params: &Parameters,
is_enum: bool,
func: Tokens,
skip_func: Tokens,
struct_trait: &StructTrait,
) -> Vec<Tokens> {
fields
.iter()
.filter(|&field| !field.attrs.skip_serializing())
.map(
|field| {
let field_ident = field.ident.clone().expect("struct has unnamed field");
let mut field_expr = if is_enum {
quote!(#field_ident)
} else {
get_field(params, field, field_ident)
};
.map(|field| {
let field_ident = field.ident.expect("struct has unnamed field");
let key_expr = field.attrs.name().serialize_name();
let mut field_expr = if is_enum {
quote!(#field_ident)
} else {
get_member(params, field, &Member::Named(field_ident))
};
let skip = field
.attrs
.skip_serializing_if()
.map(|path| quote!(#path(#field_expr)));
let key_expr = field.attrs.name().serialize_name();
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
let skip = field
.attrs
.skip_serializing_if()
.map(|path| quote!(#path(#field_expr)));
if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
}
let span = Span::def_site().located_at(field.original.span());
let ser = if field.attrs.flatten() {
quote! {
try!(_serde::Serialize::serialize(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state)));
}
let ser = quote! {
} else {
let func = struct_trait.serialize_field(span);
quote! {
try!(#func(&mut __serde_state, #key_expr, #field_expr));
};
}
};
match skip {
None => ser,
Some(skip) => {
match skip {
None => ser,
Some(skip) => {
if let Some(skip_func) = struct_trait.skip_field(span) {
quote! {
if !#skip {
#ser
@@ -932,59 +946,73 @@ fn serialize_struct_visitor(
try!(#skip_func(&mut __serde_state, #key_expr));
}
}
} else {
quote! {
if !#skip {
#ser
}
}
}
}
},
)
}
})
.collect()
}
fn wrap_serialize_field_with(
params: &Parameters,
field_ty: &syn::Ty,
serialize_with: &syn::Path,
field_expr: Tokens,
field_ty: &syn::Type,
serialize_with: &syn::ExprPath,
field_expr: &Tokens,
) -> Tokens {
wrap_serialize_with(params,
serialize_with,
&[field_ty],
&[quote!(#field_expr)])
wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)])
}
fn wrap_serialize_variant_with(
params: &Parameters,
serialize_with: &syn::Path,
serialize_with: &syn::ExprPath,
variant: &Variant,
) -> Tokens {
let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect();
let field_exprs: Vec<_> = variant.fields.iter()
let field_exprs: Vec<_> = variant
.fields
.iter()
.enumerate()
.map(|(i, field)| {
let id = field.ident.as_ref().map_or_else(|| Ident::new(format!("__field{}", i)),
|id| id.clone());
let id = field
.ident
.unwrap_or_else(|| Ident::new(&format!("__field{}", i), Span::def_site()));
quote!(#id)
})
.collect();
wrap_serialize_with(params, serialize_with, field_tys.as_slice(), field_exprs.as_slice())
wrap_serialize_with(
params,
serialize_with,
field_tys.as_slice(),
field_exprs.as_slice(),
)
}
fn wrap_serialize_with(
params: &Parameters,
serialize_with: &syn::Path,
field_tys: &[&syn::Ty],
serialize_with: &syn::ExprPath,
field_tys: &[&syn::Type],
field_exprs: &[Tokens],
) -> Tokens {
let this = &params.this;
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
let wrapper_generics = if field_exprs.len() == 0 {
let wrapper_generics = if field_exprs.is_empty() {
params.generics.clone()
} else {
bound::with_lifetime_bound(&params.generics, "'__a")
};
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
let field_access = (0..field_exprs.len()).map(|n| Ident::new(format!("{}", n)));
let field_access = (0..field_exprs.len()).map(|n| Member::Unnamed(Index {
index: n as u32,
span: Span::call_site(),
}));
quote!({
struct __SerializeWith #wrapper_impl_generics #where_clause {
@@ -1014,23 +1042,23 @@ fn wrap_serialize_with(
//
// where we want to omit the `mut` to avoid a warning.
fn mut_if(is_mut: bool) -> Option<Tokens> {
if is_mut { Some(quote!(mut)) } else { None }
if is_mut {
Some(quote!(mut))
} else {
None
}
}
fn get_field<I>(params: &Parameters, field: &Field, ident: I) -> Tokens
where
I: Into<Ident>,
{
fn get_member(params: &Parameters, field: &Field, member: &Member) -> Tokens {
let self_var = &params.self_var;
match (params.is_remote, field.attrs.getter()) {
(false, None) => {
let ident = ident.into();
quote!(&#self_var.#ident)
quote_spanned!(Span::call_site()=> &#self_var.#member)
}
(true, None) => {
let inner = quote_spanned!(Span::call_site()=> &#self_var.#member);
let ty = field.ty;
let ident = ident.into();
quote!(_serde::private::ser::constrain::<#ty>(&#self_var.#ident))
quote!(_serde::private::ser::constrain::<#ty>(#inner))
}
(true, Some(getter)) => {
let ty = field.ty;
@@ -1041,3 +1069,59 @@ where
}
}
}
enum StructTrait {
SerializeMap,
SerializeStruct,
SerializeStructVariant,
}
impl StructTrait {
fn serialize_field(&self, span: Span) -> Tokens {
match *self {
StructTrait::SerializeMap => {
quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry)
}
StructTrait::SerializeStruct => {
quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field)
}
StructTrait::SerializeStructVariant => {
quote_spanned!(span=> _serde::ser::SerializeStructVariant::serialize_field)
}
}
}
fn skip_field(&self, span: Span) -> Option<Tokens> {
match *self {
StructTrait::SerializeMap => None,
StructTrait::SerializeStruct => Some({
quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)
}),
StructTrait::SerializeStructVariant => Some({
quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)
})
}
}
}
enum TupleTrait {
SerializeTuple,
SerializeTupleStruct,
SerializeTupleVariant,
}
impl TupleTrait {
fn serialize_element(&self, span: Span) -> Tokens {
match *self {
TupleTrait::SerializeTuple => {
quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element)
}
TupleTrait::SerializeTupleStruct => {
quote_spanned!(span=> _serde::ser::SerializeTupleStruct::serialize_field)
}
TupleTrait::SerializeTupleVariant => {
quote_spanned!(span=> _serde::ser::SerializeTupleVariant::serialize_field)
}
}
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive_internals"
version = "0.17.0" # remember to update html_root_url
version = "0.22.2" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "AST representation used by Serde derive macros. Unstable."
@@ -12,8 +12,8 @@ readme = "README.md"
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
[dependencies]
syn = { version = "0.11.10", default-features = false, features = ["parsing"] }
synom = "0.11"
proc-macro2 = "0.2"
syn = { version = "0.12", default-features = false, features = ["derive", "parsing", "clone-impls"] }
[badges]
travis-ci = { repository = "serde-rs/serde" }
+85 -57
View File
@@ -10,15 +10,16 @@ use syn;
use attr;
use check;
use Ctxt;
use syn::punctuated::Punctuated;
pub struct Container<'a> {
pub ident: syn::Ident,
pub attrs: attr::Container,
pub body: Body<'a>,
pub data: Data<'a>,
pub generics: &'a syn::Generics,
}
pub enum Body<'a> {
pub enum Data<'a> {
Enum(Vec<Variant<'a>>),
Struct(Style, Vec<Field<'a>>),
}
@@ -33,7 +34,8 @@ pub struct Variant<'a> {
pub struct Field<'a> {
pub ident: Option<syn::Ident>,
pub attrs: attr::Field,
pub ty: &'a syn::Ty,
pub ty: &'a syn::Type,
pub original: &'a syn::Field,
}
#[derive(Copy, Clone)]
@@ -46,36 +48,45 @@ pub enum Style {
impl<'a> Container<'a> {
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput) -> Container<'a> {
let attrs = attr::Container::from_ast(cx, item);
let mut attrs = attr::Container::from_ast(cx, item);
let mut body = match item.body {
syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)),
syn::Body::Struct(ref variant_data) => {
let (style, fields) = struct_from_ast(cx, variant_data, None);
Body::Struct(style, fields)
let mut data = match item.data {
syn::Data::Enum(ref data) => {
Data::Enum(enum_from_ast(cx, &data.variants, attrs.default()))
}
syn::Data::Struct(ref data) => {
let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default());
Data::Struct(style, fields)
}
syn::Data::Union(_) => {
panic!("Serde does not support derive for unions");
}
};
match body {
Body::Enum(ref mut variants) => {
for ref mut variant in variants {
variant.attrs.rename_by_rule(attrs.rename_all());
for ref mut field in &mut variant.fields {
field.attrs.rename_by_rule(variant.attrs.rename_all());
}
let mut has_flatten = false;
match data {
Data::Enum(ref mut variants) => for variant in variants {
variant.attrs.rename_by_rule(attrs.rename_all());
for field in &mut variant.fields {
field.attrs.rename_by_rule(variant.attrs.rename_all());
}
}
Body::Struct(_, ref mut fields) => {
for field in fields {
field.attrs.rename_by_rule(attrs.rename_all());
},
Data::Struct(_, ref mut fields) => for field in fields {
if field.attrs.flatten() {
has_flatten = true;
}
}
field.attrs.rename_by_rule(attrs.rename_all());
},
}
if has_flatten {
attrs.mark_has_flatten();
}
let item = Container {
ident: item.ident.clone(),
ident: item.ident,
attrs: attrs,
body: body,
data: data,
generics: &item.generics,
};
check::check(cx, &item);
@@ -83,13 +94,13 @@ impl<'a> Container<'a> {
}
}
impl<'a> Body<'a> {
impl<'a> Data<'a> {
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
match *self {
Body::Enum(ref variants) => {
Data::Enum(ref variants) => {
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
}
Body::Struct(_, ref fields) => Box::new(fields.iter()),
Data::Struct(_, ref fields) => Box::new(fields.iter()),
}
}
@@ -98,47 +109,64 @@ impl<'a> Body<'a> {
}
}
fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>> {
fn enum_from_ast<'a>(
cx: &Ctxt,
variants: &'a Punctuated<syn::Variant, Token![,]>,
container_default: &attr::Default,
) -> Vec<Variant<'a>> {
variants
.iter()
.map(
|variant| {
let attrs = attr::Variant::from_ast(cx, variant);
let (style, fields) = struct_from_ast(cx, &variant.data, Some(&attrs));
Variant {
ident: variant.ident.clone(),
attrs: attrs,
style: style,
fields: fields,
}
},
)
.map(|variant| {
let attrs = attr::Variant::from_ast(cx, variant);
let (style, fields) =
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
Variant {
ident: variant.ident,
attrs: attrs,
style: style,
fields: fields,
}
})
.collect()
}
fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData, attrs: Option<&attr::Variant>) -> (Style, Vec<Field<'a>>) {
match *data {
syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields, attrs)),
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
(Style::Newtype, fields_from_ast(cx, fields, attrs))
}
syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields, attrs)),
syn::VariantData::Unit => (Style::Unit, Vec::new()),
fn struct_from_ast<'a>(
cx: &Ctxt,
fields: &'a syn::Fields,
attrs: Option<&attr::Variant>,
container_default: &attr::Default,
) -> (Style, Vec<Field<'a>>) {
match *fields {
syn::Fields::Named(ref fields) => (
Style::Struct,
fields_from_ast(cx, &fields.named, attrs, container_default),
),
syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => (
Style::Newtype,
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
),
syn::Fields::Unnamed(ref fields) => (
Style::Tuple,
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
),
syn::Fields::Unit => (Style::Unit, Vec::new()),
}
}
fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field], attrs: Option<&attr::Variant>) -> Vec<Field<'a>> {
fn fields_from_ast<'a>(
cx: &Ctxt,
fields: &'a Punctuated<syn::Field, Token![,]>,
attrs: Option<&attr::Variant>,
container_default: &attr::Default,
) -> Vec<Field<'a>> {
fields
.iter()
.enumerate()
.map(
|(i, field)| {
Field {
ident: field.ident.clone(),
attrs: attr::Field::from_ast(cx, i, field, attrs),
ty: &field.ty,
}
},
)
.map(|(i, field)| Field {
ident: field.ident,
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
ty: &field.ty,
original: field,
})
.collect()
}
File diff suppressed because it is too large Load Diff
+64 -20
View File
@@ -7,19 +7,21 @@
// except according to those terms.
// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726
#[allow(unused_imports)]
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
use std::str::FromStr;
use self::RenameRule::*;
#[derive(Debug, PartialEq)]
#[derive(PartialEq)]
pub enum RenameRule {
/// Don't apply a default rename rule.
None,
/// Rename direct children to "lowercase" style.
LowerCase,
/// Rename direct children to "UPPERCASE" style.
UPPERCASE,
/// Rename direct children to "PascalCase" style, as typically used for enum variants.
PascalCase,
/// Rename direct children to "camelCase" style.
@@ -31,7 +33,7 @@ pub enum RenameRule {
/// Rename direct children to "kebab-case" style.
KebabCase,
/// Rename direct children to "SCREAMING-KEBAB-CASE" style.
ScreamingKebabCase
ScreamingKebabCase,
}
impl RenameRule {
@@ -39,6 +41,7 @@ impl RenameRule {
match *self {
None | PascalCase => variant.to_owned(),
LowerCase => variant.to_ascii_lowercase(),
UPPERCASE => variant.to_ascii_uppercase(),
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
SnakeCase => {
let mut snake = String::new();
@@ -52,13 +55,16 @@ impl RenameRule {
}
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
ScreamingKebabCase => ScreamingSnakeCase.apply_to_variant(variant).replace('_', "-")
ScreamingKebabCase => ScreamingSnakeCase
.apply_to_variant(variant)
.replace('_', "-"),
}
}
pub fn apply_to_field(&self, field: &str) -> String {
match *self {
None | LowerCase | SnakeCase => field.to_owned(),
UPPERCASE => field.to_ascii_uppercase(),
PascalCase => {
let mut pascal = String::new();
let mut capitalize = true;
@@ -80,7 +86,7 @@ impl RenameRule {
}
ScreamingSnakeCase => field.to_ascii_uppercase(),
KebabCase => field.replace('_', "-"),
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-")
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
}
}
}
@@ -91,6 +97,7 @@ impl FromStr for RenameRule {
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),
@@ -104,34 +111,71 @@ impl FromStr for RenameRule {
#[test]
fn rename_variants() {
for &(original, lower, camel, snake, screaming, kebab, screaming_kebab) in
&[
("Outcome", "outcome", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"),
("VeryTasty", "verytasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"),
("A", "a", "a", "a", "A", "a", "A"),
("Z42", "z42", "z42", "z42", "Z42", "z42", "Z42"),
] {
for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[
(
"Outcome",
"outcome",
"OUTCOME",
"outcome",
"outcome",
"OUTCOME",
"outcome",
"OUTCOME",
),
(
"VeryTasty",
"verytasty",
"VERYTASTY",
"veryTasty",
"very_tasty",
"VERY_TASTY",
"very-tasty",
"VERY-TASTY",
),
("A", "a", "A", "a", "a", "A", "a", "A"),
("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"),
] {
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!(PascalCase.apply_to_variant(original), original);
assert_eq!(CamelCase.apply_to_variant(original), camel);
assert_eq!(SnakeCase.apply_to_variant(original), snake);
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
assert_eq!(KebabCase.apply_to_variant(original), kebab);
assert_eq!(ScreamingKebabCase.apply_to_variant(original), screaming_kebab);
assert_eq!(
ScreamingKebabCase.apply_to_variant(original),
screaming_kebab
);
}
}
#[test]
fn rename_fields() {
for &(original, pascal, camel, screaming, kebab, screaming_kebab) in
&[
("outcome", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"),
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"),
("a", "A", "a", "A", "a", "A"),
("z42", "Z42", "z42", "Z42", "z42", "Z42"),
] {
for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[
(
"outcome",
"OUTCOME",
"Outcome",
"outcome",
"OUTCOME",
"outcome",
"OUTCOME",
),
(
"very_tasty",
"VERY_TASTY",
"VeryTasty",
"veryTasty",
"VERY_TASTY",
"very-tasty",
"VERY-TASTY",
),
("a", "A", "A", "a", "A", "a", "A"),
("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!(PascalCase.apply_to_field(original), pascal);
assert_eq!(CamelCase.apply_to_field(original), camel);
assert_eq!(SnakeCase.apply_to_field(original), original);
+152 -34
View File
@@ -6,38 +6,73 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{Body, Container, Style};
use attr::Identifier;
use ast::{Data, Container, Style};
use attr::{Identifier, EnumTag};
use Ctxt;
/// Cross-cutting checks that require looking at more than a single attrs
/// object. Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &Container) {
check_getter(cx, cont);
check_flatten(cx, cont);
check_identifier(cx, cont);
check_variant_skip_attrs(cx, cont);
check_internal_tag_field_name_conflict(cx, cont);
check_adjacent_tag_conflict(cx, cont);
}
/// Getters are only allowed inside structs (not enums) with the `remote`
/// attribute.
fn check_getter(cx: &Ctxt, cont: &Container) {
match cont.body {
Body::Enum(_) => {
if cont.body.has_getter() {
match cont.data {
Data::Enum(_) => {
if cont.data.has_getter() {
cx.error("#[serde(getter = \"...\")] is not allowed in an enum");
}
}
Body::Struct(_, _) => {
if cont.body.has_getter() && cont.attrs.remote().is_none() {
Data::Struct(_, _) => {
if cont.data.has_getter() && cont.attrs.remote().is_none() {
cx.error(
"#[serde(getter = \"...\")] can only be used in structs \
that have #[serde(remote = \"...\")]",
that have #[serde(remote = \"...\")]",
);
}
}
}
}
/// Flattening has some restrictions we can test.
fn check_flatten(cx: &Ctxt, cont: &Container) {
match cont.data {
Data::Enum(_) => {
assert!(!cont.attrs.has_flatten());
}
Data::Struct(_, _) => {
for field in cont.data.all_fields() {
if !field.attrs.flatten() {
continue;
}
if field.attrs.skip_serializing() {
cx.error(
"#[serde(flatten] can not be combined with \
#[serde(skip_serializing)]"
);
} else if field.attrs.skip_serializing_if().is_some() {
cx.error(
"#[serde(flatten] can not be combined with \
#[serde(skip_serializing_if = \"...\")]"
);
} else if field.attrs.skip_deserializing() {
cx.error(
"#[serde(flatten] can not be combined with \
#[serde(skip_deserializing)]"
);
}
}
}
}
}
/// The `other` attribute must be used at most once and it must be the last
/// variant of an enum that has the `field_identifier` attribute.
///
@@ -45,18 +80,21 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
/// `field_identifier` all but possibly one variant must be unit variants. The
/// last variant may be a newtype variant which is an implicit "other" case.
fn check_identifier(cx: &Ctxt, cont: &Container) {
let variants = match cont.body {
Body::Enum(ref variants) => variants,
Body::Struct(_, _) => {
let variants = match cont.data {
Data::Enum(ref variants) => variants,
Data::Struct(_, _) => {
return;
}
};
for (i, variant) in variants.iter().enumerate() {
match (variant.style, cont.attrs.identifier(), variant.attrs.other()) {
match (
variant.style,
cont.attrs.identifier(),
variant.attrs.other(),
) {
// The `other` attribute may only be used in a field_identifier.
(_, Identifier::Variant, true) |
(_, Identifier::No, true) => {
(_, Identifier::Variant, true) | (_, Identifier::No, true) => {
cx.error("#[serde(other)] may only be used inside a field_identifier");
}
@@ -99,9 +137,9 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
/// Skip-(de)serializing attributes are not allowed on variants marked
/// (de)serialize_with.
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
let variants = match cont.body {
Body::Enum(ref variants) => variants,
Body::Struct(_, _) => {
let variants = match cont.data {
Data::Enum(ref variants) => variants,
Data::Struct(_, _) => {
return;
}
};
@@ -109,44 +147,124 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
for variant in variants.iter() {
if variant.attrs.serialize_with().is_some() {
if variant.attrs.skip_serializing() {
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
#[serde(skip_serializing)]", variant.ident));
cx.error(format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \
#[serde(skip_serializing)]",
variant.ident
));
}
for (i, field) in variant.fields.iter().enumerate() {
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i),
|ident| format!("`{}`", ident));
let ident = field
.ident
.as_ref()
.map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));
if field.attrs.skip_serializing() {
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing)]",
variant.ident, ident));
cx.error(format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing)]",
variant.ident, ident
));
}
if field.attrs.skip_serializing_if().is_some() {
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing_if)]",
variant.ident, ident));
cx.error(format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing_if)]",
variant.ident, ident
));
}
}
}
if variant.attrs.deserialize_with().is_some() {
if variant.attrs.skip_deserializing() {
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] and \
#[serde(skip_deserializing)]", variant.ident));
cx.error(format!(
"variant `{}` cannot have both #[serde(deserialize_with)] and \
#[serde(skip_deserializing)]",
variant.ident
));
}
for (i, field) in variant.fields.iter().enumerate() {
if field.attrs.skip_deserializing() {
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i),
|ident| format!("`{}`", ident));
let ident = field
.ident
.as_ref()
.map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] \
and a field {} marked with #[serde(skip_deserializing)]",
variant.ident, ident));
cx.error(format!(
"variant `{}` cannot have both #[serde(deserialize_with)] \
and a field {} marked with #[serde(skip_deserializing)]",
variant.ident, ident
));
}
}
}
}
}
/// The tag of an internally-tagged struct variant must not be
/// the same as either one of its fields, as this would result in
/// duplicate keys in the serialized output and/or ambiguity in
/// the to-be-deserialized input.
fn check_internal_tag_field_name_conflict(
cx: &Ctxt,
cont: &Container,
) {
let variants = match cont.data {
Data::Enum(ref variants) => variants,
Data::Struct(_, _) => return,
};
let tag = match *cont.attrs.tag() {
EnumTag::Internal { ref tag } => tag.as_str(),
EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
};
let diagnose_conflict = || {
let message = format!(
"variant field name `{}` conflicts with internal tag",
tag
);
cx.error(message);
};
for variant in variants {
match variant.style {
Style::Struct => {
for field in &variant.fields {
let check_ser = !field.attrs.skip_serializing();
let check_de = !field.attrs.skip_deserializing();
let name = field.attrs.name();
let ser_name = name.serialize_name();
let de_name = name.deserialize_name();
if check_ser && ser_name == tag || check_de && de_name == tag {
diagnose_conflict();
return;
}
}
},
Style::Unit | Style::Newtype | Style::Tuple => {},
}
}
}
/// In the case of adjacently-tagged enums, the type and the
/// contents tag must differ, for the same reason.
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
let (type_tag, content_tag) = match *cont.attrs.tag() {
EnumTag::Adjacent { ref tag, ref content } => (tag, content),
EnumTag::Internal { .. } | EnumTag::External | EnumTag::None => return,
};
if type_tag == content_tag {
let message = format!(
"enum tags `{}` for type and content conflict with each other",
type_tag
);
cx.error(message);
}
}
+5 -2
View File
@@ -8,6 +8,7 @@
use std::fmt::Display;
use std::cell::RefCell;
use std::thread;
#[derive(Default)]
pub struct Ctxt {
@@ -16,7 +17,9 @@ pub struct Ctxt {
impl Ctxt {
pub fn new() -> Self {
Ctxt { errors: RefCell::new(Some(Vec::new())) }
Ctxt {
errors: RefCell::new(Some(Vec::new())),
}
}
pub fn error<T: Display>(&self, msg: T) {
@@ -46,7 +49,7 @@ impl Ctxt {
impl Drop for Ctxt {
fn drop(&mut self) {
if self.errors.borrow().is_some() {
if !thread::panicking() && self.errors.borrow().is_some() {
panic!("forgot to check for errors");
}
}
+6 -3
View File
@@ -6,11 +6,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.17.0")]
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.22.2")]
#![cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity, doc_markdown, match_same_arms,
redundant_field_names))]
extern crate syn;
#[macro_use]
extern crate synom;
extern crate syn;
extern crate proc_macro2;
pub mod ast;
pub mod attr;
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "1.0.19" # remember to update html_root_url
version = "1.0.36" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations"
+19 -3
View File
@@ -184,11 +184,27 @@ where
T: Deserialize<'de> + PartialEq + Debug,
{
let mut de = Deserializer::new(tokens);
match T::deserialize(&mut de) {
Ok(v) => assert_eq!(v, *value),
let mut deserialized_val = match T::deserialize(&mut de) {
Ok(v) => {
assert_eq!(v, *value);
v
}
Err(e) => panic!("tokens failed to deserialize: {}", e),
};
if de.remaining() > 0 {
panic!("{} remaining tokens", de.remaining());
}
// Do the same thing for deserialize_in_place. This isn't *great* because a
// no-op impl of deserialize_in_place can technically succeed here. Still,
// this should catch a lot of junk.
let mut de = Deserializer::new(tokens);
match T::deserialize_in_place(&mut de, &mut deserialized_val) {
Ok(()) => {
assert_eq!(deserialized_val, *value);
}
Err(e) => panic!("tokens failed to deserialize_in_place: {}", e),
}
if de.remaining() > 0 {
panic!("{} remaining tokens", de.remaining());
}
@@ -215,7 +231,7 @@ where
///
/// assert_de_tokens_error::<S>(
/// &[
/// Token::Struct { name: "S", len: 1 },
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("x"),
/// ],
/// "unknown field `x`, expected `a` or `b`",
+15 -12
View File
@@ -11,17 +11,17 @@ pub struct Compact<T: ?Sized>(T);
/// Trait to determine whether a value is represented in human-readable or
/// compact form.
///
///
/// ```
/// extern crate serde;
/// extern crate serde_test;
///
///
/// use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// use serde_test::{Configure, Token, assert_tokens};
///
///
/// #[derive(Debug, PartialEq)]
/// struct Example(u8, u8);
///
///
/// impl Serialize for Example {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer,
@@ -33,7 +33,7 @@ pub struct Compact<T: ?Sized>(T);
/// }
/// }
/// }
///
///
/// impl<'de> Deserialize<'de> for Example {
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
/// where D: Deserializer<'de>,
@@ -52,7 +52,7 @@ pub struct Compact<T: ?Sized>(T);
/// }
/// }
/// }
///
///
/// fn main() {
/// assert_tokens(
/// &Example(1, 0).compact(),
@@ -73,11 +73,17 @@ pub struct Compact<T: ?Sized>(T);
/// ```
pub trait Configure {
/// Marks `self` as using `is_human_readable == true`
fn readable(self) -> Readable<Self> where Self: Sized {
fn readable(self) -> Readable<Self>
where
Self: Sized,
{
Readable(self)
}
/// Marks `self` as using `is_human_readable == false`
fn compact(self) -> Compact<Self> where Self: Sized {
fn compact(self) -> Compact<Self>
where
Self: Sized,
{
Compact(self)
}
}
@@ -158,7 +164,6 @@ where
}
}
macro_rules! forward_method {
($name: ident (self $(, $arg: ident : $arg_type: ty)* ) -> $return_type: ty) => {
fn $name (self $(, $arg : $arg_type)* ) -> $return_type {
@@ -455,8 +460,7 @@ macro_rules! impl_serializer {
impl_serializer!(Readable, true);
impl_serializer!(Compact, false);
use serde::de::{Visitor, EnumAccess, VariantAccess, MapAccess, DeserializeSeed, SeqAccess, Error};
use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor};
macro_rules! forward_deserialize_methods {
( $wrapper : ident ( $( $name: ident ),* ) ) => {
@@ -468,7 +472,6 @@ macro_rules! forward_deserialize_methods {
};
}
macro_rules! impl_deserializer {
($wrapper : ident, $is_human_readable : expr) => {
impl <'de, D> Deserializer<'de> for $wrapper<D> where D: Deserializer<'de> {
+64 -50
View File
@@ -95,15 +95,11 @@ impl<'de> Deserializer<'de> {
where
V: Visitor<'de>,
{
let value = try!(
visitor.visit_seq(
DeserializerSeqVisitor {
de: self,
len: len,
end: end,
},
)
);
let value = try!(visitor.visit_seq(DeserializerSeqVisitor {
de: self,
len: len,
end: end,
},));
assert_next_token!(self, end);
Ok(value)
}
@@ -117,15 +113,11 @@ impl<'de> Deserializer<'de> {
where
V: Visitor<'de>,
{
let value = try!(
visitor.visit_map(
DeserializerMapVisitor {
de: self,
len: len,
end: end,
},
)
);
let value = try!(visitor.visit_map(DeserializerMapVisitor {
de: self,
len: len,
end: end,
},));
assert_next_token!(self, end);
Ok(value)
}
@@ -169,7 +161,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
Token::NewtypeStruct { .. } => visitor.visit_newtype_struct(self),
Token::Seq { len } => self.visit_seq(len, Token::SeqEnd, visitor),
Token::Tuple { len } => self.visit_seq(Some(len), Token::TupleEnd, visitor),
Token::TupleStruct { len, .. } => self.visit_seq(Some(len), Token::TupleStructEnd, visitor),
Token::TupleStruct { len, .. } => {
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
}
Token::Map { len } => self.visit_map(len, Token::MapEnd, visitor),
Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor),
Token::Enum { .. } => {
@@ -195,17 +189,28 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
}
}
Token::UnitVariant { variant, .. } => visitor.visit_str(variant),
Token::NewtypeVariant { variant, .. } => {
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Any),)
}
Token::TupleVariant { variant, .. } => {
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Seq),)
}
Token::StructVariant { variant, .. } => {
visitor.visit_map(EnumMapVisitor::new(self, Token::Str(variant), EnumFormat::Map),)
}
Token::SeqEnd | Token::TupleEnd | Token::TupleStructEnd | Token::MapEnd |
Token::StructEnd | Token::TupleVariantEnd | Token::StructVariantEnd => {
Token::NewtypeVariant { variant, .. } => visitor.visit_map(EnumMapVisitor::new(
self,
Token::Str(variant),
EnumFormat::Any,
)),
Token::TupleVariant { variant, .. } => visitor.visit_map(EnumMapVisitor::new(
self,
Token::Str(variant),
EnumFormat::Seq,
)),
Token::StructVariant { variant, .. } => visitor.visit_map(EnumMapVisitor::new(
self,
Token::Str(variant),
EnumFormat::Map,
)),
Token::SeqEnd
| Token::TupleEnd
| Token::TupleStructEnd
| Token::MapEnd
| Token::StructEnd
| Token::TupleVariantEnd
| Token::StructVariantEnd => {
unexpected!(token);
}
}
@@ -216,8 +221,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: Visitor<'de>,
{
match self.peek_token() {
Token::Unit |
Token::None => {
Token::Unit | Token::None => {
self.next_token();
visitor.visit_none()
}
@@ -244,10 +248,11 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
visitor.visit_enum(DeserializerEnumVisitor { de: self })
}
Token::UnitVariant { name: n, .. } |
Token::NewtypeVariant { name: n, .. } |
Token::TupleVariant { name: n, .. } |
Token::StructVariant { name: n, .. } if name == n => {
Token::UnitVariant { name: n, .. }
| Token::NewtypeVariant { name: n, .. }
| Token::TupleVariant { name: n, .. }
| Token::StructVariant { name: n, .. } if name == n =>
{
visitor.visit_enum(DeserializerEnumVisitor { de: self })
}
_ => {
@@ -269,7 +274,11 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
}
}
fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value, Error>
fn deserialize_newtype_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
@@ -287,8 +296,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: Visitor<'de>,
{
match self.peek_token() {
Token::Unit |
Token::UnitStruct { .. } => {
Token::Unit | Token::UnitStruct { .. } => {
self.next_token();
visitor.visit_unit()
}
@@ -448,10 +456,10 @@ impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
V: DeserializeSeed<'de>,
{
match self.de.peek_token() {
Token::UnitVariant { variant: v, .. } |
Token::NewtypeVariant { variant: v, .. } |
Token::TupleVariant { variant: v, .. } |
Token::StructVariant { variant: v, .. } => {
Token::UnitVariant { variant: v, .. }
| Token::NewtypeVariant { variant: v, .. }
| Token::TupleVariant { variant: v, .. }
| Token::StructVariant { variant: v, .. } => {
let de = v.into_deserializer();
let value = try!(seed.deserialize(de));
Ok((value, self))
@@ -505,7 +513,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
unexpected!(token);
}
}
Token::Seq { len: Some(enum_len) } => {
Token::Seq {
len: Some(enum_len),
} => {
let token = self.de.next_token();
if len == enum_len {
@@ -518,7 +528,11 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
}
}
fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value, Error>
fn struct_variant<V>(
self,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
@@ -533,7 +547,9 @@ impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
unexpected!(token);
}
}
Token::Map { len: Some(enum_len) } => {
Token::Map {
len: Some(enum_len),
} => {
let token = self.de.next_token();
if fields.len() == enum_len {
@@ -581,10 +597,8 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
{
match self.variant.take() {
Some(Token::Str(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
Some(Token::Bytes(variant)) => {
seed.deserialize(BytesDeserializer { value: variant })
.map(Some)
}
Some(Token::Bytes(variant)) => seed.deserialize(BytesDeserializer { value: variant })
.map(Some),
Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
Some(other) => unexpected!(other),
None => Ok(None),
+7 -3
View File
@@ -9,7 +9,7 @@
use std::error;
use std::fmt::{self, Display};
use serde::{ser, de};
use serde::{de, ser};
#[derive(Clone, Debug)]
pub struct Error {
@@ -18,13 +18,17 @@ pub struct Error {
impl ser::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
Error { msg: msg.to_string() }
Error {
msg: msg.to_string(),
}
}
}
impl de::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
Error { msg: msg.to_string() }
Error {
msg: msg.to_string(),
}
}
}
+5 -8
View File
@@ -53,7 +53,7 @@
//! # use serde::ser::{Serialize, Serializer, SerializeMap};
//! # use serde::de::{Deserialize, Deserializer, Visitor, MapAccess};
//! #
//! # // Dumb immitation of LinkedHashMap.
//! # // Dumb imitation of LinkedHashMap.
//! # #[derive(PartialEq, Debug)]
//! # struct LinkedHashMap<K, V>(Vec<(K, V)>);
//! #
@@ -155,17 +155,14 @@
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.19")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.36")]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
missing_docs_in_private_items,
stutter,
use_self,
))]
#![cfg_attr(feature = "cargo-clippy",
allow(empty_line_after_outer_attr, missing_docs_in_private_items,
redundant_field_names, stutter, use_debug, use_self))]
#[macro_use]
extern crate serde;
+24 -6
View File
@@ -40,25 +40,43 @@ impl<'a> Serializer<'a> {
macro_rules! assert_next_token {
($ser:expr, $expected:ident) => {
assert_next_token!($ser, $expected, Token::$expected, true);
assert_next_token!($ser, stringify!($expected), Token::$expected, true);
};
($ser:expr, $expected:ident($v:expr)) => {
assert_next_token!($ser, $expected, Token::$expected(v), v == $v);
assert_next_token!(
$ser,
format_args!("{}({:?})", stringify!($expected), $v),
Token::$expected(v),
v == $v
);
};
($ser:expr, $expected:ident { $($k:ident),* }) => {
let compare = ($($k,)*);
assert_next_token!($ser, $expected, Token::$expected { $($k),* }, ($($k,)*) == compare);
let field_format = || {
use std::fmt::Write;
let mut buffer = String::new();
$(
write!(&mut buffer, "{}: {:?}, ", stringify!($k), $k).unwrap();
)*
buffer
};
assert_next_token!(
$ser,
format_args!("{} {{ {}}}", stringify!($expected), field_format()),
Token::$expected { $($k),* },
($($k,)*) == compare
);
};
($ser:expr, $expected:ident, $pat:pat, $guard:expr) => {
($ser:expr, $expected:expr, $pat:pat, $guard:expr) => {
match $ser.next_token() {
Some($pat) if $guard => {}
Some(other) => {
panic!("expected Token::{} but serialized as {}",
stringify!($expected), other);
$expected, other);
}
None => {
panic!("expected Token::{} after end of serialized tokens",
stringify!($expected));
$expected);
}
}
};
+18 -4
View File
@@ -232,7 +232,10 @@ pub enum Token {
/// assert_tokens(&a, &[Token::UnitVariant { name: "E", variant: "A" }]);
/// # }
/// ```
UnitVariant { name: &'static str, variant: &'static str },
UnitVariant {
name: &'static str,
variant: &'static str,
},
/// The header to a serialized newtype struct of the given name.
///
@@ -286,7 +289,10 @@ pub enum Token {
/// ]);
/// # }
/// ```
NewtypeVariant { name: &'static str, variant: &'static str },
NewtypeVariant {
name: &'static str,
variant: &'static str,
},
/// The header to a sequence.
///
@@ -391,7 +397,11 @@ pub enum Token {
/// ]);
/// # }
/// ```
TupleVariant { name: &'static str, variant: &'static str, len: usize },
TupleVariant {
name: &'static str,
variant: &'static str,
len: usize,
},
/// An indicator of the end of a tuple variant.
TupleVariantEnd,
@@ -488,7 +498,11 @@ pub enum Token {
/// ]);
/// # }
/// ```
StructVariant { name: &'static str, variant: &'static str, len: usize },
StructVariant {
name: &'static str,
variant: &'static str,
len: usize,
},
/// An indicator of the end of a struct variant.
StructVariantEnd,
+3 -2
View File
@@ -9,10 +9,11 @@ unstable = ["serde/unstable", "compiletest_rs"]
[dev-dependencies]
fnv = "1.0"
proc-macro2 = "0.2"
rustc-serialize = "0.3.16"
serde = { path = "../serde", features = ["rc"] }
serde_derive = { path = "../serde_derive" }
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
serde_test = { path = "../serde_test" }
[dependencies]
compiletest_rs = { version = "0.2", optional = true }
compiletest_rs = { version = "0.3", optional = true }
@@ -0,0 +1,20 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
#[serde(tag = "conflict", content = "conflict")]
//~^^ HELP: enum tags `conflict` for type and content conflict with each other
enum E {
A,
B,
}
fn main() {}
@@ -0,0 +1,24 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
//~^ HELP: #[serde(flatten] can not be combined with #[serde(skip_deserializing)]
struct Foo {
#[serde(flatten, skip_deserializing)]
other: Other,
}
#[derive(Deserialize)]
struct Other {
x: u32
}
fn main() {}
@@ -0,0 +1,24 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
//~^ HELP: #[serde(flatten] can not be combined with #[serde(skip_serializing_if = "...")]
struct Foo {
#[serde(flatten, skip_serializing_if="Option::is_none")]
other: Option<Other>,
}
#[derive(Serialize)]
struct Other {
x: u32
}
fn main() {}
@@ -0,0 +1,24 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
//~^ HELP: #[serde(flatten] can not be combined with #[serde(skip_serializing)]
struct Foo {
#[serde(flatten, skip_serializing)]
other: Other,
}
#[derive(Serialize)]
struct Other {
x: u32
}
fn main() {}
@@ -0,0 +1,22 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
#[serde(tag = "conflict")]
//~^^ HELP: variant field name `conflict` conflicts with internal tag
enum E {
A {
#[serde(rename = "conflict")]
x: (),
},
}
fn main() {}
File diff suppressed because it is too large Load Diff
+12 -12
View File
@@ -13,7 +13,7 @@ extern crate serde;
use serde::{Deserialize, Deserializer};
extern crate serde_test;
use serde_test::{Token, assert_de_tokens, assert_de_tokens_error};
use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};
use std::borrow::Cow;
@@ -87,18 +87,18 @@ fn test_struct() {
assert_de_tokens(
&Borrowing {
bs: "str",
bb: b"bytes",
},
bs: "str",
bb: b"bytes",
},
&[
Token::Struct { name: "Borrowing", len: 2 },
Token::Struct {
name: "Borrowing",
len: 2,
},
Token::BorrowedStr("bs"),
Token::BorrowedStr("str"),
Token::BorrowedStr("bb"),
Token::BorrowedBytes(b"bytes"),
Token::StructEnd,
],
);
@@ -115,14 +115,14 @@ fn test_cow() {
}
let tokens = &[
Token::Struct { name: "Cows", len: 2 },
Token::Struct {
name: "Cows",
len: 2,
},
Token::Str("copied"),
Token::BorrowedStr("copied"),
Token::Str("borrowed"),
Token::BorrowedStr("borrowed"),
Token::StructEnd,
];
+49 -13
View File
@@ -6,6 +6,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![cfg_attr(feature = "cargo-clippy", allow(decimal_literal_representation))]
#[macro_use]
extern crate serde_derive;
@@ -49,14 +51,16 @@ struct TupleStruct(i32, i32, i32);
struct Struct {
a: i32,
b: i32,
#[serde(skip_deserializing)] c: i32,
#[serde(skip_deserializing)]
c: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct StructDenyUnknown {
a: i32,
#[serde(skip_deserializing)] b: i32,
#[serde(skip_deserializing)]
b: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
@@ -77,13 +81,35 @@ impl Default for StructDefault<String> {
#[derive(PartialEq, Debug, Deserialize)]
struct StructSkipAll {
#[serde(skip_deserializing)] a: i32,
#[serde(skip_deserializing)]
a: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(default)]
struct StructSkipDefault {
#[serde(skip_deserializing)]
a: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(default)]
struct StructSkipDefaultGeneric<T> {
#[serde(skip_deserializing)]
t: T,
}
impl Default for StructSkipDefault {
fn default() -> Self {
StructSkipDefault { a: 16 }
}
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct StructSkipAllDenyUnknown {
#[serde(skip_deserializing)] a: i32,
#[serde(skip_deserializing)]
a: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
@@ -94,7 +120,11 @@ enum Enum {
Unit,
Simple(i32),
Seq(i32, i32, i32),
Map { a: i32, b: i32, c: i32 },
Map {
a: i32,
b: i32,
c: i32,
},
}
#[derive(PartialEq, Debug, Deserialize)]
@@ -538,7 +568,7 @@ declare_tests! {
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Struct { name: "Struct", len: 3 },
Token::Struct { name: "Struct", len: 2 },
Token::Str("a"),
Token::I32(1),
@@ -570,7 +600,7 @@ declare_tests! {
Token::MapEnd,
],
Struct { a: 1, b: 2, c: 0 } => &[
Token::Struct { name: "Struct", len: 3 },
Token::Struct { name: "Struct", len: 2 },
Token::Str("a"),
Token::I32(1),
@@ -591,7 +621,7 @@ declare_tests! {
Token::StructEnd,
],
StructSkipAll { a: 0 } => &[
Token::Struct { name: "StructSkipAll", len: 1 },
Token::Struct { name: "StructSkipAll", len: 0 },
Token::Str("a"),
Token::I32(1),
@@ -600,6 +630,12 @@ declare_tests! {
Token::StructEnd,
],
}
test_struct_skip_default {
StructSkipDefault { a: 16 } => &[
Token::Struct { name: "StructSkipDefault", len: 0 },
Token::StructEnd,
],
}
test_struct_skip_all_deny_unknown {
StructSkipAllDenyUnknown { a: 0 } => &[
Token::Struct { name: "StructSkipAllDenyUnknown", len: 0 },
@@ -608,7 +644,7 @@ declare_tests! {
}
test_struct_default {
StructDefault { a: 50, b: "overwritten".to_string() } => &[
Token::Struct { name: "StructDefault", len: 1 },
Token::Struct { name: "StructDefault", len: 2 },
Token::Str("a"),
Token::I32(50),
@@ -617,7 +653,7 @@ declare_tests! {
Token::StructEnd,
],
StructDefault { a: 100, b: "default".to_string() } => &[
Token::Struct { name: "StructDefault", len: 0 },
Token::Struct { name: "StructDefault", len: 2 },
Token::StructEnd,
],
}
@@ -954,7 +990,7 @@ fn test_cstr_internal_null_end() {
declare_error_tests! {
test_unknown_field<StructDenyUnknown> {
&[
Token::Struct { name: "StructDenyUnknown", len: 2 },
Token::Struct { name: "StructDenyUnknown", len: 1 },
Token::Str("a"),
Token::I32(0),
@@ -964,14 +1000,14 @@ declare_error_tests! {
}
test_skipped_field_is_unknown<StructDenyUnknown> {
&[
Token::Struct { name: "StructDenyUnknown", len: 2 },
Token::Struct { name: "StructDenyUnknown", len: 1 },
Token::Str("b"),
],
"unknown field `b`, expected `a`",
}
test_skip_all_deny_unknown<StructSkipAllDenyUnknown> {
&[
Token::Struct { name: "StructSkipAllDenyUnknown", len: 1 },
Token::Struct { name: "StructSkipAllDenyUnknown", len: 0 },
Token::Str("a"),
],
"unknown field `a`, there are no fields",
+72 -63
View File
@@ -11,7 +11,6 @@
// types involved.
#![deny(warnings)]
#![cfg_attr(feature = "unstable", feature(non_ascii_idents))]
#[macro_use]
@@ -23,6 +22,7 @@ use self::serde::de::{DeserializeOwned, Deserializer};
use std::borrow::Cow;
use std::marker::PhantomData;
use std::option::Option as StdOption;
use std::result::Result as StdResult;
// Try to trip up the generated code if it fails to use fully qualified paths.
@@ -32,6 +32,12 @@ struct Result;
struct Ok;
#[allow(dead_code)]
struct Err;
#[allow(dead_code)]
struct Option;
#[allow(dead_code)]
struct Some;
#[allow(dead_code)]
struct None;
//////////////////////////////////////////////////////////////////////////
@@ -40,7 +46,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
struct With<T> {
t: T,
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X,
}
assert::<With<i32>>();
@@ -48,7 +54,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
struct WithTogether<T> {
t: T,
#[serde(with="both_x")]
#[serde(with = "both_x")]
x: X,
}
assert::<WithTogether<i32>>();
@@ -56,8 +62,8 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
struct WithRef<'a, T: 'a> {
#[serde(skip_deserializing)]
t: Option<&'a T>,
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
t: StdOption<&'a T>,
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X,
}
assert::<WithRef<i32>>();
@@ -77,9 +83,9 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
struct NoBounds<T> {
t: T,
option: Option<T>,
option: StdOption<T>,
boxed: Box<T>,
option_boxed: Option<Box<T>>,
option_boxed: StdOption<Box<T>>,
}
assert::<NoBounds<i32>>();
@@ -87,17 +93,17 @@ fn test_gen() {
enum EnumWith<T> {
Unit,
Newtype(
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
X
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X,
),
Tuple(
T,
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
X
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X,
),
Struct {
t: T,
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X,
},
}
@@ -117,16 +123,16 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
struct Newtype(
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
X
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X,
);
assert::<Newtype>();
#[derive(Serialize, Deserialize)]
struct Tuple<T>(
T,
#[serde(serialize_with="ser_x", deserialize_with="de_x")]
X
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X,
);
assert::<Tuple<i32>>();
@@ -136,7 +142,9 @@ fn test_gen() {
left: Box<TreeNode<D>>,
right: Box<TreeNode<D>>,
},
Leaf { data: D },
Leaf {
data: D,
},
}
assert::<TreeNode<i32>>();
@@ -175,35 +183,34 @@ fn test_gen() {
#[derive(Serialize)]
struct OptionStatic<'a> {
a: Option<&'a str>,
b: Option<&'static str>,
a: StdOption<&'a str>,
b: StdOption<&'static str>,
}
assert_ser::<OptionStatic>();
#[derive(Serialize, Deserialize)]
#[serde(bound="D: SerializeWith + DeserializeWith")]
#[serde(bound = "D: SerializeWith + DeserializeWith")]
struct WithTraits1<D, E> {
#[serde(serialize_with="SerializeWith::serialize_with",
deserialize_with="DeserializeWith::deserialize_with")]
#[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with")]
d: D,
#[serde(serialize_with="SerializeWith::serialize_with",
deserialize_with="DeserializeWith::deserialize_with",
bound="E: SerializeWith + DeserializeWith")]
#[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with",
bound = "E: SerializeWith + DeserializeWith")]
e: E,
}
assert::<WithTraits1<X, X>>();
#[derive(Serialize, Deserialize)]
#[serde(bound(serialize="D: SerializeWith",
deserialize="D: DeserializeWith"))]
#[serde(bound(serialize = "D: SerializeWith", deserialize = "D: DeserializeWith"))]
struct WithTraits2<D, E> {
#[serde(serialize_with="SerializeWith::serialize_with",
deserialize_with="DeserializeWith::deserialize_with")]
#[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with")]
d: D,
#[serde(serialize_with="SerializeWith::serialize_with",
bound(serialize="E: SerializeWith"))]
#[serde(deserialize_with="DeserializeWith::deserialize_with",
bound(deserialize="E: DeserializeWith"))]
#[serde(serialize_with = "SerializeWith::serialize_with",
bound(serialize = "E: SerializeWith"))]
#[serde(deserialize_with = "DeserializeWith::deserialize_with",
bound(deserialize = "E: DeserializeWith"))]
e: E,
}
assert::<WithTraits2<X, X>>();
@@ -265,14 +272,14 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
struct TupleSkipAll(
#[serde(skip_deserializing)]
u8
u8,
);
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct TupleSkipAllDenyUnknown(
#[serde(skip_deserializing)]
u8
u8,
);
#[derive(Serialize, Deserialize)]
@@ -300,7 +307,7 @@ fn test_gen() {
},
TupleSkip(
#[serde(skip_deserializing)]
u8
u8,
),
}
@@ -316,7 +323,7 @@ fn test_gen() {
},
TupleSkip(
#[serde(skip_deserializing)]
u8
u8,
),
}
@@ -378,6 +385,10 @@ fn test_gen() {
s: vis::S,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "Self")]
struct RemoteSelf;
#[derive(Serialize, Deserialize)]
enum ExternallyTaggedVariantWith {
#[allow(dead_code)]
@@ -396,10 +407,7 @@ fn test_gen() {
#[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)]
Struct {
f1: String,
f2: u8,
},
Struct { f1: String, f2: u8 },
#[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")]
@@ -422,10 +430,7 @@ fn test_gen() {
#[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)]
Struct {
f1: String,
f2: u8,
},
Struct { f1: String, f2: u8 },
#[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")]
@@ -453,10 +458,7 @@ fn test_gen() {
#[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)]
Struct {
f1: String,
f2: u8,
},
Struct { f1: String, f2: u8 },
#[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")]
@@ -484,10 +486,7 @@ fn test_gen() {
#[serde(serialize_with = "serialize_some_other_variant")]
#[serde(deserialize_with = "deserialize_some_other_variant")]
#[allow(dead_code)]
Struct {
f1: String,
f2: u8,
},
Struct { f1: String, f2: u8 },
#[serde(serialize_with = "serialize_some_unit_variant")]
#[serde(deserialize_with = "deserialize_some_unit_variant")]
@@ -510,10 +509,7 @@ fn test_gen() {
#[derive(Serialize, Deserialize)]
enum StaticStrEnum<'a> {
Struct {
a: &'a str,
b: &'static str,
},
Struct { a: &'a str, b: &'static str },
Tuple(&'a str, &'static str),
Newtype(&'static str),
}
@@ -536,6 +532,13 @@ fn test_gen() {
marker: PhantomData<T>,
}
assert::<TypeMacro<X>>();
#[derive(Serialize)]
struct BigArray {
#[serde(serialize_with = "<[_]>::serialize")]
array: [u8; 256],
}
assert_ser::<BigArray>();
}
//////////////////////////////////////////////////////////////////////////
@@ -563,7 +566,7 @@ pub fn de_x<'de, D: Deserializer<'de>>(_: D) -> StdResult<X, D::Error> {
}
mod both_x {
pub use super::{ser_x as serialize, de_x as deserialize};
pub use super::{de_x as deserialize, ser_x as serialize};
}
impl SerializeWith for X {
@@ -579,27 +582,33 @@ impl DeserializeWith for X {
}
pub fn serialize_some_unit_variant<S>(_: S) -> StdResult<S::Ok, S::Error>
where S: Serializer,
where
S: Serializer,
{
unimplemented!()
}
pub fn deserialize_some_unit_variant<'de, D>(_: D) -> StdResult<(), D::Error>
where D: Deserializer<'de>,
where
D: Deserializer<'de>,
{
unimplemented!()
}
pub fn serialize_some_other_variant<S>(_: &str, _: &u8, _: S) -> StdResult<S::Ok, S::Error>
where S: Serializer,
where
S: Serializer,
{
unimplemented!()
}
pub fn deserialize_some_other_variant<'de, D>(_: D) -> StdResult<(String, u8), D::Error>
where D: Deserializer<'de>,
where
D: Deserializer<'de>,
{
unimplemented!()
}
pub fn is_zero(n: &u8) -> bool { *n == 0 }
pub fn is_zero(n: &u8) -> bool {
*n == 0
}
+2 -1
View File
@@ -49,7 +49,8 @@ fn test_unit_fallthrough() {
enum F {
Aaa,
Bbb,
#[serde(other)] Other,
#[serde(other)]
Other,
}
assert_de_tokens(&F::Other, &[Token::Str("x")]);
File diff suppressed because it is too large Load Diff
+43 -17
View File
@@ -6,6 +6,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]
#[macro_use]
extern crate serde_derive;
@@ -85,23 +87,32 @@ mod remote {
#[derive(Serialize, Deserialize)]
struct Test {
#[serde(with = "UnitDef")] unit: remote::Unit,
#[serde(with = "UnitDef")]
unit: remote::Unit,
#[serde(with = "PrimitivePrivDef")] primitive_priv: remote::PrimitivePriv,
#[serde(with = "PrimitivePrivDef")]
primitive_priv: remote::PrimitivePriv,
#[serde(with = "PrimitivePubDef")] primitive_pub: remote::PrimitivePub,
#[serde(with = "PrimitivePubDef")]
primitive_pub: remote::PrimitivePub,
#[serde(with = "NewtypePrivDef")] newtype_priv: remote::NewtypePriv,
#[serde(with = "NewtypePrivDef")]
newtype_priv: remote::NewtypePriv,
#[serde(with = "NewtypePubDef")] newtype_pub: remote::NewtypePub,
#[serde(with = "NewtypePubDef")]
newtype_pub: remote::NewtypePub,
#[serde(with = "TuplePrivDef")] tuple_priv: remote::TuplePriv,
#[serde(with = "TuplePrivDef")]
tuple_priv: remote::TuplePriv,
#[serde(with = "TuplePubDef")] tuple_pub: remote::TuplePub,
#[serde(with = "TuplePubDef")]
tuple_pub: remote::TuplePub,
#[serde(with = "StructPrivDef")] struct_priv: remote::StructPriv,
#[serde(with = "StructPrivDef")]
struct_priv: remote::StructPriv,
#[serde(with = "StructPubDef")] struct_pub: remote::StructPub,
#[serde(with = "StructPubDef")]
struct_pub: remote::StructPub,
}
#[derive(Serialize, Deserialize)]
@@ -110,7 +121,10 @@ struct UnitDef;
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::PrimitivePriv")]
struct PrimitivePrivDef(#[serde(getter = "remote::PrimitivePriv::get")] u8);
struct PrimitivePrivDef(
#[serde(getter = "remote::PrimitivePriv::get")]
u8,
);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::PrimitivePub")]
@@ -119,28 +133,39 @@ struct PrimitivePubDef(u8);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::NewtypePriv")]
struct NewtypePrivDef(
#[serde(getter = "remote::NewtypePriv::get", with = "UnitDef")] remote::Unit,
#[serde(getter = "remote::NewtypePriv::get", with = "UnitDef")]
remote::Unit,
);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::NewtypePub")]
struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit);
struct NewtypePubDef(
#[serde(with = "UnitDef")]
remote::Unit,
);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::TuplePriv")]
struct TuplePrivDef(
#[serde(getter = "remote::TuplePriv::first")] u8,
#[serde(getter = "remote::TuplePriv::second", with = "UnitDef")] remote::Unit,
#[serde(getter = "remote::TuplePriv::first")]
u8,
#[serde(getter = "remote::TuplePriv::second", with = "UnitDef")]
remote::Unit,
);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::TuplePub")]
struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit);
struct TuplePubDef(
u8,
#[serde(with = "UnitDef")]
remote::Unit,
);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::StructPriv")]
struct StructPrivDef {
#[serde(getter = "remote::StructPriv::a")] a: u8,
#[serde(getter = "remote::StructPriv::a")]
a: u8,
#[serde(getter = "remote::StructPriv::b")]
#[serde(with = "UnitDef")]
@@ -150,7 +175,8 @@ struct StructPrivDef {
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::StructPub")]
struct StructPubDef {
#[allow(dead_code)] a: u8,
#[allow(dead_code)]
a: u8,
#[allow(dead_code)]
#[serde(with = "UnitDef")]
+1 -1
View File
@@ -30,7 +30,7 @@ fn ip_addr_roundtrip() {
}
#[test]
fn socked_addr_roundtrip() {
fn socket_addr_roundtrip() {
assert_tokens(
&net::SocketAddr::from((*b"1234567890123456", 1234)).compact(),
&seq![
+15 -5
View File
@@ -50,11 +50,21 @@ enum Enum {
Unit,
One(i32),
Seq(i32, i32),
Map { a: i32, b: i32 },
#[serde(skip_serializing)] SkippedUnit,
#[serde(skip_serializing)] SkippedOne(i32),
#[serde(skip_serializing)] SkippedSeq(i32, i32),
#[serde(skip_serializing)] SkippedMap { _a: i32, _b: i32 },
Map {
a: i32,
b: i32,
},
#[serde(skip_serializing)]
SkippedUnit,
#[serde(skip_serializing)]
SkippedOne(i32),
#[serde(skip_serializing)]
SkippedSeq(i32, i32),
#[serde(skip_serializing)]
SkippedMap {
_a: i32,
_b: i32,
},
}
//////////////////////////////////////////////////////////////////////////
+1
View File
@@ -55,6 +55,7 @@ else
channel build
cd "$DIR/test_suite"
channel test --features unstable
channel build --tests --features proc-macro2/nightly
if [ -z "${APPVEYOR}" ]; then
cd "$DIR/test_suite/no_std"
channel build