Compare commits

...

72 Commits

Author SHA1 Message Date
David Tolnay 48aa054f53 Release 1.0.178 2023-07-28 16:09:39 -07:00
David Tolnay 3616860203 Delete broken symlink from precompiled derive sources 2023-07-28 16:09:22 -07:00
David Tolnay 861b0dfea2 Consistently list StdError under 'Re-exports' heading of rustdoc 2023-07-28 16:06:49 -07:00
David Tolnay 8b3d71ae2d Merge pull request #2541 from dtolnay/de-core-error
Fix `serde::de::StdError` in no-std unstable build
2023-07-28 16:05:14 -07:00
David Tolnay ff5442cd9e Add no-std unstable build in CI 2023-07-28 16:00:07 -07:00
David Tolnay 92d686f9a5 Fix serde::de::StdError in no-std unstable build 2023-07-28 15:58:57 -07:00
David Tolnay 7b09cccd77 Merge pull request #2539 from dtolnay/questionmark
Replace `try!` with `?` in serde_derive
2023-07-27 19:20:15 -07:00
David Tolnay 6f1f38d046 Replace 'try!' with '?' in serde_derive 2023-07-27 19:16:11 -07:00
David Tolnay db8f06467b Eliminate workaround for pre-1.17 rustc in serde_derive
The oldest compiler supported by serde_derive by this point is 1.56.
2023-07-27 19:05:57 -07:00
David Tolnay 91ec1c290f Enforce question mark not used in serde crate yet
Question mark regresses compile time by 6.5–7.5%.
2023-07-27 19:02:11 -07:00
David Tolnay 0676673ca5 Release 1.0.177 2023-07-27 10:51:22 -07:00
David Tolnay 7a4335d664 Merge pull request #2536 from jplatte/jplatte/error-span
Update error span for attribute / data kind mismatches
2023-07-27 10:50:26 -07:00
Jonas Platte 31a0e73489 Update error span for attribute / data kind mismatches 2023-07-27 10:47:45 +02:00
David Tolnay 74fe70855f Ignore return_self_not_must_use pedantic clippy lint
warning: missing `#[must_use]` attribute on a method returning `Self`
       --> serde_derive_internals/src/attr.rs:204:5
        |
    204 | /     pub fn or(self, other_rules: Self) -> Self {
    205 | |         Self {
    206 | |             serialize: self.serialize.or(other_rules.serialize),
    207 | |             deserialize: self.deserialize.or(other_rules.deserialize),
    208 | |         }
    209 | |     }
        | |_____^
        |
        = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
        = note: `-W clippy::return-self-not-must-use` implied by `-W clippy::pedantic`

    warning: missing `#[must_use]` attribute on a method returning `Self`
       --> serde_derive_internals/src/case.rs:112:5
        |
    112 | /     pub fn or(self, rule_b: Self) -> Self {
    113 | |         match self {
    114 | |             None => rule_b,
    115 | |             _ => self,
    116 | |         }
    117 | |     }
        | |_____^
        |
        = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
2023-07-27 00:51:57 -07:00
David Tolnay e74925bc43 Merge pull request #1695 from jplatte/rename_all_fields
Add #[serde(rename_all_fields = "foo")] attribute
2023-07-27 00:45:45 -07:00
Jonas Platte 56be1c203e Pass RenameRule, RenameAllRules by value 2023-07-27 09:19:42 +02:00
Jonas Platte 2f9bf4d3eb Add #[serde(rename_all_fields = "foo")] attribute 2023-07-27 09:19:42 +02:00
David Tolnay ad94aed753 Merge pull request #2535 from dtolnay/baretrait
Restore bare_trait_objects lint within serde_derive code
2023-07-26 14:26:02 -07:00
David Tolnay 30db83fc44 Restore bare_trait_objects lint within serde_derive code 2023-07-26 14:18:25 -07:00
David Tolnay b0f7b00e1f Resolve manual_string_new pedantic clippy lint
warning: empty String is being created manually
        --> test_suite/tests/test_annotations.rs:2280:29
         |
    2280 |     let data = Data::C { t: "".to_string() };
         |                             ^^^^^^^^^^^^^^ help: consider using: `String::new()`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new
         = note: `-W clippy::manual-string-new` implied by `-W clippy::pedantic`
2023-07-26 13:46:28 -07:00
David Tolnay 7255e192d8 Delete unused statement from PR 2266 test 2023-07-26 13:45:49 -07:00
David Tolnay 2102e1aa42 Format PR 2266 tests with rustfmt 2023-07-26 13:41:56 -07:00
David Tolnay 85d5c1fd38 Release 1.0.176 2023-07-26 13:37:44 -07:00
David Tolnay b789286bc3 Merge pull request #2266 from flisky/master
fix: don't check skipped variant with internal tag
2023-07-26 13:36:33 -07:00
David Tolnay a6a8a334f7 Add CI on macOS for the non-precompiled codepath 2023-07-26 01:03:20 -07:00
David Tolnay 78a11a27b6 Skip an extra trip through filesystem on the critical path 2023-07-26 00:58:34 -07:00
David Tolnay d2d7bad04a Improve error message on missing serde_derive exe 2023-07-26 00:52:09 -07:00
David Tolnay b978854258 Eliminate parse_macro_input conflict in precompiled mode 2023-07-26 00:44:55 -07:00
David Tolnay 0fb672a1ef Eliminate #[macro_use] from serde_derive 2023-07-25 23:23:24 -07:00
David Tolnay dd9913675d Ungroup imports 2023-07-25 23:06:34 -07:00
David Tolnay 11677ad926 Merge pull request #2533 from dtolnay/test
Move serde_test out to serde-rs/test
2023-07-25 22:52:36 -07:00
David Tolnay 25a53f10db Move serde_test out to serde-rs/test 2023-07-25 22:48:39 -07:00
David Tolnay 26e2ef001c Delete deprecated AsciiExt extension trait import
This has been superseded by inherent methods since Rust 1.26.
2023-07-25 21:07:33 -07:00
David Tolnay 30f79b3b2e Eliminate 2015-style module system imports from serde_derive 2023-07-25 20:56:19 -07:00
David Tolnay 89f84c2915 Merge pull request #2532 from dtolnay/macrouse
Delete unused serde_derive #[macro_use]
2023-07-25 18:55:14 -07:00
David Tolnay 6882285be0 Move extern crate proc_macro into each possible lib.rs
This makes it slightly more convenient to use the following as a
Reindeer fixup for those that prefer to build from source:

    extra_mapped_srcs = { "src/lib_from_source.rs" = "src/lib.rs" }

    [platform_fixups.'cfg(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"))']
    extra_deps = [":proc-macro2", ":quote", ":syn"]

as opposed to checking in a whole new file containing the `extern crate
proc_macro` + `include!("lib_from_source.rs")`.
2023-07-25 18:54:41 -07:00
David Tolnay 3260bc5896 Delete unused serde_derive #[macro_use]
In old versions of rustc (1.15 through 1.29) it would cause a warning if
this #[macro_use] was not present.

    warning: proc macro crates and `#[no_link]` crates have no effect without `#[macro_use]`
       --> serde/src/lib.rs:340:1
        |
    340 | extern crate serde_derive;
        | ^^^^^^^^^^^^^^^^^^^^^^^^^^

These days serde_derive requires a newer compiler than that, so the
bogus warning would never occur.
2023-07-25 18:47:52 -07:00
David Tolnay 6140b6f527 Release 1.0.175 2023-07-23 20:07:32 -07:00
David Tolnay 4cabc9f293 Merge pull request #2527 from ankane/license-files
Include license files in serde_derive crate
2023-07-23 20:04:18 -07:00
Andrew Kane aa7c6345a4 Include license files in serde_derive crate 2023-07-23 19:54:57 -07:00
David Tolnay 27414c90a8 Merge pull request #2522 from serde-rs/leak
Leak all memory allocated during macro expansion
2023-07-22 08:37:52 -07:00
David Tolnay 50e2f4b213 Leak all memory allocated during macro expansion 2023-07-22 08:32:18 -07:00
David Tolnay 22be673beb Release 1.0.174 2023-07-20 22:20:37 -07:00
David Tolnay 166c89fabf Opt in to generate-link-to-definition when building on docs.rs 2023-07-20 22:19:03 -07:00
David Tolnay 6e0b13eedb Release 1.0.173 2023-07-19 16:34:13 -07:00
David Tolnay 7e8f978ca9 Handle $crate special case 2023-07-19 16:32:59 -07:00
David Tolnay 6c0e838a7c Always consider empty output to be unsuccessful 2023-07-19 16:13:02 -07:00
David Tolnay d3da41927a Enable full expression parsing for precompiled serde_derive 2023-07-19 16:01:18 -07:00
David Tolnay 425a4b7a74 Check precompiled subprocess exit status 2023-07-19 16:00:37 -07:00
David Tolnay 63c65ef742 Release 1.0.172 2023-07-19 14:13:56 -07:00
David Tolnay e838b0bd81 Release 1.0.172-alpha.0 2023-07-19 14:00:50 -07:00
David Tolnay 041e99c78a Implement fallback to compiling serde_derive from source 2023-07-19 13:53:49 -07:00
David Tolnay 07dcc4f7fe Remove unneeded 'include' Cargo.toml entries 2023-07-19 13:44:55 -07:00
David Tolnay b88052d875 Rearrange precompiled directory 2023-07-19 13:24:36 -07:00
David Tolnay a28292764c Publish precompiled deserialize_in_place 2023-07-19 12:29:30 -07:00
David Tolnay 2027088741 Support precompiled deserialize_in_place 2023-07-19 12:27:37 -07:00
David Tolnay e2d8589976 Publish span-related fixes 2023-07-19 09:41:11 -07:00
David Tolnay c8a9f99d14 Preserve Group span better on compilers without Span::join 2023-07-19 09:39:11 -07:00
David Tolnay 645d04012d Fix off by one span counter, 0 is used for call_site() 2023-07-19 09:26:56 -07:00
David Tolnay 100ddada2f Suppress dead_code on fields only accessed by deserialize_in_place
error: field `option` is never read
       --> test_suite/tests/test_gen.rs:666:9
        |
    665 |     struct ImplicitlyBorrowedOption<'a> {
        |            ------------------------ field in this struct
    666 |         option: std::option::Option<&'a str>,
        |         ^^^^^^
        |
    note: the lint level is defined here
       --> test_suite/tests/test_gen.rs:5:9
        |
    5   | #![deny(warnings)]
        |         ^^^^^^^^
        = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]`

    error: fields `ty` and `id` are never read
       --> test_suite/tests/test_gen.rs:696:9
        |
    695 |     struct RelObject<'a> {
        |            --------- fields in this struct
    696 |         ty: &'a str,
        |         ^^
    697 |         id: String,
        |         ^^

    error: field `field` is never read
       --> test_suite/tests/test_gen.rs:740:17
        |
    739 |             struct MacroRules<'a> {
        |                    ---------- field in this struct
    740 |                 field: $field,
        |                 ^^^^^
    ...
    745 |     deriving!(&'a str);
        |     ------------------ in this macro invocation
        |
        = note: this error originates in the macro `deriving` (in Nightly builds, run with -Z macro-backtrace for more info)

    error: field `f` is never read
       --> test_suite/tests/test_gen.rs:756:9
        |
    754 |     struct BorrowLifetimeInsideMacro<'a> {
        |            ------------------------- field in this struct
    755 |         #[serde(borrow = "'a")]
    756 |         f: mac!(Cow<'a, str>),
        |         ^

    warning: fields `question` and `answer` are never read
        --> test_suite/tests/test_annotations.rs:2969:9
         |
    2968 |     struct Struct {
         |            ------ fields in this struct
    2969 |         question: String,
         |         ^^^^^^^^
    2970 |         answer: u32,
         |         ^^^^^^
         |
         = note: `#[warn(dead_code)]` on by default
2023-07-19 09:12:35 -07:00
David Tolnay 2ef1cd4b35 Import macros exclusively through serde_derive in test suite
This makes it easier to execute tests against the precompiled serde_derive.
2023-07-19 09:08:05 -07:00
David Tolnay be9c3fd69d Publish raw string fix 2023-07-18 18:42:54 -07:00
David Tolnay ef522e1d16 Add a reminder about trim-paths 2023-07-18 18:39:40 -07:00
David Tolnay 1ddb6c2fdb Fix handling of raw idents in proc-macro2 shim 2023-07-18 18:29:24 -07:00
David Tolnay eb3f2329af Merge pull request #2514 from dtolnay/precompiled
Add experiment to produce precompiled builds of serde_derive
2023-07-18 13:48:17 -07:00
David Tolnay 9e8f14816b Add experiment to produce precompiled builds of serde_derive 2023-07-18 13:37:36 -07:00
David Tolnay 03da66c805 Release 1.0.171 2023-07-09 18:05:02 -07:00
David Tolnay f75426f47e Inline visitor_expr of unit struct deserialize impl 2023-07-09 18:03:58 -07:00
David Tolnay 662fc3861c Add test of const-generic unit struct where-clause edge case
Closes #2501.
2023-07-09 18:01:43 -07:00
David Tolnay 28c10020b9 Merge pull request #2500 from Baptistemontan/derive_generic_unit_struct
Allow `[derive(serde::Deserialize)]` for generic unit structs
2023-07-09 17:52:12 -07:00
Baptiste de Montangon 89c8d85de9 allow Deserialize derive to handle generic unit structs 2023-07-10 01:31:40 +02:00
Yin Jifeng 983347484e fix: don't check skipped variant with internal tag 2022-08-23 20:19:34 +08:00
100 changed files with 2066 additions and 3423 deletions
+11 -4
View File
@@ -46,8 +46,6 @@ jobs:
toolchain: ${{matrix.rust}}
- run: cd serde && cargo build --features rc
- run: cd serde && cargo build --no-default-features
- run: cd serde_test && cargo build
- run: cd serde_test && cargo test --features serde/derive,serde/rc
nightly:
name: Rust nightly ${{matrix.os == 'windows' && '(windows)' || ''}}
@@ -64,6 +62,7 @@ jobs:
- run: cd serde && cargo build --no-default-features
- run: cd serde && cargo build --no-default-features --features alloc
- run: cd serde && cargo build --no-default-features --features rc,alloc
- run: cd serde && cargo build --no-default-features --features unstable
- run: cd serde && cargo test --features derive,rc,unstable
- run: cd test_suite/no_std && cargo build
if: matrix.os != 'windows'
@@ -88,7 +87,6 @@ jobs:
- run: cd serde && cargo build --features rc
- run: cd serde && cargo build --no-default-features
- run: cd serde && cargo build
- run: cd serde_test && cargo build
more:
name: Rust ${{matrix.rust}}
@@ -118,6 +116,7 @@ jobs:
- run: cd serde && cargo check --no-default-features
- run: cd serde && cargo check
- run: cd serde_derive && cargo check
- run: cd precompiled/serde_derive && cargo check
alloc:
name: Rust 1.36.0
@@ -128,6 +127,15 @@ jobs:
- uses: dtolnay/rust-toolchain@1.36.0
- run: cd serde && cargo build --no-default-features --features alloc
macos:
name: macOS
runs-on: macos-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- run: cd precompiled/serde_derive && cargo check
minimal:
name: Minimal versions
runs-on: ubuntu-latest
@@ -149,7 +157,6 @@ jobs:
- run: cd serde && cargo clippy --features rc,unstable -- -Dclippy::all -Dclippy::pedantic
- run: cd serde_derive && cargo clippy -- -Dclippy::all -Dclippy::pedantic
- run: cd serde_derive_internals && cargo clippy -- -Dclippy::all -Dclippy::pedantic
- run: cd serde_test && cargo clippy -- -Dclippy::all -Dclippy::pedantic
- run: cd test_suite && cargo clippy --tests --features unstable -- -Dclippy::all -Dclippy::pedantic
- run: cd test_suite/no_std && cargo clippy -- -Dclippy::all -Dclippy::pedantic
+3 -1
View File
@@ -3,6 +3,8 @@ members = [
"serde",
"serde_derive",
"serde_derive_internals",
"serde_test",
"test_suite",
]
[patch.crates-io]
serde = { path = "serde" }
+1
View File
@@ -0,0 +1 @@
/serde_derive/serde_derive-x86_64-unknown-linux-gnu
+14
View File
@@ -0,0 +1,14 @@
[workspace]
members = ["bin", "proc-macro2"]
resolver = "2"
[patch.crates-io]
proc-macro2 = { path = "proc-macro2" }
[profile.precompiled]
inherits = "release"
codegen-units = 1
lto = true
opt-level = "z"
panic = "abort"
strip = true
+17
View File
@@ -0,0 +1,17 @@
[package]
name = "serde_derive"
version = "1.0.178"
authors = ["David Tolnay <dtolnay@gmail.com>"]
publish = false
[lib]
doctest = false
[[bin]]
name = "serde_derive"
path = "main.rs"
[dependencies]
proc-macro2 = "1"
quote = { version = "1", default-features = false }
syn = { version = "2.0.25", default-features = false, features = ["clone-impls", "derive", "full", "parsing", "printing"] }
+4
View File
@@ -0,0 +1,4 @@
fn main() {
println!("cargo:rustc-cfg=precompiled");
println!("cargo:rustc-cfg=feature=\"deserialize_in_place\"");
}
+45
View File
@@ -0,0 +1,45 @@
extern crate proc_macro2;
use proc_macro2::watt;
use proc_macro2::watt::buffer::InputBuffer;
use std::alloc::{GlobalAlloc, Layout, System};
use std::io::{self, Read, Write};
use std::sync::atomic::Ordering;
struct MonotonicAllocator;
#[global_allocator]
static ALLOCATOR: MonotonicAllocator = MonotonicAllocator;
unsafe impl GlobalAlloc for MonotonicAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
System.alloc(layout)
}
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
// Leak: this cuts 3% of code size from the precompiled macro binary.
// There is no way that serde_derive would fill up all memory on the
// host. When the subprocess exits, operating system will clean this up.
}
}
fn main() {
let mut buf = Vec::new();
io::stdin().read_to_end(&mut buf).unwrap();
let mut buf = InputBuffer::new(&buf);
let derive = match buf.read_u8() {
0 => serde_derive::derive_serialize,
1 => serde_derive::derive_deserialize,
2 => {
serde_derive::DESERIALIZE_IN_PLACE.store(true, Ordering::Relaxed);
serde_derive::derive_deserialize
}
_ => unreachable!(),
};
let input = watt::load(&mut buf);
let output = derive(input);
let bytes = watt::linearize(output);
io::stdout().write_all(&bytes).unwrap();
}
+1
View File
@@ -0,0 +1 @@
../../serde_derive/src
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null
set -e -x
# TODO: Sanitize host filesystem paths. https://github.com/rust-lang/cargo/issues/12137
cargo +nightly build \
--manifest-path bin/Cargo.toml \
--bin serde_derive \
--profile precompiled \
-Z unstable-options \
-Z build-std=std,panic_abort \
-Z build-std-features=panic_immediate_abort \
--target x86_64-unknown-linux-musl \
--out-dir serde_derive
rm -f serde_derive/serde_derive-x86_64-unknown-linux-gnu
mv serde_derive/serde_derive{,-x86_64-unknown-linux-gnu}
#upx --best --lzma serde_derive/serde_derive-x86_64-unknown-linux-gnu
+8
View File
@@ -0,0 +1,8 @@
[package]
name = "proc-macro2"
version = "1.0.66"
edition = "2021"
publish = false
[dependencies]
proc-macro2 = { package = "proc-macro2-fallback", version = "1" }
+815
View File
@@ -0,0 +1,815 @@
#[doc(hidden)]
pub mod watt;
use crate::extra::DelimSpan;
use crate::watt::Identity;
use std::cmp::Ordering;
use std::fmt::{self, Debug, Display};
use std::hash::{Hash, Hasher};
use std::ops::RangeBounds;
use std::str::FromStr;
pub use proc_macro2::{Delimiter, Spacing};
#[derive(Copy, Clone)]
pub struct Span {
lo: u32,
hi: u32,
}
impl Span {
pub fn call_site() -> Self {
Span { lo: 0, hi: 0 }
}
pub fn join(&self, other: Self) -> Option<Self> {
Some(Span {
lo: self.lo,
hi: other.hi,
})
}
}
#[derive(Clone)]
pub enum TokenTree {
Group(Group),
Ident(Ident),
Punct(Punct),
Literal(Literal),
}
impl TokenTree {
pub fn span(&self) -> Span {
match self {
TokenTree::Group(group) => group.span(),
TokenTree::Ident(ident) => ident.span(),
TokenTree::Punct(punct) => punct.span(),
TokenTree::Literal(literal) => literal.span(),
}
}
pub fn set_span(&mut self, span: Span) {
match self {
TokenTree::Group(group) => group.set_span(span),
TokenTree::Ident(ident) => ident.set_span(span),
TokenTree::Punct(punct) => punct.set_span(span),
TokenTree::Literal(literal) => literal.set_span(span),
}
}
}
impl From<Group> for TokenTree {
fn from(group: Group) -> Self {
TokenTree::Group(group)
}
}
impl From<Ident> for TokenTree {
fn from(ident: Ident) -> Self {
TokenTree::Ident(ident)
}
}
impl From<Punct> for TokenTree {
fn from(punct: Punct) -> Self {
TokenTree::Punct(punct)
}
}
impl From<Literal> for TokenTree {
fn from(literal: Literal) -> Self {
TokenTree::Literal(literal)
}
}
impl Debug for TokenTree {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self {
TokenTree::Group(group) => Debug::fmt(group, formatter),
TokenTree::Ident(ident) => {
let mut debug = formatter.debug_struct("Ident");
debug.field("sym", &format_args!("{}", ident));
debug.finish()
}
TokenTree::Punct(punct) => Debug::fmt(punct, formatter),
TokenTree::Literal(literal) => Debug::fmt(literal, formatter),
}
}
}
#[derive(Clone)]
pub struct Group {
delimiter: Delimiter,
stream: Vec<TokenTree>,
span: Span,
span_open: Span,
span_close: Span,
identity: u32,
}
impl Group {
pub fn new(delimiter: Delimiter, stream: TokenStream) -> Self {
Group {
delimiter,
stream: stream.content,
span: Span::call_site(),
span_open: Span::call_site(),
span_close: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn stream(&self) -> TokenStream {
TokenStream {
content: self.stream.clone(),
}
}
pub fn delimiter(&self) -> Delimiter {
self.delimiter
}
pub fn span(&self) -> Span {
self.span
}
pub fn span_open(&self) -> Span {
self.span_open
}
pub fn span_close(&self) -> Span {
self.span_close
}
pub fn delim_span(&self) -> DelimSpan {
DelimSpan {
join: self.span,
open: self.span_open,
close: self.span_close,
}
}
pub fn set_span(&mut self, span: Span) {
self.span = span;
self.identity |= Identity::RESPANNED;
}
}
impl Display for Group {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let (open, close) = match self.delimiter {
Delimiter::Parenthesis => ("(", ")"),
Delimiter::Brace => ("{ ", "}"),
Delimiter::Bracket => ("[", "]"),
Delimiter::None => ("", ""),
};
formatter.write_str(open)?;
display_tokens(&self.stream, formatter)?;
if self.delimiter == Delimiter::Brace && !self.stream.is_empty() {
formatter.write_str(" ")?;
}
formatter.write_str(close)?;
Ok(())
}
}
impl Debug for Group {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let mut debug = formatter.debug_struct("Group");
debug.field("delimiter", &self.delimiter);
debug.field("stream", &self.stream);
debug.finish()
}
}
#[derive(Clone)]
pub struct Ident {
fallback: proc_macro2::Ident,
span: Span,
identity: u32,
}
impl Ident {
pub fn new(string: &str, span: Span) -> Self {
Ident {
fallback: proc_macro2::Ident::new(string, proc_macro2::Span::call_site()),
span,
identity: Identity::NOVEL,
}
}
pub fn new_raw(string: &str, span: Span) -> Self {
Ident {
fallback: proc_macro2::Ident::new_raw(string, proc_macro2::Span::call_site()),
span,
identity: Identity::NOVEL,
}
}
pub fn span(&self) -> Span {
self.span
}
pub fn set_span(&mut self, span: Span) {
self.span = span;
self.identity |= Identity::RESPANNED;
}
}
impl Display for Ident {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.fallback, formatter)
}
}
impl Debug for Ident {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.fallback, formatter)
}
}
impl Eq for Ident {}
impl PartialEq for Ident {
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(&self.fallback, &other.fallback)
}
}
impl<T> PartialEq<T> for Ident
where
T: ?Sized + AsRef<str>,
{
fn eq(&self, other: &T) -> bool {
PartialEq::eq(&self.fallback, other)
}
}
impl Ord for Ident {
fn cmp(&self, other: &Self) -> Ordering {
Ord::cmp(&self.fallback, &other.fallback)
}
}
impl PartialOrd for Ident {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
PartialOrd::partial_cmp(&self.fallback, &other.fallback)
}
}
impl Hash for Ident {
fn hash<H: Hasher>(&self, hasher: &mut H) {
Hash::hash(&self.fallback, hasher);
}
}
#[derive(Clone)]
pub struct Punct {
fallback: proc_macro2::Punct,
span: Span,
identity: u32,
}
impl Punct {
pub fn new(ch: char, spacing: Spacing) -> Self {
Punct {
fallback: proc_macro2::Punct::new(ch, spacing),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn as_char(&self) -> char {
self.fallback.as_char()
}
pub fn spacing(&self) -> Spacing {
self.fallback.spacing()
}
pub fn span(&self) -> Span {
self.span
}
pub fn set_span(&mut self, span: Span) {
self.span = span;
self.identity |= Identity::RESPANNED;
}
}
impl Display for Punct {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.fallback, formatter)
}
}
impl Debug for Punct {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.fallback, formatter)
}
}
#[derive(Clone)]
pub struct Literal {
fallback: proc_macro2::Literal,
span: Span,
identity: u32,
}
impl Literal {
pub fn u8_suffixed(n: u8) -> Self {
Literal {
fallback: proc_macro2::Literal::u8_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u16_suffixed(n: u16) -> Self {
Literal {
fallback: proc_macro2::Literal::u16_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u32_suffixed(n: u32) -> Self {
Literal {
fallback: proc_macro2::Literal::u32_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u64_suffixed(n: u64) -> Self {
Literal {
fallback: proc_macro2::Literal::u64_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u128_suffixed(n: u128) -> Self {
Literal {
fallback: proc_macro2::Literal::u128_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn usize_suffixed(n: usize) -> Self {
Literal {
fallback: proc_macro2::Literal::usize_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i8_suffixed(n: i8) -> Self {
Literal {
fallback: proc_macro2::Literal::i8_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i16_suffixed(n: i16) -> Self {
Literal {
fallback: proc_macro2::Literal::i16_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i32_suffixed(n: i32) -> Self {
Literal {
fallback: proc_macro2::Literal::i32_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i64_suffixed(n: i64) -> Self {
Literal {
fallback: proc_macro2::Literal::i64_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i128_suffixed(n: i128) -> Self {
Literal {
fallback: proc_macro2::Literal::i128_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn isize_suffixed(n: isize) -> Self {
Literal {
fallback: proc_macro2::Literal::isize_suffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u8_unsuffixed(n: u8) -> Self {
Literal {
fallback: proc_macro2::Literal::u8_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u16_unsuffixed(n: u16) -> Self {
Literal {
fallback: proc_macro2::Literal::u16_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u32_unsuffixed(n: u32) -> Self {
Literal {
fallback: proc_macro2::Literal::u32_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u64_unsuffixed(n: u64) -> Self {
Literal {
fallback: proc_macro2::Literal::u64_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn u128_unsuffixed(n: u128) -> Self {
Literal {
fallback: proc_macro2::Literal::u128_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn usize_unsuffixed(n: usize) -> Self {
Literal {
fallback: proc_macro2::Literal::usize_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i8_unsuffixed(n: i8) -> Self {
Literal {
fallback: proc_macro2::Literal::i8_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i16_unsuffixed(n: i16) -> Self {
Literal {
fallback: proc_macro2::Literal::i16_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i32_unsuffixed(n: i32) -> Self {
Literal {
fallback: proc_macro2::Literal::i32_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i64_unsuffixed(n: i64) -> Self {
Literal {
fallback: proc_macro2::Literal::i64_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn i128_unsuffixed(n: i128) -> Self {
Literal {
fallback: proc_macro2::Literal::i128_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn isize_unsuffixed(n: isize) -> Self {
Literal {
fallback: proc_macro2::Literal::isize_unsuffixed(n),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn f64_unsuffixed(f: f64) -> Self {
Literal {
fallback: proc_macro2::Literal::f64_unsuffixed(f),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn f64_suffixed(f: f64) -> Self {
Literal {
fallback: proc_macro2::Literal::f64_suffixed(f),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn f32_unsuffixed(f: f32) -> Self {
Literal {
fallback: proc_macro2::Literal::f32_unsuffixed(f),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn f32_suffixed(f: f32) -> Self {
Literal {
fallback: proc_macro2::Literal::f32_suffixed(f),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn string(string: &str) -> Self {
Literal {
fallback: proc_macro2::Literal::string(string),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn character(ch: char) -> Self {
Literal {
fallback: proc_macro2::Literal::character(ch),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn byte_string(s: &[u8]) -> Self {
Literal {
fallback: proc_macro2::Literal::byte_string(s),
span: Span::call_site(),
identity: Identity::NOVEL,
}
}
pub fn span(&self) -> Span {
self.span
}
pub fn set_span(&mut self, span: Span) {
self.span = span;
self.identity |= Identity::RESPANNED;
}
pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
let _ = range;
None
}
}
impl FromStr for Literal {
type Err = LexError;
fn from_str(repr: &str) -> Result<Self, Self::Err> {
let fallback = match proc_macro2::Literal::from_str(repr) {
Ok(literal) => literal,
Err(error) => {
return Err(LexError {
fallback: error,
span: Span::call_site(),
});
}
};
Ok(Literal {
fallback,
span: Span::call_site(),
identity: Identity::NOVEL,
})
}
}
impl Display for Literal {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.fallback, formatter)
}
}
impl Debug for Literal {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.fallback, formatter)
}
}
#[derive(Clone)]
pub struct TokenStream {
content: Vec<TokenTree>,
}
impl TokenStream {
pub fn new() -> Self {
TokenStream {
content: Vec::new(),
}
}
pub fn is_empty(&self) -> bool {
self.content.is_empty()
}
}
impl IntoIterator for TokenStream {
type Item = TokenTree;
type IntoIter = token_stream::IntoIter;
fn into_iter(self) -> Self::IntoIter {
token_stream::IntoIter {
iter: self.content.into_iter(),
}
}
}
impl Extend<TokenStream> for TokenStream {
fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
self.content.extend(streams.into_iter().flatten());
}
}
impl Extend<TokenTree> for TokenStream {
fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I) {
self.content.extend(streams);
}
}
impl FromIterator<TokenStream> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
let content = streams.into_iter().flatten().collect();
TokenStream { content }
}
}
impl FromIterator<TokenTree> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self {
let content = streams.into_iter().collect();
TokenStream { content }
}
}
impl FromStr for TokenStream {
type Err = LexError;
fn from_str(string: &str) -> Result<Self, Self::Err> {
let fallback = match proc_macro2::TokenStream::from_str(string) {
Ok(token_stream) => token_stream,
Err(error) => {
return Err(LexError {
fallback: error,
span: Span::call_site(),
});
}
};
fn convert_token_stream(stream: proc_macro2::TokenStream) -> TokenStream {
TokenStream {
content: stream.into_iter().map(convert_token_tree).collect(),
}
}
fn convert_token_tree(token: proc_macro2::TokenTree) -> TokenTree {
match token {
proc_macro2::TokenTree::Group(group) => TokenTree::Group(Group::new(
group.delimiter(),
convert_token_stream(group.stream()),
)),
proc_macro2::TokenTree::Ident(ident) => TokenTree::Ident(Ident {
fallback: ident,
span: Span::call_site(),
identity: Identity::NOVEL,
}),
proc_macro2::TokenTree::Punct(punct) => TokenTree::Punct(Punct {
fallback: punct,
span: Span::call_site(),
identity: Identity::NOVEL,
}),
proc_macro2::TokenTree::Literal(literal) => TokenTree::Literal(Literal {
fallback: literal,
span: Span::call_site(),
identity: Identity::NOVEL,
}),
}
}
Ok(convert_token_stream(fallback))
}
}
fn display_tokens(tokens: &[TokenTree], formatter: &mut fmt::Formatter) -> fmt::Result {
let mut joint = false;
for (i, token) in tokens.iter().enumerate() {
if i != 0 && !joint {
write!(formatter, " ")?;
}
joint = false;
match token {
TokenTree::Group(group) => Display::fmt(group, formatter),
TokenTree::Ident(ident) => Display::fmt(ident, formatter),
TokenTree::Punct(punct) => {
joint = punct.spacing() == Spacing::Joint;
Display::fmt(punct, formatter)
}
TokenTree::Literal(literal) => Display::fmt(literal, formatter),
}?;
}
Ok(())
}
impl Display for TokenStream {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
display_tokens(&self.content, formatter)
}
}
impl Debug for TokenStream {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("TokenStream ")?;
formatter.debug_list().entries(&self.content).finish()
}
}
pub struct LexError {
fallback: proc_macro2::LexError,
span: Span,
}
impl LexError {
pub fn span(&self) -> Span {
self.span
}
}
impl Debug for LexError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.fallback, formatter)
}
}
pub mod token_stream {
use super::*;
#[derive(Clone)]
pub struct IntoIter {
pub(crate) iter: <Vec<TokenTree> as IntoIterator>::IntoIter,
}
impl Iterator for IntoIter {
type Item = TokenTree;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
}
pub mod extra {
use crate::Span;
#[derive(Copy, Clone)]
pub struct DelimSpan {
pub(crate) join: Span,
pub(crate) open: Span,
pub(crate) close: Span,
}
impl DelimSpan {
pub fn join(&self) -> Span {
self.join
}
pub fn open(&self) -> Span {
self.open
}
pub fn close(&self) -> Span {
self.close
}
}
}
@@ -0,0 +1,69 @@
use std::str;
pub struct OutputBuffer {
bytes: Vec<u8>,
}
impl OutputBuffer {
pub fn new() -> Self {
OutputBuffer { bytes: Vec::new() }
}
pub fn write_u8(&mut self, value: u8) {
self.bytes.push(value);
}
pub fn write_u16(&mut self, value: u16) {
self.bytes.extend_from_slice(&value.to_le_bytes());
}
pub fn write_u32(&mut self, value: u32) {
self.bytes.extend_from_slice(&value.to_le_bytes());
}
pub fn write_str(&mut self, value: &str) {
self.bytes.extend_from_slice(value.as_bytes());
}
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
}
pub struct InputBuffer<'a> {
bytes: &'a [u8],
}
impl<'a> InputBuffer<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
InputBuffer { bytes }
}
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
pub fn read_u8(&mut self) -> u8 {
let (first, rest) = self.bytes.split_first().unwrap();
self.bytes = rest;
*first
}
pub fn read_u16(&mut self) -> u16 {
let (value, rest) = self.bytes.split_at(2);
self.bytes = rest;
u16::from_le_bytes([value[0], value[1]])
}
pub fn read_u32(&mut self) -> u32 {
let (value, rest) = self.bytes.split_at(4);
self.bytes = rest;
u32::from_le_bytes([value[0], value[1], value[2], value[3]])
}
pub fn read_str(&mut self, len: usize) -> &'a str {
let (string, rest) = self.bytes.split_at(len);
self.bytes = rest;
str::from_utf8(string).unwrap()
}
}
@@ -0,0 +1,17 @@
pub enum Bytecode {}
impl Bytecode {
pub const GROUP_PARENTHESIS: u8 = 0;
pub const GROUP_BRACE: u8 = 1;
pub const GROUP_BRACKET: u8 = 2;
pub const GROUP_NONE: u8 = 3;
pub const IDENT: u8 = 4;
pub const PUNCT_ALONE: u8 = 5;
pub const PUNCT_JOINT: u8 = 6;
pub const LITERAL: u8 = 7;
pub const LOAD_GROUP: u8 = 8;
pub const LOAD_IDENT: u8 = 9;
pub const LOAD_PUNCT: u8 = 10;
pub const LOAD_LITERAL: u8 = 11;
pub const SET_SPAN: u8 = 12;
}
+205
View File
@@ -0,0 +1,205 @@
pub mod buffer;
pub mod bytecode;
use crate::watt::buffer::{InputBuffer, OutputBuffer};
use crate::watt::bytecode::Bytecode;
use crate::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
use std::str::FromStr;
pub enum Kind {
Group(Delimiter),
Ident,
Punct(Spacing),
Literal,
}
pub enum Identity {}
impl Identity {
pub const RESPANNED: u32 = 1 << 31;
pub const NOVEL: u32 = u32::MAX;
}
impl Span {
fn is_call_site(&self) -> bool {
self.lo == 0 && self.hi == 0
}
}
fn post_increment(counter: &mut u32) -> impl FnMut() -> u32 + '_ {
|| {
let value = *counter;
*counter += 1;
value
}
}
pub fn load(buf: &mut InputBuffer) -> TokenStream {
let mut span_counter = 1;
let mut next_span = post_increment(&mut span_counter);
let mut next_span = || {
let next = next_span();
Span { lo: next, hi: next }
};
let [mut group_counter, mut ident_counter, mut punct_counter, mut literal_counter] = [0; 4];
let mut next_group = post_increment(&mut group_counter);
let mut next_ident = post_increment(&mut ident_counter);
let mut next_punct = post_increment(&mut punct_counter);
let mut next_literal = post_increment(&mut literal_counter);
let mut trees = Vec::new();
while !buf.is_empty() {
match match buf.read_u8() {
Bytecode::GROUP_PARENTHESIS => Kind::Group(Delimiter::Parenthesis),
Bytecode::GROUP_BRACE => Kind::Group(Delimiter::Brace),
Bytecode::GROUP_BRACKET => Kind::Group(Delimiter::Bracket),
Bytecode::GROUP_NONE => Kind::Group(Delimiter::None),
Bytecode::IDENT => Kind::Ident,
Bytecode::PUNCT_ALONE => Kind::Punct(Spacing::Alone),
Bytecode::PUNCT_JOINT => Kind::Punct(Spacing::Joint),
Bytecode::LITERAL => Kind::Literal,
_ => unreachable!(),
} {
Kind::Group(delimiter) => {
let len = buf.read_u32();
let stream = trees.drain(trees.len() - len as usize..).collect();
trees.push(TokenTree::Group(Group {
delimiter,
stream,
span: next_span(),
span_open: next_span(),
span_close: next_span(),
identity: next_group(),
}));
}
Kind::Ident => {
let len = buf.read_u16();
let repr = buf.read_str(len as usize);
let ident = if let Some(repr) = repr.strip_prefix("r#") {
proc_macro2::Ident::new_raw(repr, proc_macro2::Span::call_site())
} else if repr == "$crate" {
proc_macro2::Ident::new("crate", proc_macro2::Span::call_site())
} else {
proc_macro2::Ident::new(repr, proc_macro2::Span::call_site())
};
trees.push(TokenTree::Ident(Ident {
fallback: ident,
span: next_span(),
identity: next_ident(),
}));
}
Kind::Punct(spacing) => {
let ch = buf.read_u8();
assert!(ch.is_ascii());
let punct = proc_macro2::Punct::new(ch as char, spacing);
trees.push(TokenTree::Punct(Punct {
fallback: punct,
span: next_span(),
identity: next_punct(),
}));
}
Kind::Literal => {
let len = buf.read_u16();
let repr = buf.read_str(len as usize);
let literal = proc_macro2::Literal::from_str(repr).unwrap();
trees.push(TokenTree::Literal(Literal {
fallback: literal,
span: next_span(),
identity: next_literal(),
}));
}
}
}
TokenStream { content: trees }
}
pub fn linearize(tokens: TokenStream) -> Vec<u8> {
let mut buf = OutputBuffer::new();
for token in &tokens.content {
linearize_token(token, &mut buf);
}
buf.into_bytes()
}
fn linearize_token(token: &TokenTree, buf: &mut OutputBuffer) {
let needs_span;
match token {
TokenTree::Group(group) => {
if group.identity < Identity::NOVEL {
buf.write_u8(Bytecode::LOAD_GROUP);
buf.write_u32(group.identity & !Identity::RESPANNED);
needs_span = group.identity >= Identity::RESPANNED;
} else {
let len = group.stream.len();
assert!(len <= u32::MAX as usize);
for token in &group.stream {
linearize_token(token, buf);
}
buf.write_u8(match group.delimiter {
Delimiter::Parenthesis => Bytecode::GROUP_PARENTHESIS,
Delimiter::Brace => Bytecode::GROUP_BRACE,
Delimiter::Bracket => Bytecode::GROUP_BRACKET,
Delimiter::None => Bytecode::GROUP_NONE,
});
buf.write_u32(len as u32);
needs_span = !group.span.is_call_site();
}
}
TokenTree::Ident(ident) => {
if ident.identity < Identity::NOVEL {
buf.write_u8(Bytecode::LOAD_IDENT);
buf.write_u32(ident.identity & !Identity::RESPANNED);
needs_span = ident.identity >= Identity::RESPANNED;
} else {
buf.write_u8(Bytecode::IDENT);
let repr = ident.to_string();
assert!(repr.len() <= u16::MAX as usize);
buf.write_u16(repr.len() as u16);
buf.write_str(&repr);
linearize_span(ident.span, buf);
needs_span = false;
}
}
TokenTree::Punct(punct) => {
if punct.identity < Identity::NOVEL {
buf.write_u8(Bytecode::LOAD_PUNCT);
buf.write_u32(punct.identity & !Identity::RESPANNED);
needs_span = punct.identity >= Identity::RESPANNED;
} else {
buf.write_u8(match punct.spacing() {
Spacing::Alone => Bytecode::PUNCT_ALONE,
Spacing::Joint => Bytecode::PUNCT_JOINT,
});
let ch = punct.as_char();
assert!(ch.is_ascii());
buf.write_u8(ch as u8);
needs_span = !punct.span.is_call_site();
}
}
TokenTree::Literal(literal) => {
if literal.identity < Identity::NOVEL {
buf.write_u8(Bytecode::LOAD_LITERAL);
buf.write_u32(literal.identity & !Identity::RESPANNED);
needs_span = literal.identity >= Identity::RESPANNED;
} else {
buf.write_u8(Bytecode::LITERAL);
let repr = literal.to_string();
assert!(repr.len() <= u16::MAX as usize);
buf.write_u16(repr.len() as u16);
buf.write_str(&repr);
needs_span = !literal.span.is_call_site();
}
}
}
if needs_span {
buf.write_u8(Bytecode::SET_SPAN);
linearize_span(token.span(), buf);
}
}
fn linearize_span(span: Span, buf: &mut OutputBuffer) {
buf.write_u32(span.lo);
buf.write_u32(span.hi);
}
+36
View File
@@ -0,0 +1,36 @@
[package]
name = "serde_derive"
version = "1.0.178"
authors = ["David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std", "no-std::no-alloc"]
description = "Implementation of #[derive(Serialize, Deserialize)]"
documentation = "https://serde.rs/derive.html"
edition = "2015"
homepage = "https://serde.rs"
include = ["serde_derive-x86_64-unknown-linux-gnu", "src", "LICENSE-APACHE", "LICENSE-MIT"]
keywords = ["serde", "serialization", "no_std", "derive"]
license = "MIT OR Apache-2.0"
readme = "crates-io.md"
repository = "https://github.com/serde-rs/serde"
rust-version = "1.56"
[features]
default = []
deserialize_in_place = []
[lib]
proc-macro = true
[target.'cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))'.dependencies]
proc-macro2 = "1"
quote = "1"
syn = "2.0.25"
[dev-dependencies]
serde = { version = "1", path = "../../serde" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]
[workspace]
+1
View File
@@ -0,0 +1 @@
../../LICENSE-APACHE
+1
View File
@@ -0,0 +1 @@
../../LICENSE-MIT
+1
View File
@@ -0,0 +1 @@
../../README.md
+1
View File
@@ -0,0 +1 @@
../../crates-io.md
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/bound.rs
+1
View File
@@ -0,0 +1 @@
../../proc-macro2/src/watt/buffer.rs
+1
View File
@@ -0,0 +1 @@
../../proc-macro2/src/watt/bytecode.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/de.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/dummy.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/fragment.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/internals/
+22
View File
@@ -0,0 +1,22 @@
//! This crate provides Serde's two derive macros.
//!
//! ```edition2021
//! # use serde_derive::{Deserialize, Serialize};
//! #
//! #[derive(Serialize, Deserialize)]
//! # struct S;
//! #
//! # fn main() {}
//! ```
//!
//! Please refer to [https://serde.rs/derive.html] for how to set this up.
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.178")]
#[cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))]
include!("lib_from_source.rs");
#[cfg(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu"))]
include!("lib_precompiled.rs");
@@ -0,0 +1,35 @@
extern crate proc_macro;
extern crate proc_macro2;
extern crate quote;
extern crate syn;
#[macro_use]
mod bound;
#[macro_use]
mod fragment;
mod de;
mod dummy;
mod internals;
mod pretend;
mod ser;
mod this;
use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
ser::expand_derive_serialize(&mut input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
de::expand_derive_deserialize(&mut input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
@@ -0,0 +1,234 @@
extern crate proc_macro;
mod buffer;
mod bytecode;
use crate::buffer::{InputBuffer, OutputBuffer};
use crate::bytecode::Bytecode;
use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
use std::io::{ErrorKind, Read, Write};
use std::iter::FromIterator;
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};
use std::str::FromStr;
#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
derive(0, input)
}
#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
derive(1 + cfg!(feature = "deserialize_in_place") as u8, input)
}
fn derive(select: u8, input: TokenStream) -> TokenStream {
let mut memory = TokenMemory::default();
let mut buf = OutputBuffer::new();
buf.write_u8(select);
memory.spans.push(Span::call_site());
for token in input {
memory.linearize_token(token, &mut buf);
}
let exe_path = Path::new(concat!(
env!("CARGO_MANIFEST_DIR"),
"/serde_derive-x86_64-unknown-linux-gnu",
));
let mut child = match Command::new(exe_path)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
{
Ok(child) => child,
Err(io_error) => {
if io_error.kind() == ErrorKind::NotFound {
panic!(
"file missing from serde_derive manifest directory during macro expansion: {}",
exe_path.display(),
);
} else {
panic!("failed to spawn process: {}", io_error);
}
}
};
let mut stdin = child.stdin.take().unwrap();
let mut buf = buf.into_bytes();
stdin.write_all(&buf).unwrap();
drop(stdin);
let mut stdout = child.stdout.take().unwrap();
buf.clear();
stdout.read_to_end(&mut buf).unwrap();
let success = child.wait().as_ref().map_or(true, ExitStatus::success);
if !success || buf.is_empty() {
panic!();
}
let mut buf = InputBuffer::new(&buf);
memory.receive(&mut buf)
}
#[derive(Default)]
struct TokenMemory {
spans: Vec<Span>,
groups: Vec<Group>,
idents: Vec<Ident>,
puncts: Vec<Punct>,
literals: Vec<Literal>,
}
enum Kind {
Group(Delimiter),
Ident,
Punct(Spacing),
Literal,
}
impl TokenMemory {
// Depth-first post-order traversal.
fn linearize_token(&mut self, token: TokenTree, buf: &mut OutputBuffer) {
match token {
TokenTree::Group(group) => {
let mut len = 0usize;
for token in group.stream() {
self.linearize_token(token, buf);
len += 1;
}
assert!(len <= u32::MAX as usize);
buf.write_u8(match group.delimiter() {
Delimiter::Parenthesis => Bytecode::GROUP_PARENTHESIS,
Delimiter::Brace => Bytecode::GROUP_BRACE,
Delimiter::Bracket => Bytecode::GROUP_BRACKET,
Delimiter::None => Bytecode::GROUP_NONE,
});
buf.write_u32(len as u32);
self.spans
.extend([group.span(), group.span_open(), group.span_close()]);
self.groups.push(group);
}
TokenTree::Ident(ident) => {
buf.write_u8(Bytecode::IDENT);
let repr = ident.to_string();
assert!(repr.len() <= u16::MAX as usize);
buf.write_u16(repr.len() as u16);
buf.write_str(&repr);
self.spans.push(ident.span());
self.idents.push(ident);
}
TokenTree::Punct(punct) => {
buf.write_u8(match punct.spacing() {
Spacing::Alone => Bytecode::PUNCT_ALONE,
Spacing::Joint => Bytecode::PUNCT_JOINT,
});
let ch = punct.as_char();
assert!(ch.is_ascii());
buf.write_u8(ch as u8);
self.spans.push(punct.span());
self.puncts.push(punct);
}
TokenTree::Literal(literal) => {
buf.write_u8(Bytecode::LITERAL);
let repr = literal.to_string();
assert!(repr.len() <= u16::MAX as usize);
buf.write_u16(repr.len() as u16);
buf.write_str(&repr);
self.spans.push(literal.span());
self.literals.push(literal);
}
}
}
fn receive(&self, buf: &mut InputBuffer) -> TokenStream {
let mut trees = Vec::new();
while !buf.is_empty() {
match match buf.read_u8() {
Bytecode::GROUP_PARENTHESIS => Kind::Group(Delimiter::Parenthesis),
Bytecode::GROUP_BRACE => Kind::Group(Delimiter::Brace),
Bytecode::GROUP_BRACKET => Kind::Group(Delimiter::Bracket),
Bytecode::GROUP_NONE => Kind::Group(Delimiter::None),
Bytecode::IDENT => Kind::Ident,
Bytecode::PUNCT_ALONE => Kind::Punct(Spacing::Alone),
Bytecode::PUNCT_JOINT => Kind::Punct(Spacing::Joint),
Bytecode::LITERAL => Kind::Literal,
Bytecode::LOAD_GROUP => {
let identity = buf.read_u32();
let group = self.groups[identity as usize].clone();
trees.push(TokenTree::Group(group));
continue;
}
Bytecode::LOAD_IDENT => {
let identity = buf.read_u32();
let ident = self.idents[identity as usize].clone();
trees.push(TokenTree::Ident(ident));
continue;
}
Bytecode::LOAD_PUNCT => {
let identity = buf.read_u32();
let punct = self.puncts[identity as usize].clone();
trees.push(TokenTree::Punct(punct));
continue;
}
Bytecode::LOAD_LITERAL => {
let identity = buf.read_u32();
let literal = self.literals[identity as usize].clone();
trees.push(TokenTree::Literal(literal));
continue;
}
Bytecode::SET_SPAN => {
trees.last_mut().unwrap().set_span(self.read_span(buf));
continue;
}
_ => unreachable!(),
} {
Kind::Group(delimiter) => {
let len = buf.read_u32();
let stream = trees.drain(trees.len() - len as usize..).collect();
let group = Group::new(delimiter, stream);
trees.push(TokenTree::Group(group));
}
Kind::Ident => {
let len = buf.read_u16();
let repr = buf.read_str(len as usize);
let span = self.read_span(buf);
let ident = if let Some(repr) = repr.strip_prefix("r#") {
Ident::new_raw(repr, span)
} else {
Ident::new(repr, span)
};
trees.push(TokenTree::Ident(ident));
}
Kind::Punct(spacing) => {
let ch = buf.read_u8();
assert!(ch.is_ascii());
let punct = Punct::new(ch as char, spacing);
trees.push(TokenTree::Punct(punct));
}
Kind::Literal => {
let len = buf.read_u16();
let repr = buf.read_str(len as usize);
let literal = Literal::from_str(repr).unwrap();
trees.push(TokenTree::Literal(literal));
}
}
}
TokenStream::from_iter(trees)
}
fn read_span(&self, buf: &mut InputBuffer) -> Span {
let lo = buf.read_u32();
let hi = buf.read_u32();
let span = self.spans[lo as usize];
if lo == hi {
span
} else {
#[cfg(any())] // FIXME
return span.join(self.spans[hi as usize]).unwrap_or(span);
span
}
}
}
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/pretend.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/ser.rs
+1
View File
@@ -0,0 +1 @@
../../../serde_derive/src/this.rs
+4 -4
View File
@@ -1,13 +1,12 @@
[package]
name = "serde"
version = "1.0.170" # remember to update html_root_url and serde_derive dependency
version = "1.0.178" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["encoding", "no-std", "no-std::no-alloc"]
description = "A generic serialization/deserialization framework"
documentation = "https://docs.rs/serde"
homepage = "https://serde.rs"
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
keywords = ["serde", "serialization", "no_std"]
license = "MIT OR Apache-2.0"
readme = "crates-io.md"
@@ -15,10 +14,10 @@ repository = "https://github.com/serde-rs/serde"
rust-version = "1.19"
[dependencies]
serde_derive = { version = "=1.0.170", optional = true, path = "../serde_derive" }
serde_derive = { version = "=1.0.178", optional = true, path = "../serde_derive" }
[dev-dependencies]
serde_derive = { version = "1.0", path = "../serde_derive" }
serde_derive = { version = "1", path = "../serde_derive" }
[lib]
doc-scrape-examples = false
@@ -29,6 +28,7 @@ features = ["derive", "rc"]
[package.metadata.docs.rs]
features = ["derive"]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]
### FEATURES #################################################################
+4 -1
View File
@@ -126,10 +126,13 @@ mod utf8;
pub use self::ignored_any::IgnoredAny;
#[cfg(all(feature = "unstable", not(feature = "std")))]
#[doc(no_inline)]
pub use core::error::Error as StdError;
#[cfg(feature = "std")]
#[doc(no_inline)]
pub use std::error::Error as StdError;
#[cfg(not(feature = "std"))]
#[cfg(not(any(feature = "std", feature = "unstable")))]
#[doc(no_inline)]
pub use std_error::Error as StdError;
+3 -3
View File
@@ -93,7 +93,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.170")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.178")]
// 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
@@ -149,6 +149,8 @@
must_use_candidate,
)
)]
// Restrictions
#![cfg_attr(feature = "cargo-clippy", deny(question_mark_used))]
// Rustc lints.
#![deny(missing_docs, unused_imports)]
@@ -335,8 +337,6 @@ mod std_error;
// be annoying for crates that provide handwritten impls or data formats. They
// would need to disable default features and then explicitly re-enable std.
#[cfg(feature = "serde_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
/// Derive macro available if serde is built with `features = ["derive"]`.
+1 -1
View File
@@ -116,7 +116,7 @@ mod impossible;
pub use self::impossible::Impossible;
#[cfg(all(feature = "unstable", not(feature = "std")))]
#[doc(inline)]
#[doc(no_inline)]
pub use core::error::Error as StdError;
#[cfg(feature = "std")]
#[doc(no_inline)]
+3 -3
View File
@@ -1,12 +1,11 @@
[package]
name = "serde_derive"
version = "1.0.170" # remember to update html_root_url
version = "1.0.178" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std", "no-std::no-alloc"]
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
documentation = "https://serde.rs/derive.html"
homepage = "https://serde.rs"
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
keywords = ["serde", "serialization", "no_std", "derive"]
license = "MIT OR Apache-2.0"
readme = "crates-io.md"
@@ -27,7 +26,8 @@ quote = "1.0"
syn = "2.0.25"
[dev-dependencies]
serde = { version = "1.0", path = "../serde" }
serde = { version = "1", path = "../serde" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]
+5 -8
View File
@@ -1,12 +1,9 @@
use std::collections::HashSet;
use syn;
use syn::punctuated::{Pair, Punctuated};
use internals::ast::{Container, Data};
use internals::{attr, ungroup};
use crate::internals::ast::{Container, Data};
use crate::internals::{attr, ungroup};
use proc_macro2::Span;
use std::collections::HashSet;
use syn::punctuated::{Pair, Punctuated};
use syn::Token;
// Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not
+73 -58
View File
@@ -1,19 +1,16 @@
use crate::fragment::{Expr, Fragment, Match, Stmts};
use crate::internals::ast::{Container, Data, Field, Style, Variant};
use crate::internals::{attr, replace_receiver, ungroup, Ctxt, Derive};
use crate::{bound, dummy, pretend, this};
use proc_macro2::{Literal, Span, TokenStream};
use quote::ToTokens;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{self, Ident, Index, Member};
use bound;
use dummy;
use fragment::{Expr, Fragment, Match, Stmts};
use internals::ast::{Container, Data, Field, Style, Variant};
use internals::{attr, replace_receiver, ungroup, Ctxt, Derive};
use pretend;
use this;
use quote::{quote, quote_spanned, ToTokens};
use std::collections::BTreeSet;
use std::ptr;
#[cfg(precompiled)]
use std::sync::atomic::Ordering;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{parse_quote, Ident, Index, Member};
pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
replace_receiver(input);
@@ -304,6 +301,11 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
#[cfg(feature = "deserialize_in_place")]
fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<Stmts> {
#[cfg(precompiled)]
if !crate::DESERIALIZE_IN_PLACE.load(Ordering::Relaxed) {
return None;
}
// Only remote derives have getters, and we do not generate
// deserialize_in_place for remote derives.
assert!(!params.has_getter);
@@ -410,16 +412,22 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
let this_type = &params.this_type;
let this_value = &params.this_value;
let type_name = cattrs.name().deserialize_name();
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime();
let expecting = format!("unit struct {}", params.type_name());
let expecting = cattrs.expecting().unwrap_or(&expecting);
quote_block! {
#[doc(hidden)]
struct __Visitor;
struct __Visitor #de_impl_generics #where_clause {
marker: _serde::__private::PhantomData<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData<&#delife ()>,
}
impl<'de> _serde::de::Visitor<'de> for __Visitor {
type Value = #this_type;
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
type Value = #this_type #ty_generics;
fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result {
_serde::__private::Formatter::write_str(__formatter, #expecting)
@@ -434,7 +442,14 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra
}
}
_serde::Deserializer::deserialize_unit_struct(__deserializer, #type_name, __Visitor)
_serde::Deserializer::deserialize_unit_struct(
__deserializer,
#type_name,
__Visitor {
marker: _serde::__private::PhantomData::<#this_type #ty_generics>,
lifetime: _serde::__private::PhantomData,
},
)
}
}
@@ -695,14 +710,14 @@ fn deserialize_seq(
let span = field.original.span();
let func =
quote_spanned!(span=> _serde::de::SeqAccess::next_element::<#field_ty>);
quote!(try!(#func(&mut __seq)))
quote!(#func(&mut __seq)?)
}
Some(path) => {
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
quote!({
#wrapper
_serde::__private::Option::map(
try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)),
_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)?,
|__wrap| __wrap.value)
})
}
@@ -809,8 +824,8 @@ fn deserialize_seq_in_place(
let write = match field.attrs.deserialize_with() {
None => {
quote! {
if let _serde::__private::None = try!(_serde::de::SeqAccess::next_element_seed(&mut __seq,
_serde::__private::de::InPlaceSeed(&mut self.place.#member)))
if let _serde::__private::None = _serde::de::SeqAccess::next_element_seed(&mut __seq,
_serde::__private::de::InPlaceSeed(&mut self.place.#member))?
{
#value_if_none
}
@@ -820,7 +835,7 @@ fn deserialize_seq_in_place(
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
quote!({
#wrapper
match try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)) {
match _serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)? {
_serde::__private::Some(__wrap) => {
self.place.#member = __wrap.value;
}
@@ -872,12 +887,12 @@ fn deserialize_newtype_struct(
let span = field.original.span();
let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize);
quote! {
try!(#func(__e))
#func(__e)?
}
}
Some(path) => {
quote! {
try!(#path(__e))
#path(__e)?
}
}
};
@@ -1349,7 +1364,7 @@ fn deserialize_externally_tagged_enum(
}
} else {
quote! {
match try!(_serde::de::EnumAccess::variant(__data)) {
match _serde::de::EnumAccess::variant(__data)? {
#(#variant_arms)*
}
}
@@ -1429,9 +1444,9 @@ fn deserialize_internally_tagged_enum(
#variants_stmt
let (__tag, __content) = try!(_serde::Deserializer::deserialize_any(
let (__tag, __content) = _serde::Deserializer::deserialize_any(
__deserializer,
_serde::__private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting)));
_serde::__private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting))?;
let __deserializer = _serde::__private::de::ContentDeserializer::<__D::Error>::new(__content);
match __tag {
@@ -1539,7 +1554,7 @@ fn deserialize_adjacently_tagged_enum(
// Advance the map by one key, returning early in case of error.
let next_key = quote! {
try!(_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content))
_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content)?
};
// When allowing unknown fields, we want to transparently step through keys
@@ -1552,7 +1567,7 @@ fn deserialize_adjacently_tagged_enum(
while let _serde::__private::Some(__k) = #next_key {
match __k {
_serde::__private::de::TagContentOtherField::Other => {
let _ = try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map));
let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
continue;
},
_serde::__private::de::TagContentOtherField::Tag => {
@@ -1587,14 +1602,14 @@ fn deserialize_adjacently_tagged_enum(
let finish_content_then_tag = if variant_arms.is_empty() {
quote! {
match try!(_serde::de::MapAccess::next_value::<__Field>(&mut __map)) {}
match _serde::de::MapAccess::next_value::<__Field>(&mut __map)? {}
}
} else {
quote! {
let __ret = try!(match try!(_serde::de::MapAccess::next_value(&mut __map)) {
let __ret = match _serde::de::MapAccess::next_value(&mut __map)? {
// Deserialize the buffered content now that we know the variant.
#(#variant_arms)*
});
}?;
// Visit remaining keys, looking for duplicates.
#visit_remaining_keys
}
@@ -1647,7 +1662,7 @@ fn deserialize_adjacently_tagged_enum(
// First key is the tag.
_serde::__private::Some(_serde::__private::de::TagOrContentField::Tag) => {
// Parse the tag.
let __field = try!(_serde::de::MapAccess::next_value(&mut __map));
let __field = _serde::de::MapAccess::next_value(&mut __map)?;
// Visit the second key.
match #next_relevant_key {
// Second key is a duplicate of the tag.
@@ -1656,12 +1671,12 @@ fn deserialize_adjacently_tagged_enum(
}
// Second key is the content.
_serde::__private::Some(_serde::__private::de::TagOrContentField::Content) => {
let __ret = try!(_serde::de::MapAccess::next_value_seed(&mut __map,
let __ret = _serde::de::MapAccess::next_value_seed(&mut __map,
__Seed {
field: __field,
marker: _serde::__private::PhantomData,
lifetime: _serde::__private::PhantomData,
}));
})?;
// Visit remaining keys, looking for duplicates.
#visit_remaining_keys
}
@@ -1672,7 +1687,7 @@ fn deserialize_adjacently_tagged_enum(
// First key is the content.
_serde::__private::Some(_serde::__private::de::TagOrContentField::Content) => {
// Buffer up the content.
let __content = try!(_serde::de::MapAccess::next_value::<_serde::__private::de::Content>(&mut __map));
let __content = _serde::de::MapAccess::next_value::<_serde::__private::de::Content>(&mut __map)?;
// Visit the second key.
match #next_relevant_key {
// Second key is the tag.
@@ -1702,17 +1717,17 @@ fn deserialize_adjacently_tagged_enum(
__A: _serde::de::SeqAccess<#delife>,
{
// Visit the first element - the tag.
match try!(_serde::de::SeqAccess::next_element(&mut __seq)) {
match _serde::de::SeqAccess::next_element(&mut __seq)? {
_serde::__private::Some(__field) => {
// Visit the second element - the content.
match try!(_serde::de::SeqAccess::next_element_seed(
match _serde::de::SeqAccess::next_element_seed(
&mut __seq,
__Seed {
field: __field,
marker: _serde::__private::PhantomData,
lifetime: _serde::__private::PhantomData,
},
)) {
)? {
_serde::__private::Some(__ret) => _serde::__private::Ok(__ret),
// There is no second element.
_serde::__private::None => {
@@ -1782,7 +1797,7 @@ fn deserialize_untagged_enum_after(
let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg);
quote_block! {
let __content = try!(<_serde::__private::de::Content as _serde::Deserialize>::deserialize(__deserializer));
let __content = <_serde::__private::de::Content as _serde::Deserialize>::deserialize(__deserializer)?;
let __deserializer = _serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content);
#(
@@ -1815,7 +1830,7 @@ fn deserialize_externally_tagged_variant(
Style::Unit => {
let this_value = &params.this_value;
quote_block! {
try!(_serde::de::VariantAccess::unit_variant(__variant));
_serde::de::VariantAccess::unit_variant(__variant)?;
_serde::__private::Ok(#this_value::#variant_ident)
}
}
@@ -1864,7 +1879,7 @@ fn deserialize_internally_tagged_variant(
quote!((#default))
});
quote_block! {
try!(_serde::Deserializer::deserialize_any(#deserializer, _serde::__private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name)));
_serde::Deserializer::deserialize_any(#deserializer, _serde::__private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))?;
_serde::__private::Ok(#this_value::#variant_ident #default)
}
}
@@ -1950,7 +1965,7 @@ fn deserialize_externally_tagged_newtype_variant(
if field.attrs.skip_deserializing() {
let default = Expr(expr_is_missing(field, cattrs));
return quote_block! {
try!(_serde::de::VariantAccess::unit_variant(__variant));
_serde::de::VariantAccess::unit_variant(__variant)?;
_serde::__private::Ok(#this_value::#variant_ident(#default))
};
}
@@ -2525,7 +2540,7 @@ fn deserialize_map(
let func =
quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>);
quote! {
try!(#func(&mut __map))
#func(&mut __map)?
}
}
Some(path) => {
@@ -2557,14 +2572,14 @@ fn deserialize_map(
__Field::__other(__name) => {
__collect.push(_serde::__private::Some((
__name,
try!(_serde::de::MapAccess::next_value(&mut __map)))));
_serde::de::MapAccess::next_value(&mut __map)?)));
}
})
} else if cattrs.deny_unknown_fields() {
None
} else {
Some(quote! {
_ => { let _ = try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)); }
_ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; }
})
};
@@ -2572,14 +2587,14 @@ fn deserialize_map(
let match_keys = if cattrs.deny_unknown_fields() && all_skipped {
quote! {
// FIXME: Once feature(exhaustive_patterns) is stable:
// let _serde::__private::None::<__Field> = try!(_serde::de::MapAccess::next_key(&mut __map));
// let _serde::__private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?;
_serde::__private::Option::map(
try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)),
_serde::de::MapAccess::next_key::<__Field>(&mut __map)?,
|__impossible| match __impossible {});
}
} else {
quote! {
while let _serde::__private::Some(__key) = try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)) {
while let _serde::__private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
match __key {
#(#value_arms)*
#ignored_arm
@@ -2615,10 +2630,10 @@ fn deserialize_map(
Some(path) => quote!(#path),
};
quote! {
let #name: #field_ty = try!(#func(
let #name: #field_ty = #func(
_serde::__private::de::FlatMapDeserializer(
&mut __collect,
_serde::__private::PhantomData)));
_serde::__private::PhantomData))?;
}
});
@@ -2765,7 +2780,7 @@ fn deserialize_map_in_place(
let visit = match field.attrs.deserialize_with() {
None => {
quote! {
try!(_serde::de::MapAccess::next_value_seed(&mut __map, _serde::__private::de::InPlaceSeed(&mut self.place.#member)))
_serde::de::MapAccess::next_value_seed(&mut __map, _serde::__private::de::InPlaceSeed(&mut self.place.#member))?
}
}
Some(path) => {
@@ -2797,7 +2812,7 @@ fn deserialize_map_in_place(
None
} else {
Some(quote! {
_ => { let _ = try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)); }
_ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; }
})
};
@@ -2806,14 +2821,14 @@ fn deserialize_map_in_place(
let match_keys = if cattrs.deny_unknown_fields() && all_skipped {
quote! {
// FIXME: Once feature(exhaustive_patterns) is stable:
// let _serde::__private::None::<__Field> = try!(_serde::de::MapAccess::next_key(&mut __map));
// let _serde::__private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?;
_serde::__private::Option::map(
try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)),
_serde::de::MapAccess::next_key::<__Field>(&mut __map)?,
|__impossible| match __impossible {});
}
} else {
quote! {
while let _serde::__private::Some(__key) = try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)) {
while let _serde::__private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
match __key {
#(#value_arms_from)*
#ignored_arm
@@ -2910,7 +2925,7 @@ fn wrap_deserialize_with(
__D: _serde::Deserializer<#delife>,
{
_serde::__private::Ok(__DeserializeWith {
value: try!(#deserialize_with(__deserializer)),
value: #deserialize_with(__deserializer)?,
phantom: _serde::__private::PhantomData,
lifetime: _serde::__private::PhantomData,
})
@@ -3020,7 +3035,7 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
let span = field.original.span();
let func = quote_spanned!(span=> _serde::__private::de::missing_field);
quote_expr! {
try!(#func(#name))
#func(#name)?
}
}
Some(_) => {
+1 -6
View File
@@ -1,11 +1,7 @@
use proc_macro2::TokenStream;
use syn;
use try;
use quote::quote;
pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream {
let try_replacement = try::replacement();
let use_serde = match serde_path {
Some(path) => quote! {
use #path as _serde;
@@ -21,7 +17,6 @@ pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> Token
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const _: () = {
#use_serde
#try_replacement
#code
};
}
+1 -1
View File
@@ -1,6 +1,6 @@
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::token;
use syn::{token, Token};
pub enum Fragment {
/// Tokens that can be used as an expression.
+9 -8
View File
@@ -1,10 +1,8 @@
//! A Serde ast, parsed from the Syn ast and ready to generate Rust code.
use internals::attr;
use internals::check;
use internals::{Ctxt, Derive};
use syn;
use crate::internals::{attr, check, Ctxt, Derive};
use syn::punctuated::Punctuated;
use syn::Token;
/// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`,
/// parsed into an internal representation.
@@ -88,9 +86,12 @@ impl<'a> Container<'a> {
if field.attrs.flatten() {
has_flatten = true;
}
field
.attrs
.rename_by_rules(variant.attrs.rename_all_rules());
field.attrs.rename_by_rules(
variant
.attrs
.rename_all_rules()
.or(attrs.rename_all_fields_rules()),
);
}
}
}
@@ -121,7 +122,7 @@ impl<'a> Container<'a> {
}
impl<'a> Data<'a> {
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
pub fn all_fields(&'a self) -> Box<dyn Iterator<Item = &'a Field<'a>> + 'a> {
match self {
Data::Enum(variants) => {
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
+91 -31
View File
@@ -1,15 +1,14 @@
use internals::symbol::*;
use internals::{ungroup, Ctxt};
use crate::internals::symbol::*;
use crate::internals::{ungroup, Ctxt};
use proc_macro2::{Spacing, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::borrow::Cow;
use std::collections::BTreeSet;
use std::iter::FromIterator;
use syn;
use syn::meta::ParseNestedMeta;
use syn::parse::ParseStream;
use syn::punctuated::Punctuated;
use syn::{token, Ident, Lifetime};
use syn::{parse_quote, token, Ident, Lifetime, Token};
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints
// are `attr::Container::from_ast`, `attr::Variant::from_ast`, and
@@ -19,7 +18,7 @@ use syn::{token, Ident, Lifetime};
// user will see errors simultaneously for all bad attributes in the crate
// rather than just the first.
pub use internals::case::RenameRule;
pub use crate::internals::case::RenameRule;
struct Attr<'c, T> {
cx: &'c Ctxt,
@@ -193,11 +192,23 @@ impl Name {
}
}
#[derive(Copy, Clone)]
pub struct RenameAllRules {
serialize: RenameRule,
deserialize: RenameRule,
}
impl RenameAllRules {
/// Returns a new `RenameAllRules` with the individual rules of `self` and
/// `other_rules` joined by `RenameRules::or`.
pub fn or(self, other_rules: Self) -> Self {
Self {
serialize: self.serialize.or(other_rules.serialize),
deserialize: self.deserialize.or(other_rules.deserialize),
}
}
}
/// Represents struct or enum attribute information.
pub struct Container {
name: Name,
@@ -205,6 +216,7 @@ pub struct Container {
deny_unknown_fields: bool,
default: Default,
rename_all_rules: RenameAllRules,
rename_all_fields_rules: RenameAllRules,
ser_bound: Option<Vec<syn::WherePredicate>>,
de_bound: Option<Vec<syn::WherePredicate>>,
tag: TagType,
@@ -288,6 +300,8 @@ impl Container {
let mut default = Attr::none(cx, DEFAULT);
let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL);
let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL);
let mut rename_all_fields_ser_rule = Attr::none(cx, RENAME_ALL_FIELDS);
let mut rename_all_fields_de_rule = Attr::none(cx, RENAME_ALL_FIELDS);
let mut ser_bound = Attr::none(cx, BOUND);
let mut de_bound = Attr::none(cx, BOUND);
let mut untagged = BoolAttr::none(cx, UNTAGGED);
@@ -341,6 +355,44 @@ impl Container {
}
}
}
} else if meta.path == RENAME_ALL_FIELDS {
// #[serde(rename_all_fields = "foo")]
// #[serde(rename_all_fields(serialize = "foo", deserialize = "bar"))]
let one_name = meta.input.peek(Token![=]);
let (ser, de) = get_renames(cx, RENAME_ALL_FIELDS, &meta)?;
match item.data {
syn::Data::Enum(_) => {
if let Some(ser) = ser {
match RenameRule::from_str(&ser.value()) {
Ok(rename_rule) => {
rename_all_fields_ser_rule.set(&meta.path, rename_rule);
}
Err(err) => cx.error_spanned_by(ser, err),
}
}
if let Some(de) = de {
match RenameRule::from_str(&de.value()) {
Ok(rename_rule) => {
rename_all_fields_de_rule.set(&meta.path, rename_rule);
}
Err(err) => {
if !one_name {
cx.error_spanned_by(de, err);
}
}
}
}
}
syn::Data::Struct(_) => {
let msg = "#[serde(rename_all_fields)] can only be used on enums";
cx.syn_error(meta.error(msg));
}
syn::Data::Union(_) => {
let msg = "#[serde(rename_all_fields)] can only be used on enums";
cx.syn_error(meta.error(msg));
}
}
} else if meta.path == TRANSPARENT {
// #[serde(transparent)]
transparent.set_true(meta.path);
@@ -358,16 +410,16 @@ impl Container {
}
syn::Fields::Unnamed(_) | syn::Fields::Unit => {
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
cx.error_spanned_by(fields, msg);
cx.syn_error(meta.error(msg));
}
},
syn::Data::Enum(syn::DataEnum { enum_token, .. }) => {
syn::Data::Enum(_) => {
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
cx.error_spanned_by(enum_token, msg);
cx.syn_error(meta.error(msg));
}
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
syn::Data::Union(_) => {
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
cx.error_spanned_by(union_token, msg);
cx.syn_error(meta.error(msg));
}
}
}
@@ -383,13 +435,13 @@ impl Container {
cx.error_spanned_by(fields, msg);
}
},
syn::Data::Enum(syn::DataEnum { enum_token, .. }) => {
syn::Data::Enum(_) => {
let msg = "#[serde(default)] can only be used on structs with named fields";
cx.error_spanned_by(enum_token, msg);
cx.syn_error(meta.error(msg));
}
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
syn::Data::Union(_) => {
let msg = "#[serde(default)] can only be used on structs with named fields";
cx.error_spanned_by(union_token, msg);
cx.syn_error(meta.error(msg));
}
}
}
@@ -405,13 +457,13 @@ impl Container {
syn::Data::Enum(_) => {
untagged.set_true(&meta.path);
}
syn::Data::Struct(syn::DataStruct { struct_token, .. }) => {
syn::Data::Struct(_) => {
let msg = "#[serde(untagged)] can only be used on enums";
cx.error_spanned_by(struct_token, msg);
cx.syn_error(meta.error(msg));
}
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
syn::Data::Union(_) => {
let msg = "#[serde(untagged)] can only be used on enums";
cx.error_spanned_by(union_token, msg);
cx.syn_error(meta.error(msg));
}
}
} else if meta.path == TAG {
@@ -427,12 +479,12 @@ impl Container {
}
syn::Fields::Unnamed(_) | syn::Fields::Unit => {
let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields";
cx.error_spanned_by(fields, msg);
cx.syn_error(meta.error(msg));
}
},
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
syn::Data::Union(_) => {
let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields";
cx.error_spanned_by(union_token, msg);
cx.syn_error(meta.error(msg));
}
}
}
@@ -443,13 +495,13 @@ impl Container {
syn::Data::Enum(_) => {
content.set(&meta.path, s.value());
}
syn::Data::Struct(syn::DataStruct { struct_token, .. }) => {
syn::Data::Struct(_) => {
let msg = "#[serde(content = \"...\")] can only be used on enums";
cx.error_spanned_by(struct_token, msg);
cx.syn_error(meta.error(msg));
}
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
syn::Data::Union(_) => {
let msg = "#[serde(content = \"...\")] can only be used on enums";
cx.error_spanned_by(union_token, msg);
cx.syn_error(meta.error(msg));
}
}
}
@@ -528,6 +580,10 @@ impl Container {
serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None),
deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None),
},
rename_all_fields_rules: RenameAllRules {
serialize: rename_all_fields_ser_rule.get().unwrap_or(RenameRule::None),
deserialize: rename_all_fields_de_rule.get().unwrap_or(RenameRule::None),
},
ser_bound: ser_bound.get(),
de_bound: de_bound.get(),
tag: decide_tag(cx, item, untagged, internal_tag, content),
@@ -547,8 +603,12 @@ impl Container {
&self.name
}
pub fn rename_all_rules(&self) -> &RenameAllRules {
&self.rename_all_rules
pub fn rename_all_rules(&self) -> RenameAllRules {
self.rename_all_rules
}
pub fn rename_all_fields_rules(&self) -> RenameAllRules {
self.rename_all_fields_rules
}
pub fn transparent(&self) -> bool {
@@ -921,7 +981,7 @@ impl Variant {
self.name.deserialize_aliases()
}
pub fn rename_by_rules(&mut self, rules: &RenameAllRules) {
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
if !self.name.serialize_renamed {
self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize);
}
@@ -930,8 +990,8 @@ impl Variant {
}
}
pub fn rename_all_rules(&self) -> &RenameAllRules {
&self.rename_all_rules
pub fn rename_all_rules(&self) -> RenameAllRules {
self.rename_all_rules
}
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
@@ -1260,7 +1320,7 @@ impl Field {
self.name.deserialize_aliases()
}
pub fn rename_by_rules(&mut self, rules: &RenameAllRules) {
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
if !self.name.serialize_renamed {
self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize);
}
+13 -10
View File
@@ -1,13 +1,8 @@
//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the
//! case of the source (e.g. `my-field`, `MY_FIELD`).
// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
use std::fmt::{self, Debug, Display};
use self::RenameRule::*;
use std::fmt::{self, Debug, Display};
/// The different possible ways to change case of fields in a struct, or variants in an enum.
#[derive(Copy, Clone, PartialEq)]
@@ -59,8 +54,8 @@ impl RenameRule {
}
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
pub fn apply_to_variant(&self, variant: &str) -> String {
match *self {
pub fn apply_to_variant(self, variant: &str) -> String {
match self {
None | PascalCase => variant.to_owned(),
LowerCase => variant.to_ascii_lowercase(),
UpperCase => variant.to_ascii_uppercase(),
@@ -84,8 +79,8 @@ impl RenameRule {
}
/// Apply a renaming rule to a struct field, returning the version expected in the source.
pub fn apply_to_field(&self, field: &str) -> String {
match *self {
pub fn apply_to_field(self, field: &str) -> String {
match self {
None | LowerCase | SnakeCase => field.to_owned(),
UpperCase => field.to_ascii_uppercase(),
PascalCase => {
@@ -112,6 +107,14 @@ impl RenameRule {
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
}
}
/// Returns the `RenameRule` if it is not `None`, `rule_b` otherwise.
pub fn or(self, rule_b: Self) -> Self {
match self {
None => rule_b,
_ => self,
}
}
}
pub struct ParseError<'a> {
+7 -5
View File
@@ -1,6 +1,6 @@
use internals::ast::{Container, Data, Field, Style};
use internals::attr::{Identifier, TagType};
use internals::{ungroup, Ctxt, Derive};
use crate::internals::ast::{Container, Data, Field, Style};
use crate::internals::attr::{Identifier, TagType};
use crate::internals::{ungroup, Ctxt, Derive};
use syn::{Member, Type};
// Cross-cutting checks that require looking at more than a single attrs object.
@@ -285,8 +285,10 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
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 check_ser =
!(field.attrs.skip_serializing() || variant.attrs.skip_serializing());
let check_de =
!(field.attrs.skip_deserializing() || variant.attrs.skip_deserializing());
let name = field.attrs.name();
let ser_name = name.serialize_name();
-1
View File
@@ -2,7 +2,6 @@ use quote::ToTokens;
use std::cell::RefCell;
use std::fmt::Display;
use std::thread;
use syn;
/// A type to collect errors together and format them.
///
+5 -6
View File
@@ -1,19 +1,18 @@
pub mod ast;
pub mod attr;
mod ctxt;
pub use self::ctxt::Ctxt;
mod receiver;
pub use self::receiver::replace_receiver;
mod case;
mod check;
mod ctxt;
mod receiver;
mod respan;
mod symbol;
use syn::Type;
pub use self::ctxt::Ctxt;
pub use self::receiver::replace_receiver;
#[derive(Copy, Clone)]
pub enum Derive {
Serialize,
+2 -2
View File
@@ -1,11 +1,11 @@
use internals::respan::respan;
use crate::internals::respan::respan;
use proc_macro2::Span;
use quote::ToTokens;
use std::mem;
use syn::punctuated::Punctuated;
use syn::{
parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro,
Path, PathArguments, QSelf, ReturnType, Type, TypeParamBound, TypePath, WherePredicate,
Path, PathArguments, QSelf, ReturnType, Token, Type, TypeParamBound, TypePath, WherePredicate,
};
pub fn replace_receiver(input: &mut DeriveInput) {
+1
View File
@@ -23,6 +23,7 @@ pub const OTHER: Symbol = Symbol("other");
pub const REMOTE: Symbol = Symbol("remote");
pub const RENAME: Symbol = Symbol("rename");
pub const RENAME_ALL: Symbol = Symbol("rename_all");
pub const RENAME_ALL_FIELDS: Symbol = Symbol("rename_all_fields");
pub const REPR: Symbol = Symbol("repr");
pub const SERDE: Symbol = Symbol("serde");
pub const SERIALIZE: Symbol = Symbol("serialize");
+24 -8
View File
@@ -13,8 +13,7 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.170")]
#![allow(unknown_lints, bare_trait_objects)]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.178")]
// Ignored clippy lints
#![allow(
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
@@ -63,17 +62,22 @@
)]
#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
#[macro_use]
extern crate proc_macro2;
extern crate quote;
#[macro_use]
extern crate syn;
#[cfg(not(precompiled))]
extern crate proc_macro;
extern crate proc_macro2;
#[cfg(precompiled)]
extern crate proc_macro2 as proc_macro;
mod internals;
use proc_macro::TokenStream;
#[cfg(precompiled)]
use std::sync::atomic::AtomicBool;
#[cfg(not(precompiled))]
use syn::parse_macro_input;
use syn::DeriveInput;
#[macro_use]
@@ -86,9 +90,21 @@ mod dummy;
mod pretend;
mod ser;
mod this;
mod try;
#[proc_macro_derive(Serialize, attributes(serde))]
#[cfg(precompiled)]
macro_rules! parse_macro_input {
($tokenstream:ident as $ty:ty) => {
match syn::parse2::<$ty>($tokenstream) {
Ok(data) => data,
Err(err) => return err.to_compile_error(),
}
};
}
#[cfg(precompiled)]
pub static DESERIALIZE_IN_PLACE: AtomicBool = AtomicBool::new(false);
#[cfg_attr(not(precompiled), proc_macro_derive(Serialize, attributes(serde)))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
ser::expand_derive_serialize(&mut input)
@@ -96,7 +112,7 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream {
.into()
}
#[proc_macro_derive(Deserialize, attributes(serde))]
#[cfg_attr(not(precompiled), proc_macro_derive(Deserialize, attributes(serde)))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
de::expand_derive_deserialize(&mut input)
+2 -3
View File
@@ -1,7 +1,6 @@
use crate::internals::ast::{Container, Data, Field, Style, Variant};
use proc_macro2::TokenStream;
use quote::format_ident;
use internals::ast::{Container, Data, Field, Style, Variant};
use quote::{format_ident, quote};
// Suppress dead_code warnings that would otherwise appear when using a remote
// derive. Other than this pretend code, a struct annotated with remote derive
+55 -58
View File
@@ -1,14 +1,11 @@
use crate::fragment::{Fragment, Match, Stmts};
use crate::internals::ast::{Container, Data, Field, Style, Variant};
use crate::internals::{attr, replace_receiver, Ctxt, Derive};
use crate::{bound, dummy, pretend, this};
use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
use syn::{self, Ident, Index, Member};
use bound;
use dummy;
use fragment::{Fragment, Match, Stmts};
use internals::ast::{Container, Data, Field, Style, Variant};
use internals::{attr, replace_receiver, Ctxt, Derive};
use pretend;
use this;
use syn::{parse_quote, Ident, Index, Member};
pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
replace_receiver(input);
@@ -285,7 +282,7 @@ fn serialize_tuple_struct(
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len));
let #let_mut __serde_state = _serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len)?;
#(#serialize_stmts)*
_serde::ser::SerializeTupleStruct::end(__serde_state)
}
@@ -307,7 +304,7 @@ fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTra
let type_name = cattrs.name().serialize_name();
let func = struct_trait.serialize_field(Span::call_site());
quote! {
try!(#func(&mut __serde_state, #tag, #type_name));
#func(&mut __serde_state, #tag, #type_name)?;
}
}
_ => quote! {},
@@ -348,7 +345,7 @@ fn serialize_struct_as_struct(
);
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(__serializer, #type_name, #len));
let #let_mut __serde_state = _serde::Serializer::serialize_struct(__serializer, #type_name, #len)?;
#tag_field
#(#serialize_fields)*
_serde::ser::SerializeStruct::end(__serde_state)
@@ -392,7 +389,7 @@ fn serialize_struct_as_map(
};
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(__serializer, #len));
let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, #len)?;
#tag_field
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
@@ -596,10 +593,10 @@ fn serialize_internally_tagged_variant(
match effective_style(variant) {
Style::Unit => {
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));
let mut __struct = _serde::Serializer::serialize_struct(
__serializer, #type_name, 1)?;
_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name)?;
_serde::ser::SerializeStruct::end(__struct)
}
}
@@ -653,10 +650,10 @@ fn serialize_adjacently_tagged_variant(
match effective_style(variant) {
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));
let mut __struct = _serde::Serializer::serialize_struct(
__serializer, #type_name, 1)?;
_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name)?;
_serde::ser::SerializeStruct::end(__struct)
};
}
@@ -670,12 +667,12 @@ fn serialize_adjacently_tagged_variant(
let span = field.original.span();
let func = quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field);
return quote_block! {
let mut __struct = try!(_serde::Serializer::serialize_struct(
__serializer, #type_name, 2));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name));
try!(#func(
&mut __struct, #content, #field_expr));
let mut __struct = _serde::Serializer::serialize_struct(
__serializer, #type_name, 2)?;
_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name)?;
#func(
&mut __struct, #content, #field_expr)?;
_serde::ser::SerializeStruct::end(__struct)
};
}
@@ -735,15 +732,15 @@ fn serialize_adjacently_tagged_variant(
}
}
let mut __struct = try!(_serde::Serializer::serialize_struct(
__serializer, #type_name, 2));
try!(_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name));
try!(_serde::ser::SerializeStruct::serialize_field(
let mut __struct = _serde::Serializer::serialize_struct(
__serializer, #type_name, 2)?;
_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #tag, #variant_name)?;
_serde::ser::SerializeStruct::serialize_field(
&mut __struct, #content, &__AdjacentlyTagged {
data: (#(#fields_ident,)*),
phantom: _serde::__private::PhantomData::<#this_type #ty_generics>,
}));
})?;
_serde::ser::SerializeStruct::end(__struct)
}
}
@@ -833,21 +830,21 @@ fn serialize_tuple_variant(
variant_name,
} => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_variant(
let #let_mut __serde_state = _serde::Serializer::serialize_tuple_variant(
__serializer,
#type_name,
#variant_index,
#variant_name,
#len));
#len)?;
#(#serialize_stmts)*
_serde::ser::SerializeTupleVariant::end(__serde_state)
}
}
TupleVariant::Untagged => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple(
let #let_mut __serde_state = _serde::Serializer::serialize_tuple(
__serializer,
#len));
#len)?;
#(#serialize_stmts)*
_serde::ser::SerializeTuple::end(__serde_state)
}
@@ -910,40 +907,40 @@ fn serialize_struct_variant(
variant_name,
} => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct_variant(
let #let_mut __serde_state = _serde::Serializer::serialize_struct_variant(
__serializer,
#name,
#variant_index,
#variant_name,
#len,
));
)?;
#(#serialize_fields)*
_serde::ser::SerializeStructVariant::end(__serde_state)
}
}
StructVariant::InternallyTagged { tag, variant_name } => {
quote_block! {
let mut __serde_state = try!(_serde::Serializer::serialize_struct(
let mut __serde_state = _serde::Serializer::serialize_struct(
__serializer,
#name,
#len + 1,
));
try!(_serde::ser::SerializeStruct::serialize_field(
)?;
_serde::ser::SerializeStruct::serialize_field(
&mut __serde_state,
#tag,
#variant_name,
));
)?;
#(#serialize_fields)*
_serde::ser::SerializeStruct::end(__serde_state)
}
}
StructVariant::Untagged => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(
let #let_mut __serde_state = _serde::Serializer::serialize_struct(
__serializer,
#name,
#len,
));
)?;
#(#serialize_fields)*
_serde::ser::SerializeStruct::end(__serde_state)
}
@@ -993,9 +990,9 @@ fn serialize_struct_variant_with_flatten(
__S: _serde::Serializer,
{
let (#(#members,)*) = self.data;
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
let #let_mut __serde_state = _serde::Serializer::serialize_map(
__serializer,
_serde::__private::None));
_serde::__private::None)?;
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
}
@@ -1014,23 +1011,23 @@ fn serialize_struct_variant_with_flatten(
}
StructVariant::InternallyTagged { tag, variant_name } => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
let #let_mut __serde_state = _serde::Serializer::serialize_map(
__serializer,
_serde::__private::None));
try!(_serde::ser::SerializeMap::serialize_entry(
_serde::__private::None)?;
_serde::ser::SerializeMap::serialize_entry(
&mut __serde_state,
#tag,
#variant_name,
));
)?;
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
}
}
StructVariant::Untagged => {
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
let #let_mut __serde_state = _serde::Serializer::serialize_map(
__serializer,
_serde::__private::None));
_serde::__private::None)?;
#(#serialize_fields)*
_serde::ser::SerializeMap::end(__serde_state)
}
@@ -1075,7 +1072,7 @@ fn serialize_tuple_struct_visitor(
let span = field.original.span();
let func = tuple_trait.serialize_element(span);
let ser = quote! {
try!(#func(&mut __serde_state, #field_expr));
#func(&mut __serde_state, #field_expr)?;
};
match skip {
@@ -1119,12 +1116,12 @@ fn serialize_struct_visitor(
let ser = if field.attrs.flatten() {
let func = quote_spanned!(span=> _serde::Serialize::serialize);
quote! {
try!(#func(&#field_expr, _serde::__private::ser::FlatMapSerializer(&mut __serde_state)));
#func(&#field_expr, _serde::__private::ser::FlatMapSerializer(&mut __serde_state))?;
}
} else {
let func = struct_trait.serialize_field(span);
quote! {
try!(#func(&mut __serde_state, #key_expr, #field_expr));
#func(&mut __serde_state, #key_expr, #field_expr)?;
}
};
@@ -1136,7 +1133,7 @@ fn serialize_struct_visitor(
if !#skip {
#ser
} else {
try!(#skip_func(&mut __serde_state, #key_expr));
#skip_func(&mut __serde_state, #key_expr)?;
}
}
} else {
@@ -1236,7 +1233,7 @@ fn wrap_serialize_with(
// Serialization of an empty struct results in code like:
//
// let mut __serde_state = try!(serializer.serialize_struct("S", 0));
// let mut __serde_state = serializer.serialize_struct("S", 0)?;
// _serde::ser::SerializeStruct::end(__serde_state)
//
// where we want to omit the `mut` to avoid a warning.
+1 -1
View File
@@ -1,4 +1,4 @@
use internals::ast::Container;
use crate::internals::ast::Container;
use syn::{Path, PathArguments, Token};
pub fn this_type(cont: &Container) -> Path {
-24
View File
@@ -1,24 +0,0 @@
use proc_macro2::{Punct, Spacing, TokenStream};
// None of our generated code requires the `From::from` error conversion
// performed by the standard library's `try!` macro. With this simplified macro
// we see a significant improvement in type checking and borrow checking time of
// the generated code and a slight improvement in binary size.
pub fn replacement() -> TokenStream {
// Cannot pass `$expr` to `quote!` prior to Rust 1.17.0 so interpolate it.
let dollar = Punct::new('$', Spacing::Alone);
quote! {
#[allow(unused_macros)]
macro_rules! try {
(#dollar __expr:expr) => {
match #dollar __expr {
_serde::__private::Ok(__val) => __val,
_serde::__private::Err(__err) => {
return _serde::__private::Err(__err);
}
}
}
}
}
}
+2 -1
View File
@@ -4,8 +4,8 @@ version = "0.28.0" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
description = "AST representation used by Serde derive macros. Unstable."
documentation = "https://docs.rs/serde_derive_internals"
exclude = ["build.rs"]
homepage = "https://serde.rs"
include = ["lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT"]
keywords = ["serde", "serialization"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/serde-rs/serde"
@@ -21,3 +21,4 @@ syn = { version = "2.0.25", default-features = false, features = ["clone-impls",
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]
+2 -4
View File
@@ -1,5 +1,4 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.28.0")]
#![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints
#![allow(
clippy::cognitive_complexity,
@@ -30,6 +29,7 @@
clippy::missing_errors_doc,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::return_self_not_must_use,
clippy::similar_names,
clippy::single_match_else,
clippy::struct_excessive_bools,
@@ -38,11 +38,9 @@
clippy::wildcard_imports
)]
#[macro_use]
extern crate syn;
extern crate proc_macro2;
extern crate quote;
extern crate syn;
#[cfg_attr(serde_build_from_git, path = "../serde_derive/src/internals/mod.rs")]
#[cfg_attr(not(serde_build_from_git), path = "src/mod.rs")]
-28
View File
@@ -1,28 +0,0 @@
[package]
name = "serde_test"
version = "1.0.170" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["development-tools::testing"]
description = "Token De/Serializer for testing De/Serialize implementations"
documentation = "https://docs.rs/serde_test"
homepage = "https://serde.rs"
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
keywords = ["serde", "serialization", "testing", "dev-dependencies"]
license = "MIT OR Apache-2.0"
readme = "crates-io.md"
repository = "https://github.com/serde-rs/serde"
rust-version = "1.19"
[dependencies]
serde = { version = "1.0.60", path = "../serde" }
[dev-dependencies]
serde = { version = "1.0", path = "../serde", features = ["rc"] }
serde_derive = { version = "1.0", path = "../serde_derive" }
[lib]
doc-scrape-examples = false
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
-1
View File
@@ -1 +0,0 @@
../LICENSE-APACHE
-1
View File
@@ -1 +0,0 @@
../LICENSE-MIT
-1
View File
@@ -1 +0,0 @@
../README.md
-50
View File
@@ -1,50 +0,0 @@
use std::env;
use std::process::Command;
use std::str::{self, FromStr};
// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let minor = match rustc_minor_version() {
Some(minor) => minor,
None => return,
};
// #[track_caller] stabilized in Rust 1.46:
// https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html#track_caller
if minor < 46 {
println!("cargo:rustc-cfg=no_track_caller");
}
}
fn rustc_minor_version() -> Option<u32> {
let rustc = match env::var_os("RUSTC") {
Some(rustc) => rustc,
None => return None,
};
let output = match Command::new(rustc).arg("--version").output() {
Ok(output) => output,
Err(_) => return None,
};
let version = match str::from_utf8(&output.stdout) {
Ok(version) => version,
Err(_) => return None,
};
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return None;
}
let next = match pieces.next() {
Some(next) => next,
None => return None,
};
u32::from_str(next).ok()
}
-1
View File
@@ -1 +0,0 @@
../crates-io.md
-237
View File
@@ -1,237 +0,0 @@
use serde::{Deserialize, Serialize};
use de::Deserializer;
use ser::Serializer;
use token::Token;
use std::fmt::Debug;
/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
/// a: u8,
/// b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_tokens(
/// &s,
/// &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// ```
#[cfg_attr(not(no_track_caller), track_caller)]
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
T: Serialize + Deserialize<'de> + PartialEq + Debug,
{
assert_ser_tokens(value, tokens);
assert_de_tokens(value, tokens);
}
/// Asserts that `value` serializes to the given `tokens`.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_ser_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
/// a: u8,
/// b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_ser_tokens(
/// &s,
/// &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// ```
#[cfg_attr(not(no_track_caller), track_caller)]
pub fn assert_ser_tokens<T: ?Sized>(value: &T, tokens: &[Token])
where
T: Serialize,
{
let mut ser = Serializer::new(tokens);
match value.serialize(&mut ser) {
Ok(_) => {}
Err(err) => panic!("value failed to serialize: {}", err),
}
if ser.remaining() > 0 {
panic!("{} remaining tokens", ser.remaining());
}
}
/// Asserts that `value` serializes to the given `tokens`, and then yields
/// `error`.
///
/// ```edition2021
/// use serde_derive::Serialize;
/// use serde_test::{assert_ser_tokens_error, Token};
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// #[derive(Serialize)]
/// struct Example {
/// lock: Arc<Mutex<u32>>,
/// }
///
/// fn main() {
/// let example = Example {
/// lock: Arc::new(Mutex::new(0)),
/// };
/// let lock = example.lock.clone();
///
/// let thread = thread::spawn(move || {
/// // This thread will acquire the mutex first, unwrapping the result
/// // of `lock` because the lock has not been poisoned.
/// let _guard = lock.lock().unwrap();
///
/// // This panic while holding the lock (`_guard` is in scope) will
/// // poison the mutex.
/// panic!()
/// });
/// thread.join();
///
/// let expected = &[
/// Token::Struct {
/// name: "Example",
/// len: 1,
/// },
/// Token::Str("lock"),
/// ];
/// let error = "lock poison error while serializing";
/// assert_ser_tokens_error(&example, expected, error);
/// }
/// ```
#[cfg_attr(not(no_track_caller), track_caller)]
pub fn assert_ser_tokens_error<T: ?Sized>(value: &T, tokens: &[Token], error: &str)
where
T: Serialize,
{
let mut ser = Serializer::new(tokens);
match value.serialize(&mut ser) {
Ok(_) => panic!("value serialized successfully"),
Err(e) => assert_eq!(e, *error),
}
if ser.remaining() > 0 {
panic!("{} remaining tokens", ser.remaining());
}
}
/// Asserts that the given `tokens` deserialize into `value`.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_de_tokens, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
/// a: u8,
/// b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_de_tokens(
/// &s,
/// &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// ```
#[cfg_attr(not(no_track_caller), track_caller)]
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
T: Deserialize<'de> + PartialEq + Debug,
{
let mut de = Deserializer::new(tokens);
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());
}
}
/// Asserts that the given `tokens` yield `error` when deserializing.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_de_tokens_error, Token};
/// #
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// #[serde(deny_unknown_fields)]
/// struct S {
/// a: u8,
/// b: u8,
/// }
///
/// assert_de_tokens_error::<S>(
/// &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("x"),
/// ],
/// "unknown field `x`, expected `a` or `b`",
/// );
/// ```
#[cfg_attr(not(no_track_caller), track_caller)]
pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str)
where
T: Deserialize<'de>,
{
let mut de = Deserializer::new(tokens);
match T::deserialize(&mut de) {
Ok(_) => panic!("tokens deserialized successfully"),
Err(e) => assert_eq!(e, *error),
}
// There may be one token left if a peek caused the error
de.next_token_opt();
if de.remaining() > 0 {
panic!("{} remaining tokens", de.remaining());
}
}
-847
View File
@@ -1,847 +0,0 @@
use std::fmt;
use serde::ser::{
SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
SerializeTupleStruct, SerializeTupleVariant,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Readable<T: ?Sized>(T);
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Compact<T: ?Sized>(T);
/// Trait to determine whether a value is represented in human-readable or
/// compact form.
///
/// ```edition2021
/// use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// use serde_test::{assert_tokens, Configure, Token};
///
/// #[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,
/// {
/// if serializer.is_human_readable() {
/// format!("{}.{}", self.0, self.1).serialize(serializer)
/// } else {
/// (self.0, self.1).serialize(serializer)
/// }
/// }
/// }
///
/// impl<'de> Deserialize<'de> for Example {
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
/// where
/// D: Deserializer<'de>,
/// {
/// use serde::de::Error;
/// if deserializer.is_human_readable() {
/// let s = String::deserialize(deserializer)?;
/// let parts: Vec<_> = s.split('.').collect();
/// Ok(Example(
/// parts[0].parse().map_err(D::Error::custom)?,
/// parts[1].parse().map_err(D::Error::custom)?,
/// ))
/// } else {
/// let (x, y) = Deserialize::deserialize(deserializer)?;
/// Ok(Example(x, y))
/// }
/// }
/// }
///
/// fn main() {
/// assert_tokens(
/// &Example(1, 0).compact(),
/// &[
/// Token::Tuple { len: 2 },
/// Token::U8(1),
/// Token::U8(0),
/// Token::TupleEnd,
/// ],
/// );
/// assert_tokens(&Example(1, 0).readable(), &[Token::Str("1.0")]);
/// }
/// ```
pub trait Configure {
/// Marks `self` as using `is_human_readable == true`
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,
{
Compact(self)
}
}
impl<T: ?Sized> Configure for T {}
impl<T: ?Sized> Serialize for Readable<T>
where
T: Serialize,
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(Readable(serializer))
}
}
impl<T: ?Sized> Serialize for Compact<T>
where
T: Serialize,
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(Compact(serializer))
}
}
impl<'de, T> Deserialize<'de> for Readable<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize(Readable(deserializer)).map(Readable)
}
}
impl<'de, T> Deserialize<'de> for Compact<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize(Compact(deserializer)).map(Compact)
}
}
impl<'de, T> DeserializeSeed<'de> for Readable<T>
where
T: DeserializeSeed<'de>,
{
type Value = T::Value;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
self.0.deserialize(Readable(deserializer))
}
}
impl<'de, T> DeserializeSeed<'de> for Compact<T>
where
T: DeserializeSeed<'de>,
{
type Value = T::Value;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
self.0.deserialize(Compact(deserializer))
}
}
macro_rules! forward_method {
($name: ident (self $(, $arg: ident : $arg_type: ty)* ) -> $return_type: ty) => {
fn $name (self $(, $arg : $arg_type)* ) -> $return_type {
(self.0).$name( $($arg),* )
}
};
}
macro_rules! forward_serialize_methods {
( $( $name: ident $arg_type: ty ),* ) => {
$(
forward_method!($name(self, v : $arg_type) -> Result<Self::Ok, Self::Error>);
)*
};
}
macro_rules! impl_serializer {
($wrapper:ident, $is_human_readable:expr) => {
impl<S> Serializer for $wrapper<S>
where
S: Serializer,
{
type Ok = S::Ok;
type Error = S::Error;
type SerializeSeq = $wrapper<S::SerializeSeq>;
type SerializeTuple = $wrapper<S::SerializeTuple>;
type SerializeTupleStruct = $wrapper<S::SerializeTupleStruct>;
type SerializeTupleVariant = $wrapper<S::SerializeTupleVariant>;
type SerializeMap = $wrapper<S::SerializeMap>;
type SerializeStruct = $wrapper<S::SerializeStruct>;
type SerializeStructVariant = $wrapper<S::SerializeStructVariant>;
fn is_human_readable(&self) -> bool {
$is_human_readable
}
forward_serialize_methods! {
serialize_bool bool,
serialize_i8 i8,
serialize_i16 i16,
serialize_i32 i32,
serialize_i64 i64,
serialize_u8 u8,
serialize_u16 u16,
serialize_u32 u32,
serialize_u64 u64,
serialize_f32 f32,
serialize_f64 f64,
serialize_char char,
serialize_str &str,
serialize_bytes &[u8],
serialize_unit_struct &'static str
}
fn serialize_unit(self) -> Result<S::Ok, S::Error> {
self.0.serialize_unit()
}
fn serialize_unit_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
) -> Result<S::Ok, S::Error> {
self.0.serialize_unit_variant(name, variant_index, variant)
}
fn serialize_newtype_struct<T: ?Sized>(
self,
name: &'static str,
value: &T,
) -> Result<S::Ok, S::Error>
where
T: Serialize,
{
self.0.serialize_newtype_struct(name, &$wrapper(value))
}
fn serialize_newtype_variant<T: ?Sized>(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<S::Ok, S::Error>
where
T: Serialize,
{
self.0
.serialize_newtype_variant(name, variant_index, variant, &$wrapper(value))
}
fn serialize_none(self) -> Result<S::Ok, Self::Error> {
self.0.serialize_none()
}
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<S::Ok, Self::Error>
where
T: Serialize,
{
self.0.serialize_some(&$wrapper(value))
}
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
self.0.serialize_seq(len).map($wrapper)
}
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
self.0.serialize_tuple(len).map($wrapper)
}
fn serialize_tuple_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
self.0.serialize_tuple_struct(name, len).map($wrapper)
}
fn serialize_tuple_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
self.0
.serialize_tuple_variant(name, variant_index, variant, len)
.map($wrapper)
}
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
self.0.serialize_map(len).map($wrapper)
}
fn serialize_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
self.0.serialize_struct(name, len).map($wrapper)
}
fn serialize_struct_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
self.0
.serialize_struct_variant(name, variant_index, variant, len)
.map($wrapper)
}
}
impl<S> SerializeSeq for $wrapper<S>
where
S: SerializeSeq,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_element(&$wrapper(value))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeTuple for $wrapper<S>
where
S: SerializeTuple,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_element(&$wrapper(value))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeTupleStruct for $wrapper<S>
where
S: SerializeTupleStruct,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_field(&$wrapper(value))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeTupleVariant for $wrapper<S>
where
S: SerializeTupleVariant,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_field(&$wrapper(value))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeMap for $wrapper<S>
where
S: SerializeMap,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_key(&$wrapper(key))
}
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_value(&$wrapper(value))
}
fn serialize_entry<K: ?Sized, V: ?Sized>(
&mut self,
key: &K,
value: &V,
) -> Result<(), S::Error>
where
K: Serialize,
V: Serialize,
{
self.0.serialize_entry(key, &$wrapper(value))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeStruct for $wrapper<S>
where
S: SerializeStruct,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_field<T: ?Sized>(
&mut self,
name: &'static str,
field: &T,
) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_field(name, &$wrapper(field))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
impl<S> SerializeStructVariant for $wrapper<S>
where
S: SerializeStructVariant,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_field<T: ?Sized>(
&mut self,
name: &'static str,
field: &T,
) -> Result<(), S::Error>
where
T: Serialize,
{
self.0.serialize_field(name, &$wrapper(field))
}
fn end(self) -> Result<S::Ok, S::Error> {
self.0.end()
}
}
};
}
impl_serializer!(Readable, true);
impl_serializer!(Compact, false);
use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor};
macro_rules! forward_deserialize_methods {
( $wrapper : ident ( $( $name: ident ),* ) ) => {
$(
fn $name<V>(self, visitor: V) -> Result<V::Value, D::Error>
where
V: Visitor<'de>,
{
(self.0).$name($wrapper(visitor))
}
)*
};
}
macro_rules! impl_deserializer {
($wrapper:ident, $is_human_readable:expr) => {
impl<'de, D> Deserializer<'de> for $wrapper<D>
where
D: Deserializer<'de>,
{
type Error = D::Error;
forward_deserialize_methods! {
$wrapper (
deserialize_any,
deserialize_bool,
deserialize_u8,
deserialize_u16,
deserialize_u32,
deserialize_u64,
deserialize_i8,
deserialize_i16,
deserialize_i32,
deserialize_i64,
deserialize_f32,
deserialize_f64,
deserialize_char,
deserialize_str,
deserialize_string,
deserialize_bytes,
deserialize_byte_buf,
deserialize_option,
deserialize_unit,
deserialize_seq,
deserialize_map,
deserialize_identifier,
deserialize_ignored_any
)
}
fn deserialize_unit_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, D::Error>
where
V: Visitor<'de>,
{
self.0.deserialize_unit_struct(name, $wrapper(visitor))
}
fn deserialize_newtype_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, D::Error>
where
V: Visitor<'de>,
{
self.0.deserialize_newtype_struct(name, $wrapper(visitor))
}
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, D::Error>
where
V: Visitor<'de>,
{
self.0.deserialize_tuple(len, $wrapper(visitor))
}
fn deserialize_tuple_struct<V>(
self,
name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value, D::Error>
where
V: Visitor<'de>,
{
self.0
.deserialize_tuple_struct(name, len, $wrapper(visitor))
}
fn deserialize_struct<V>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, D::Error>
where
V: Visitor<'de>,
{
self.0.deserialize_struct(name, fields, $wrapper(visitor))
}
fn deserialize_enum<V>(
self,
name: &'static str,
variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, D::Error>
where
V: Visitor<'de>,
{
self.0.deserialize_enum(name, variants, $wrapper(visitor))
}
fn is_human_readable(&self) -> bool {
$is_human_readable
}
}
impl<'de, D> Visitor<'de> for $wrapper<D>
where
D: Visitor<'de>,
{
type Value = D::Value;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.0.expecting(formatter)
}
fn visit_bool<E>(self, v: bool) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_bool(v)
}
fn visit_i8<E>(self, v: i8) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_i8(v)
}
fn visit_i16<E>(self, v: i16) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_i16(v)
}
fn visit_i32<E>(self, v: i32) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_i32(v)
}
fn visit_i64<E>(self, v: i64) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_i64(v)
}
fn visit_u8<E>(self, v: u8) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_u8(v)
}
fn visit_u16<E>(self, v: u16) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_u16(v)
}
fn visit_u32<E>(self, v: u32) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_u32(v)
}
fn visit_u64<E>(self, v: u64) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_u64(v)
}
fn visit_f32<E>(self, v: f32) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_f32(v)
}
fn visit_f64<E>(self, v: f64) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_f64(v)
}
fn visit_char<E>(self, v: char) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_char(v)
}
fn visit_str<E>(self, v: &str) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_str(v)
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_borrowed_str(v)
}
fn visit_string<E>(self, v: String) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_string(v)
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_bytes(v)
}
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_borrowed_bytes(v)
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_byte_buf(v)
}
fn visit_none<E>(self) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_none()
}
fn visit_some<D2>(self, deserializer: D2) -> Result<Self::Value, D2::Error>
where
D2: Deserializer<'de>,
{
self.0.visit_some($wrapper(deserializer))
}
fn visit_unit<E>(self) -> Result<D::Value, E>
where
E: Error,
{
self.0.visit_unit()
}
fn visit_newtype_struct<D2>(self, deserializer: D2) -> Result<Self::Value, D2::Error>
where
D2: Deserializer<'de>,
{
self.0.visit_newtype_struct($wrapper(deserializer))
}
fn visit_seq<V>(self, seq: V) -> Result<D::Value, V::Error>
where
V: SeqAccess<'de>,
{
self.0.visit_seq($wrapper(seq))
}
fn visit_map<V>(self, map: V) -> Result<D::Value, V::Error>
where
V: MapAccess<'de>,
{
self.0.visit_map($wrapper(map))
}
fn visit_enum<V>(self, data: V) -> Result<D::Value, V::Error>
where
V: EnumAccess<'de>,
{
self.0.visit_enum($wrapper(data))
}
}
impl<'de, D> SeqAccess<'de> for $wrapper<D>
where
D: SeqAccess<'de>,
{
type Error = D::Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, D::Error>
where
T: DeserializeSeed<'de>,
{
self.0.next_element_seed($wrapper(seed))
}
fn size_hint(&self) -> Option<usize> {
self.0.size_hint()
}
}
impl<'de, D> MapAccess<'de> for $wrapper<D>
where
D: MapAccess<'de>,
{
type Error = D::Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, D::Error>
where
K: DeserializeSeed<'de>,
{
self.0.next_key_seed($wrapper(seed))
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, D::Error>
where
V: DeserializeSeed<'de>,
{
self.0.next_value_seed($wrapper(seed))
}
fn next_entry_seed<K, V>(
&mut self,
kseed: K,
vseed: V,
) -> Result<Option<(K::Value, V::Value)>, D::Error>
where
K: DeserializeSeed<'de>,
V: DeserializeSeed<'de>,
{
self.0.next_entry_seed($wrapper(kseed), $wrapper(vseed))
}
fn size_hint(&self) -> Option<usize> {
self.0.size_hint()
}
}
impl<'de, D> EnumAccess<'de> for $wrapper<D>
where
D: EnumAccess<'de>,
{
type Error = D::Error;
type Variant = $wrapper<D::Variant>;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
self.0
.variant_seed($wrapper(seed))
.map(|(value, variant)| (value, $wrapper(variant)))
}
}
impl<'de, D> VariantAccess<'de> for $wrapper<D>
where
D: VariantAccess<'de>,
{
type Error = D::Error;
fn unit_variant(self) -> Result<(), D::Error> {
self.0.unit_variant()
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, D::Error>
where
T: DeserializeSeed<'de>,
{
self.0.newtype_variant_seed($wrapper(seed))
}
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, D::Error>
where
V: Visitor<'de>,
{
self.0.tuple_variant(len, $wrapper(visitor))
}
fn struct_variant<V>(
self,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, D::Error>
where
V: Visitor<'de>,
{
self.0.struct_variant(fields, $wrapper(visitor))
}
}
};
}
impl_deserializer!(Readable, true);
impl_deserializer!(Compact, false);
-671
View File
@@ -1,671 +0,0 @@
use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
use serde::de::{
self, Deserialize, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,
VariantAccess, Visitor,
};
use error::Error;
use token::Token;
#[derive(Debug)]
pub struct Deserializer<'de> {
tokens: &'de [Token],
}
fn assert_next_token(de: &mut Deserializer, expected: Token) -> Result<(), Error> {
match de.next_token_opt() {
Some(token) if token == expected => Ok(()),
Some(other) => Err(de::Error::custom(format!(
"expected Token::{} but deserialization wants Token::{}",
other, expected,
))),
None => Err(de::Error::custom(format!(
"end of tokens but deserialization wants Token::{}",
expected,
))),
}
}
fn unexpected(token: Token) -> Error {
de::Error::custom(format!(
"deserialization did not expect this token: {}",
token,
))
}
fn end_of_tokens() -> Error {
de::Error::custom("ran out of tokens to deserialize")
}
impl<'de> Deserializer<'de> {
pub fn new(tokens: &'de [Token]) -> Self {
Deserializer { tokens: tokens }
}
fn peek_token_opt(&self) -> Option<Token> {
self.tokens.first().cloned()
}
fn peek_token(&self) -> Result<Token, Error> {
self.peek_token_opt().ok_or_else(end_of_tokens)
}
pub fn next_token_opt(&mut self) -> Option<Token> {
match self.tokens.split_first() {
Some((&first, rest)) => {
self.tokens = rest;
Some(first)
}
None => None,
}
}
fn next_token(&mut self) -> Result<Token, Error> {
let (&first, rest) = self.tokens.split_first().ok_or_else(end_of_tokens)?;
self.tokens = rest;
Ok(first)
}
pub fn remaining(&self) -> usize {
self.tokens.len()
}
fn visit_seq<V>(
&mut self,
len: Option<usize>,
end: Token,
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
let value = visitor.visit_seq(DeserializerSeqVisitor {
de: self,
len: len,
end: end,
})?;
assert_next_token(self, end)?;
Ok(value)
}
fn visit_map<V>(
&mut self,
len: Option<usize>,
end: Token,
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
let value = visitor.visit_map(DeserializerMapVisitor {
de: self,
len: len,
end: end,
})?;
assert_next_token(self, end)?;
Ok(value)
}
}
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
type Error = Error;
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf unit seq map identifier ignored_any
}
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
let token = self.next_token()?;
match token {
Token::Bool(v) => visitor.visit_bool(v),
Token::I8(v) => visitor.visit_i8(v),
Token::I16(v) => visitor.visit_i16(v),
Token::I32(v) => visitor.visit_i32(v),
Token::I64(v) => visitor.visit_i64(v),
Token::U8(v) => visitor.visit_u8(v),
Token::U16(v) => visitor.visit_u16(v),
Token::U32(v) => visitor.visit_u32(v),
Token::U64(v) => visitor.visit_u64(v),
Token::F32(v) => visitor.visit_f32(v),
Token::F64(v) => visitor.visit_f64(v),
Token::Char(v) => visitor.visit_char(v),
Token::Str(v) => visitor.visit_str(v),
Token::BorrowedStr(v) => visitor.visit_borrowed_str(v),
Token::String(v) => visitor.visit_string(v.to_owned()),
Token::Bytes(v) => visitor.visit_bytes(v),
Token::BorrowedBytes(v) => visitor.visit_borrowed_bytes(v),
Token::ByteBuf(v) => visitor.visit_byte_buf(v.to_vec()),
Token::None => visitor.visit_none(),
Token::Some => visitor.visit_some(self),
Token::Unit | Token::UnitStruct { .. } => visitor.visit_unit(),
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::Map { len } => self.visit_map(len, Token::MapEnd, visitor),
Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor),
Token::Enum { .. } => {
let variant = self.next_token()?;
let next = self.peek_token()?;
match (variant, next) {
(Token::Str(variant), Token::Unit) => {
self.next_token()?;
visitor.visit_str(variant)
}
(Token::BorrowedStr(variant), Token::Unit) => {
self.next_token()?;
visitor.visit_borrowed_str(variant)
}
(Token::String(variant), Token::Unit) => {
self.next_token()?;
visitor.visit_string(variant.to_string())
}
(Token::Bytes(variant), Token::Unit) => {
self.next_token()?;
visitor.visit_bytes(variant)
}
(Token::BorrowedBytes(variant), Token::Unit) => {
self.next_token()?;
visitor.visit_borrowed_bytes(variant)
}
(Token::ByteBuf(variant), Token::Unit) => {
self.next_token()?;
visitor.visit_byte_buf(variant.to_vec())
}
(Token::U8(variant), Token::Unit) => {
self.next_token()?;
visitor.visit_u8(variant)
}
(Token::U16(variant), Token::Unit) => {
self.next_token()?;
visitor.visit_u16(variant)
}
(Token::U32(variant), Token::Unit) => {
self.next_token()?;
visitor.visit_u32(variant)
}
(Token::U64(variant), Token::Unit) => {
self.next_token()?;
visitor.visit_u64(variant)
}
(variant, Token::Unit) => Err(unexpected(variant)),
(variant, _) => {
visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any))
}
}
}
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 => Err(unexpected(token)),
}
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
match self.peek_token()? {
Token::Unit | Token::None => {
self.next_token()?;
visitor.visit_none()
}
Token::Some => {
self.next_token()?;
visitor.visit_some(self)
}
_ => self.deserialize_any(visitor),
}
}
fn deserialize_enum<V>(
self,
name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
match self.peek_token()? {
Token::Enum { name: n } if name == n => {
self.next_token()?;
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 =>
{
visitor.visit_enum(DeserializerEnumVisitor { de: self })
}
_ => self.deserialize_any(visitor),
}
}
fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
match self.peek_token()? {
Token::UnitStruct { .. } => {
assert_next_token(self, Token::UnitStruct { name: name })?;
visitor.visit_unit()
}
_ => self.deserialize_any(visitor),
}
}
fn deserialize_newtype_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
match self.peek_token()? {
Token::NewtypeStruct { .. } => {
assert_next_token(self, Token::NewtypeStruct { name: name })?;
visitor.visit_newtype_struct(self)
}
_ => self.deserialize_any(visitor),
}
}
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
match self.peek_token()? {
Token::Unit | Token::UnitStruct { .. } => {
self.next_token()?;
visitor.visit_unit()
}
Token::Seq { .. } => {
self.next_token()?;
self.visit_seq(Some(len), Token::SeqEnd, visitor)
}
Token::Tuple { .. } => {
self.next_token()?;
self.visit_seq(Some(len), Token::TupleEnd, visitor)
}
Token::TupleStruct { .. } => {
self.next_token()?;
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
}
_ => self.deserialize_any(visitor),
}
}
fn deserialize_tuple_struct<V>(
self,
name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
match self.peek_token()? {
Token::Unit => {
self.next_token()?;
visitor.visit_unit()
}
Token::UnitStruct { .. } => {
assert_next_token(self, Token::UnitStruct { name: name })?;
visitor.visit_unit()
}
Token::Seq { .. } => {
self.next_token()?;
self.visit_seq(Some(len), Token::SeqEnd, visitor)
}
Token::Tuple { .. } => {
self.next_token()?;
self.visit_seq(Some(len), Token::TupleEnd, visitor)
}
Token::TupleStruct { len: n, .. } => {
assert_next_token(self, Token::TupleStruct { name: name, len: n })?;
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
}
_ => self.deserialize_any(visitor),
}
}
fn deserialize_struct<V>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
match self.peek_token()? {
Token::Struct { len: n, .. } => {
assert_next_token(self, Token::Struct { name: name, len: n })?;
self.visit_map(Some(fields.len()), Token::StructEnd, visitor)
}
Token::Map { .. } => {
self.next_token()?;
self.visit_map(Some(fields.len()), Token::MapEnd, visitor)
}
_ => self.deserialize_any(visitor),
}
}
fn is_human_readable(&self) -> bool {
panic!(
"Types which have different human-readable and compact representations \
must explicitly mark their test cases with `serde_test::Configure`"
);
}
}
//////////////////////////////////////////////////////////////////////////
struct DeserializerSeqVisitor<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>,
len: Option<usize>,
end: Token,
}
impl<'de, 'a> SeqAccess<'de> for DeserializerSeqVisitor<'a, 'de> {
type Error = Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Error>
where
T: DeserializeSeed<'de>,
{
if self.de.peek_token_opt() == Some(self.end) {
return Ok(None);
}
self.len = self.len.map(|len| len.saturating_sub(1));
seed.deserialize(&mut *self.de).map(Some)
}
fn size_hint(&self) -> Option<usize> {
self.len
}
}
//////////////////////////////////////////////////////////////////////////
struct DeserializerMapVisitor<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>,
len: Option<usize>,
end: Token,
}
impl<'de, 'a> MapAccess<'de> for DeserializerMapVisitor<'a, 'de> {
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
where
K: DeserializeSeed<'de>,
{
if self.de.peek_token_opt() == Some(self.end) {
return Ok(None);
}
self.len = self.len.map(|len| len.saturating_sub(1));
seed.deserialize(&mut *self.de).map(Some)
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
where
V: DeserializeSeed<'de>,
{
seed.deserialize(&mut *self.de)
}
fn size_hint(&self) -> Option<usize> {
self.len
}
}
//////////////////////////////////////////////////////////////////////////
struct DeserializerEnumVisitor<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>,
}
impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
type Error = Error;
type Variant = Self;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self), Error>
where
V: DeserializeSeed<'de>,
{
match self.de.peek_token()? {
Token::UnitVariant { variant: v, .. }
| Token::NewtypeVariant { variant: v, .. }
| Token::TupleVariant { variant: v, .. }
| Token::StructVariant { variant: v, .. } => {
let de = v.into_deserializer();
let value = seed.deserialize(de)?;
Ok((value, self))
}
_ => {
let value = seed.deserialize(&mut *self.de)?;
Ok((value, self))
}
}
}
}
impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
type Error = Error;
fn unit_variant(self) -> Result<(), Error> {
match self.de.peek_token()? {
Token::UnitVariant { .. } => {
self.de.next_token()?;
Ok(())
}
_ => Deserialize::deserialize(self.de),
}
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.de.peek_token()? {
Token::NewtypeVariant { .. } => {
self.de.next_token()?;
seed.deserialize(self.de)
}
_ => seed.deserialize(self.de),
}
}
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
match self.de.peek_token()? {
Token::TupleVariant { len: enum_len, .. } => {
let token = self.de.next_token()?;
if len == enum_len {
self.de
.visit_seq(Some(len), Token::TupleVariantEnd, visitor)
} else {
Err(unexpected(token))
}
}
Token::Seq {
len: Some(enum_len),
} => {
let token = self.de.next_token()?;
if len == enum_len {
self.de.visit_seq(Some(len), Token::SeqEnd, visitor)
} else {
Err(unexpected(token))
}
}
_ => de::Deserializer::deserialize_any(self.de, visitor),
}
}
fn struct_variant<V>(
self,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
match self.de.peek_token()? {
Token::StructVariant { len: enum_len, .. } => {
let token = self.de.next_token()?;
if fields.len() == enum_len {
self.de
.visit_map(Some(fields.len()), Token::StructVariantEnd, visitor)
} else {
Err(unexpected(token))
}
}
Token::Map {
len: Some(enum_len),
} => {
let token = self.de.next_token()?;
if fields.len() == enum_len {
self.de
.visit_map(Some(fields.len()), Token::MapEnd, visitor)
} else {
Err(unexpected(token))
}
}
_ => de::Deserializer::deserialize_any(self.de, visitor),
}
}
}
//////////////////////////////////////////////////////////////////////////
struct EnumMapVisitor<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>,
variant: Option<Token>,
format: EnumFormat,
}
enum EnumFormat {
Seq,
Map,
Any,
}
impl<'a, 'de> EnumMapVisitor<'a, 'de> {
fn new(de: &'a mut Deserializer<'de>, variant: Token, format: EnumFormat) -> Self {
EnumMapVisitor {
de: de,
variant: Some(variant),
format: format,
}
}
}
impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
where
K: DeserializeSeed<'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::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
Some(other) => Err(unexpected(other)),
None => Ok(None),
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
where
V: DeserializeSeed<'de>,
{
match self.format {
EnumFormat::Seq => {
let value = {
let visitor = DeserializerSeqVisitor {
de: self.de,
len: None,
end: Token::TupleVariantEnd,
};
seed.deserialize(SeqAccessDeserializer::new(visitor))?
};
assert_next_token(self.de, Token::TupleVariantEnd)?;
Ok(value)
}
EnumFormat::Map => {
let value = {
let visitor = DeserializerMapVisitor {
de: self.de,
len: None,
end: Token::StructVariantEnd,
};
seed.deserialize(MapAccessDeserializer::new(visitor))?
};
assert_next_token(self.de, Token::StructVariantEnd)?;
Ok(value)
}
EnumFormat::Any => seed.deserialize(&mut *self.de),
}
}
}
struct BytesDeserializer {
value: &'static [u8],
}
impl<'de> de::Deserializer<'de> for BytesDeserializer {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_bytes(self.value)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
-43
View File
@@ -1,43 +0,0 @@
use std::error;
use std::fmt::{self, Display};
use serde::{de, ser};
#[derive(Clone, Debug)]
pub struct Error {
msg: String,
}
impl ser::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
Error {
msg: msg.to_string(),
}
}
}
impl de::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
Error {
msg: msg.to_string(),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(&self.msg)
}
}
impl error::Error for Error {
fn description(&self) -> &str {
&self.msg
}
}
impl PartialEq<str> for Error {
fn eq(&self, other: &str) -> bool {
self.msg == other
}
}
-188
View File
@@ -1,188 +0,0 @@
//! This crate provides a convenient concise way to write unit tests for
//! implementations of [`Serialize`] and [`Deserialize`].
//!
//! [`Serialize`]: serde::ser::Serialize
//! [`Deserialize`]: serde::de::Deserialize
//!
//! The `Serialize` impl for a value can be characterized by the sequence of
//! [`Serializer`] calls that are made in the course of serializing the value,
//! so `serde_test` provides a [`Token`] abstraction which corresponds roughly
//! to `Serializer` method calls. There is an [`assert_ser_tokens`] function to
//! test that a value serializes to a particular sequence of method calls, an
//! [`assert_de_tokens`] function to test that a value can be deserialized from
//! a particular sequence of method calls, and an [`assert_tokens`] function to
//! test both directions. There are also functions to test expected failure
//! conditions.
//!
//! [`Serializer`]: serde::ser::Serializer
//!
//! Here is an example from the [`linked-hash-map`] crate.
//!
//! [`linked-hash-map`]: https://github.com/contain-rs/linked-hash-map
//!
//! ```edition2021
//! # const IGNORE: &str = stringify! {
//! use linked_hash_map::LinkedHashMap;
//! # };
//! use serde_test::{assert_tokens, Token};
//!
//! # use std::fmt;
//! # use std::marker::PhantomData;
//! #
//! # use serde::ser::{Serialize, Serializer, SerializeMap};
//! # use serde::de::{Deserialize, Deserializer, Visitor, MapAccess};
//! #
//! # // Dumb imitation of LinkedHashMap.
//! # #[derive(PartialEq, Debug)]
//! # struct LinkedHashMap<K, V>(Vec<(K, V)>);
//! #
//! # impl<K, V> LinkedHashMap<K, V> {
//! # fn new() -> Self {
//! # LinkedHashMap(Vec::new())
//! # }
//! #
//! # fn insert(&mut self, k: K, v: V) {
//! # self.0.push((k, v));
//! # }
//! # }
//! #
//! # impl<K, V> Serialize for LinkedHashMap<K, V>
//! # where
//! # K: Serialize,
//! # V: Serialize,
//! # {
//! # fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
//! # where
//! # S: Serializer,
//! # {
//! # let mut map = serializer.serialize_map(Some(self.0.len()))?;
//! # for &(ref k, ref v) in &self.0 {
//! # map.serialize_entry(k, v)?;
//! # }
//! # map.end()
//! # }
//! # }
//! #
//! # struct LinkedHashMapVisitor<K, V>(PhantomData<(K, V)>);
//! #
//! # impl<'de, K, V> Visitor<'de> for LinkedHashMapVisitor<K, V>
//! # where
//! # K: Deserialize<'de>,
//! # V: Deserialize<'de>,
//! # {
//! # type Value = LinkedHashMap<K, V>;
//! #
//! # fn expecting(&self, _: &mut fmt::Formatter) -> fmt::Result {
//! # unimplemented!()
//! # }
//! #
//! # fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
//! # where
//! # M: MapAccess<'de>,
//! # {
//! # let mut map = LinkedHashMap::new();
//! # while let Some((key, value)) = access.next_entry()? {
//! # map.insert(key, value);
//! # }
//! # Ok(map)
//! # }
//! # }
//! #
//! # impl<'de, K, V> Deserialize<'de> for LinkedHashMap<K, V>
//! # where
//! # K: Deserialize<'de>,
//! # V: Deserialize<'de>,
//! # {
//! # fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
//! # where
//! # D: Deserializer<'de>,
//! # {
//! # deserializer.deserialize_map(LinkedHashMapVisitor(PhantomData))
//! # }
//! # }
//! #
//! #[test]
//! # fn not_a_test_ser_de_empty() {}
//! fn test_ser_de_empty() {
//! let map = LinkedHashMap::<char, u32>::new();
//!
//! assert_tokens(
//! &map,
//! &[
//! Token::Map { len: Some(0) },
//! Token::MapEnd,
//! ],
//! );
//! }
//!
//! #[test]
//! # fn not_a_test_ser_de() {}
//! fn test_ser_de() {
//! let mut map = LinkedHashMap::new();
//! map.insert('b', 20);
//! map.insert('a', 10);
//! map.insert('c', 30);
//!
//! assert_tokens(
//! &map,
//! &[
//! Token::Map { len: Some(3) },
//! Token::Char('b'),
//! Token::I32(20),
//! Token::Char('a'),
//! Token::I32(10),
//! Token::Char('c'),
//! Token::I32(30),
//! Token::MapEnd,
//! ],
//! );
//! }
//! #
//! # fn main() {
//! # test_ser_de_empty();
//! # test_ser_de();
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.170")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
// Ignored clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))]
// Ignored clippy_pedantic lints
#![cfg_attr(
feature = "cargo-clippy",
allow(
cloned_instead_of_copied,
doc_link_with_quotes, // https://github.com/rust-lang/rust-clippy/issues/8961
empty_line_after_outer_attr,
manual_assert,
missing_docs_in_private_items,
missing_panics_doc,
module_name_repetitions,
must_use_candidate,
redundant_field_names,
too_many_lines,
type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772
use_debug,
use_self
)
)]
#[macro_use]
extern crate serde;
mod de;
mod error;
mod ser;
mod assert;
mod configure;
mod token;
pub use assert::{
assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_ser_tokens_error,
assert_tokens,
};
pub use token::Token;
pub use configure::{Compact, Configure, Readable};
-462
View File
@@ -1,462 +0,0 @@
use serde::{ser, Serialize};
use error::Error;
use token::Token;
/// A `Serializer` that ensures that a value serializes to a given list of
/// tokens.
#[derive(Debug)]
pub struct Serializer<'a> {
tokens: &'a [Token],
}
impl<'a> Serializer<'a> {
/// Creates the serializer.
pub fn new(tokens: &'a [Token]) -> Self {
Serializer { tokens: tokens }
}
/// Pulls the next token off of the serializer, ignoring it.
fn next_token(&mut self) -> Option<Token> {
if let Some((&first, rest)) = self.tokens.split_first() {
self.tokens = rest;
Some(first)
} else {
None
}
}
pub fn remaining(&self) -> usize {
self.tokens.len()
}
}
macro_rules! assert_next_token {
($ser:expr, $actual:ident) => {{
assert_next_token!($ser, stringify!($actual), Token::$actual, true);
}};
($ser:expr, $actual:ident($v:expr)) => {{
assert_next_token!(
$ser,
format_args!(concat!(stringify!($actual), "({:?})"), $v),
Token::$actual(v),
v == $v
);
}};
($ser:expr, $actual:ident { $($k:ident),* }) => {{
let compare = ($($k,)*);
let field_format = || {
use std::fmt::Write;
let mut buffer = String::new();
$(
write!(&mut buffer, concat!(stringify!($k), ": {:?}, "), $k).unwrap();
)*
buffer
};
assert_next_token!(
$ser,
format_args!(concat!(stringify!($actual), " {{ {}}}"), field_format()),
Token::$actual { $($k),* },
($($k,)*) == compare
);
}};
($ser:expr, $actual:expr, $pat:pat, $guard:expr) => {
match $ser.next_token() {
Some($pat) if $guard => {}
Some(expected) => return Err(ser::Error::custom(
format!("expected Token::{} but serialized as {}", expected, $actual)
)),
None => return Err(ser::Error::custom(
format!("expected end of tokens, but {} was serialized", $actual)
)),
}
};
}
impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> {
type Ok = ();
type Error = Error;
type SerializeSeq = Self;
type SerializeTuple = Self;
type SerializeTupleStruct = Self;
type SerializeTupleVariant = Variant<'s, 'a>;
type SerializeMap = Self;
type SerializeStruct = Self;
type SerializeStructVariant = Variant<'s, 'a>;
fn serialize_bool(self, v: bool) -> Result<(), Error> {
assert_next_token!(self, Bool(v));
Ok(())
}
fn serialize_i8(self, v: i8) -> Result<(), Error> {
assert_next_token!(self, I8(v));
Ok(())
}
fn serialize_i16(self, v: i16) -> Result<(), Error> {
assert_next_token!(self, I16(v));
Ok(())
}
fn serialize_i32(self, v: i32) -> Result<(), Error> {
assert_next_token!(self, I32(v));
Ok(())
}
fn serialize_i64(self, v: i64) -> Result<(), Error> {
assert_next_token!(self, I64(v));
Ok(())
}
fn serialize_u8(self, v: u8) -> Result<(), Error> {
assert_next_token!(self, U8(v));
Ok(())
}
fn serialize_u16(self, v: u16) -> Result<(), Error> {
assert_next_token!(self, U16(v));
Ok(())
}
fn serialize_u32(self, v: u32) -> Result<(), Error> {
assert_next_token!(self, U32(v));
Ok(())
}
fn serialize_u64(self, v: u64) -> Result<(), Error> {
assert_next_token!(self, U64(v));
Ok(())
}
fn serialize_f32(self, v: f32) -> Result<(), Error> {
assert_next_token!(self, F32(v));
Ok(())
}
fn serialize_f64(self, v: f64) -> Result<(), Error> {
assert_next_token!(self, F64(v));
Ok(())
}
fn serialize_char(self, v: char) -> Result<(), Error> {
assert_next_token!(self, Char(v));
Ok(())
}
fn serialize_str(self, v: &str) -> Result<(), Error> {
match self.tokens.first() {
Some(&Token::BorrowedStr(_)) => assert_next_token!(self, BorrowedStr(v)),
Some(&Token::String(_)) => assert_next_token!(self, String(v)),
_ => assert_next_token!(self, Str(v)),
}
Ok(())
}
fn serialize_bytes(self, v: &[u8]) -> Result<(), Self::Error> {
match self.tokens.first() {
Some(&Token::BorrowedBytes(_)) => assert_next_token!(self, BorrowedBytes(v)),
Some(&Token::ByteBuf(_)) => assert_next_token!(self, ByteBuf(v)),
_ => assert_next_token!(self, Bytes(v)),
}
Ok(())
}
fn serialize_unit(self) -> Result<(), Error> {
assert_next_token!(self, Unit);
Ok(())
}
fn serialize_unit_struct(self, name: &'static str) -> Result<(), Error> {
assert_next_token!(self, UnitStruct { name });
Ok(())
}
fn serialize_unit_variant(
self,
name: &'static str,
_variant_index: u32,
variant: &'static str,
) -> Result<(), Error> {
if self.tokens.first() == Some(&Token::Enum { name: name }) {
self.next_token();
assert_next_token!(self, Str(variant));
assert_next_token!(self, Unit);
} else {
assert_next_token!(self, UnitVariant { name, variant });
}
Ok(())
}
fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<(), Error>
where
T: Serialize,
{
assert_next_token!(self, NewtypeStruct { name });
value.serialize(self)
}
fn serialize_newtype_variant<T: ?Sized>(
self,
name: &'static str,
_variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<(), Error>
where
T: Serialize,
{
if self.tokens.first() == Some(&Token::Enum { name: name }) {
self.next_token();
assert_next_token!(self, Str(variant));
} else {
assert_next_token!(self, NewtypeVariant { name, variant });
}
value.serialize(self)
}
fn serialize_none(self) -> Result<(), Error> {
assert_next_token!(self, None);
Ok(())
}
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<(), Error>
where
T: Serialize,
{
assert_next_token!(self, Some);
value.serialize(self)
}
fn serialize_seq(self, len: Option<usize>) -> Result<Self, Error> {
assert_next_token!(self, Seq { len });
Ok(self)
}
fn serialize_tuple(self, len: usize) -> Result<Self, Error> {
assert_next_token!(self, Tuple { len });
Ok(self)
}
fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result<Self, Error> {
assert_next_token!(self, TupleStruct { name, len });
Ok(self)
}
fn serialize_tuple_variant(
self,
name: &'static str,
_variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeTupleVariant, Error> {
if self.tokens.first() == Some(&Token::Enum { name: name }) {
self.next_token();
assert_next_token!(self, Str(variant));
let len = Some(len);
assert_next_token!(self, Seq { len });
Ok(Variant {
ser: self,
end: Token::SeqEnd,
})
} else {
assert_next_token!(self, TupleVariant { name, variant, len });
Ok(Variant {
ser: self,
end: Token::TupleVariantEnd,
})
}
}
fn serialize_map(self, len: Option<usize>) -> Result<Self, Error> {
assert_next_token!(self, Map { len });
Ok(self)
}
fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self, Error> {
assert_next_token!(self, Struct { name, len });
Ok(self)
}
fn serialize_struct_variant(
self,
name: &'static str,
_variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, Error> {
if self.tokens.first() == Some(&Token::Enum { name: name }) {
self.next_token();
assert_next_token!(self, Str(variant));
let len = Some(len);
assert_next_token!(self, Map { len });
Ok(Variant {
ser: self,
end: Token::MapEnd,
})
} else {
assert_next_token!(self, StructVariant { name, variant, len });
Ok(Variant {
ser: self,
end: Token::StructVariantEnd,
})
}
}
fn is_human_readable(&self) -> bool {
panic!(
"Types which have different human-readable and compact representations \
must explicitly mark their test cases with `serde_test::Configure`"
);
}
}
pub struct Variant<'s, 'a: 's> {
ser: &'s mut Serializer<'a>,
end: Token,
}
impl<'s, 'a> ser::SerializeSeq for &'s mut Serializer<'a> {
type Ok = ();
type Error = Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
where
T: Serialize,
{
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
assert_next_token!(self, SeqEnd);
Ok(())
}
}
impl<'s, 'a> ser::SerializeTuple for &'s mut Serializer<'a> {
type Ok = ();
type Error = Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
where
T: Serialize,
{
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
assert_next_token!(self, TupleEnd);
Ok(())
}
}
impl<'s, 'a> ser::SerializeTupleStruct for &'s mut Serializer<'a> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
where
T: Serialize,
{
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Error> {
assert_next_token!(self, TupleStructEnd);
Ok(())
}
}
impl<'s, 'a> ser::SerializeTupleVariant for Variant<'s, 'a> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
where
T: Serialize,
{
value.serialize(&mut *self.ser)
}
fn end(self) -> Result<(), Error> {
match self.end {
Token::TupleVariantEnd => assert_next_token!(self.ser, TupleVariantEnd),
Token::SeqEnd => assert_next_token!(self.ser, SeqEnd),
_ => unreachable!(),
}
Ok(())
}
}
impl<'s, 'a> ser::SerializeMap for &'s mut Serializer<'a> {
type Ok = ();
type Error = Error;
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
where
T: Serialize,
{
key.serialize(&mut **self)
}
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: Serialize,
{
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Self::Error> {
assert_next_token!(self, MapEnd);
Ok(())
}
}
impl<'s, 'a> ser::SerializeStruct for &'s mut Serializer<'a> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Self::Error>
where
T: Serialize,
{
key.serialize(&mut **self)?;
value.serialize(&mut **self)
}
fn end(self) -> Result<(), Self::Error> {
assert_next_token!(self, StructEnd);
Ok(())
}
}
impl<'s, 'a> ser::SerializeStructVariant for Variant<'s, 'a> {
type Ok = ();
type Error = Error;
fn serialize_field<T: ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Self::Error>
where
T: Serialize,
{
key.serialize(&mut *self.ser)?;
value.serialize(&mut *self.ser)
}
fn end(self) -> Result<(), Self::Error> {
match self.end {
Token::StructVariantEnd => assert_next_token!(self.ser, StructVariantEnd),
Token::MapEnd => assert_next_token!(self.ser, MapEnd),
_ => unreachable!(),
}
Ok(())
}
}
-561
View File
@@ -1,561 +0,0 @@
use std::fmt::{self, Debug, Display};
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Token {
/// A serialized `bool`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&true, &[Token::Bool(true)]);
/// ```
Bool(bool),
/// A serialized `i8`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0i8, &[Token::I8(0)]);
/// ```
I8(i8),
/// A serialized `i16`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0i16, &[Token::I16(0)]);
/// ```
I16(i16),
/// A serialized `i32`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0i32, &[Token::I32(0)]);
/// ```
I32(i32),
/// A serialized `i64`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0i64, &[Token::I64(0)]);
/// ```
I64(i64),
/// A serialized `u8`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0u8, &[Token::U8(0)]);
/// ```
U8(u8),
/// A serialized `u16`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0u16, &[Token::U16(0)]);
/// ```
U16(u16),
/// A serialized `u32`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0u32, &[Token::U32(0)]);
/// ```
U32(u32),
/// A serialized `u64`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0u64, &[Token::U64(0)]);
/// ```
U64(u64),
/// A serialized `f32`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0f32, &[Token::F32(0.0)]);
/// ```
F32(f32),
/// A serialized `f64`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&0f64, &[Token::F64(0.0)]);
/// ```
F64(f64),
/// A serialized `char`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&'\n', &[Token::Char('\n')]);
/// ```
Char(char),
/// A serialized `str`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let s = String::from("transient");
/// assert_tokens(&s, &[Token::Str("transient")]);
/// ```
Str(&'static str),
/// A borrowed `str`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let s: &str = "borrowed";
/// assert_tokens(&s, &[Token::BorrowedStr("borrowed")]);
/// ```
BorrowedStr(&'static str),
/// A serialized `String`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let s = String::from("owned");
/// assert_tokens(&s, &[Token::String("owned")]);
/// ```
String(&'static str),
/// A serialized `[u8]`
Bytes(&'static [u8]),
/// A borrowed `[u8]`.
BorrowedBytes(&'static [u8]),
/// A serialized `ByteBuf`
ByteBuf(&'static [u8]),
/// A serialized `Option<T>` containing none.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let opt = None::<char>;
/// assert_tokens(&opt, &[Token::None]);
/// ```
None,
/// The header to a serialized `Option<T>` containing some value.
///
/// The tokens of the value follow after this header.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let opt = Some('c');
/// assert_tokens(&opt, &[Token::Some, Token::Char('c')]);
/// ```
Some,
/// A serialized `()`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// assert_tokens(&(), &[Token::Unit]);
/// ```
Unit,
/// A serialized unit struct of the given name.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct X;
///
/// assert_tokens(&X, &[Token::UnitStruct { name: "X" }]);
/// # }
/// ```
UnitStruct { name: &'static str },
/// A unit variant of an enum.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// enum E {
/// A,
/// }
///
/// let a = E::A;
/// assert_tokens(
/// &a,
/// &[Token::UnitVariant {
/// name: "E",
/// variant: "A",
/// }],
/// );
/// # }
/// ```
UnitVariant {
name: &'static str,
variant: &'static str,
},
/// The header to a serialized newtype struct of the given name.
///
/// After this header is the value contained in the newtype struct.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct N(String);
///
/// let n = N("newtype".to_owned());
/// assert_tokens(
/// &n,
/// &[Token::NewtypeStruct { name: "N" }, Token::String("newtype")],
/// );
/// # }
/// ```
NewtypeStruct { name: &'static str },
/// The header to a newtype variant of an enum.
///
/// After this header is the value contained in the newtype variant.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// enum E {
/// B(u8),
/// }
///
/// let b = E::B(0);
/// assert_tokens(
/// &b,
/// &[
/// Token::NewtypeVariant {
/// name: "E",
/// variant: "B",
/// },
/// Token::U8(0),
/// ],
/// );
/// # }
/// ```
NewtypeVariant {
name: &'static str,
variant: &'static str,
},
/// The header to a sequence.
///
/// After this header are the elements of the sequence, followed by
/// `SeqEnd`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let vec = vec!['a', 'b', 'c'];
/// assert_tokens(
/// &vec,
/// &[
/// Token::Seq { len: Some(3) },
/// Token::Char('a'),
/// Token::Char('b'),
/// Token::Char('c'),
/// Token::SeqEnd,
/// ],
/// );
/// ```
Seq { len: Option<usize> },
/// An indicator of the end of a sequence.
SeqEnd,
/// The header to a tuple.
///
/// After this header are the elements of the tuple, followed by `TupleEnd`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// let tuple = ('a', 100);
/// assert_tokens(
/// &tuple,
/// &[
/// Token::Tuple { len: 2 },
/// Token::Char('a'),
/// Token::I32(100),
/// Token::TupleEnd,
/// ],
/// );
/// ```
Tuple { len: usize },
/// An indicator of the end of a tuple.
TupleEnd,
/// The header to a tuple struct.
///
/// After this header are the fields of the tuple struct, followed by
/// `TupleStructEnd`.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct T(u8, u8);
///
/// let t = T(0, 0);
/// assert_tokens(
/// &t,
/// &[
/// Token::TupleStruct { name: "T", len: 2 },
/// Token::U8(0),
/// Token::U8(0),
/// Token::TupleStructEnd,
/// ],
/// );
/// # }
/// ```
TupleStruct { name: &'static str, len: usize },
/// An indicator of the end of a tuple struct.
TupleStructEnd,
/// The header to a tuple variant of an enum.
///
/// After this header are the fields of the tuple variant, followed by
/// `TupleVariantEnd`.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// enum E {
/// C(u8, u8),
/// }
///
/// let c = E::C(0, 0);
/// assert_tokens(
/// &c,
/// &[
/// Token::TupleVariant {
/// name: "E",
/// variant: "C",
/// len: 2,
/// },
/// Token::U8(0),
/// Token::U8(0),
/// Token::TupleVariantEnd,
/// ],
/// );
/// # }
/// ```
TupleVariant {
name: &'static str,
variant: &'static str,
len: usize,
},
/// An indicator of the end of a tuple variant.
TupleVariantEnd,
/// The header to a map.
///
/// After this header are the entries of the map, followed by `MapEnd`.
///
/// ```edition2021
/// # use serde_test::{assert_tokens, Token};
/// #
/// use std::collections::BTreeMap;
///
/// let mut map = BTreeMap::new();
/// map.insert('A', 65);
/// map.insert('Z', 90);
///
/// assert_tokens(
/// &map,
/// &[
/// Token::Map { len: Some(2) },
/// Token::Char('A'),
/// Token::I32(65),
/// Token::Char('Z'),
/// Token::I32(90),
/// Token::MapEnd,
/// ],
/// );
/// ```
Map { len: Option<usize> },
/// An indicator of the end of a map.
MapEnd,
/// The header of a struct.
///
/// After this header are the fields of the struct, followed by `StructEnd`.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct S {
/// a: u8,
/// b: u8,
/// }
///
/// let s = S { a: 0, b: 0 };
/// assert_tokens(
/// &s,
/// &[
/// Token::Struct { name: "S", len: 2 },
/// Token::Str("a"),
/// Token::U8(0),
/// Token::Str("b"),
/// Token::U8(0),
/// Token::StructEnd,
/// ],
/// );
/// # }
/// ```
Struct { name: &'static str, len: usize },
/// An indicator of the end of a struct.
StructEnd,
/// The header of a struct variant of an enum.
///
/// After this header are the fields of the struct variant, followed by
/// `StructVariantEnd`.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// enum E {
/// D { d: u8 },
/// }
///
/// let d = E::D { d: 0 };
/// assert_tokens(
/// &d,
/// &[
/// Token::StructVariant {
/// name: "E",
/// variant: "D",
/// len: 1,
/// },
/// Token::Str("d"),
/// Token::U8(0),
/// Token::StructVariantEnd,
/// ],
/// );
/// # }
/// ```
StructVariant {
name: &'static str,
variant: &'static str,
len: usize,
},
/// An indicator of the end of a struct variant.
StructVariantEnd,
/// The header to an enum of the given name.
///
/// ```edition2021
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde_test::{assert_tokens, Token};
/// #
/// # fn main() {
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// enum E {
/// A,
/// B(u8),
/// C(u8, u8),
/// D { d: u8 },
/// }
///
/// let a = E::A;
/// assert_tokens(
/// &a,
/// &[Token::Enum { name: "E" }, Token::Str("A"), Token::Unit],
/// );
///
/// let b = E::B(0);
/// assert_tokens(
/// &b,
/// &[Token::Enum { name: "E" }, Token::Str("B"), Token::U8(0)],
/// );
///
/// let c = E::C(0, 0);
/// assert_tokens(
/// &c,
/// &[
/// Token::Enum { name: "E" },
/// Token::Str("C"),
/// Token::Seq { len: Some(2) },
/// Token::U8(0),
/// Token::U8(0),
/// Token::SeqEnd,
/// ],
/// );
///
/// let d = E::D { d: 0 };
/// assert_tokens(
/// &d,
/// &[
/// Token::Enum { name: "E" },
/// Token::Str("D"),
/// Token::Map { len: Some(1) },
/// Token::Str("d"),
/// Token::U8(0),
/// Token::MapEnd,
/// ],
/// );
/// # }
/// ```
Enum { name: &'static str },
}
impl Display for Token {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(self, formatter)
}
}
+2 -2
View File
@@ -15,7 +15,7 @@ serde = { path = "../serde" }
automod = "1.0.1"
fnv = "1.0"
rustversion = "1.0"
serde = { path = "../serde", features = ["rc", "derive"] }
serde = { path = "../serde", features = ["rc"] }
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
serde_test = { path = "../serde_test" }
serde_test = "1.0.176"
trybuild = { version = "1.0.66", features = ["diff"] }
+2 -1
View File
@@ -7,6 +7,7 @@ publish = false
[dependencies]
libc = { version = "0.2", default-features = false }
serde = { path = "../../serde", default-features = false, features = ["derive"] }
serde = { path = "../../serde", default-features = false }
serde_derive = { path = "../../serde_derive" }
[workspace]
+1 -1
View File
@@ -19,7 +19,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
//////////////////////////////////////////////////////////////////////////////
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Unit;
+1 -1
View File
@@ -1,4 +1,4 @@
use serde::Deserialize;
use serde_derive::Deserialize;
#[derive(Deserialize)]
pub struct Nested;
+1 -1
View File
@@ -1,4 +1,4 @@
use serde::Deserialize;
use serde_derive::Deserialize;
macro_rules! bug {
($serde_path:literal) => {
+42 -8
View File
@@ -10,18 +10,17 @@
clippy::uninlined_format_args,
)]
use serde::de::{self, IgnoredAny, MapAccess, Unexpected, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::collections::{BTreeMap, HashMap};
use std::convert::TryFrom;
use std::fmt;
use std::marker::PhantomData;
use serde::de::{self, Deserialize, Deserializer, IgnoredAny, MapAccess, Unexpected, Visitor};
use serde::ser::{Serialize, Serializer};
use serde_derive::{Deserialize, Serialize};
use serde_test::{
assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_ser_tokens_error,
assert_tokens, Token,
};
use std::collections::{BTreeMap, HashMap};
use std::convert::TryFrom;
use std::fmt;
use std::marker::PhantomData;
trait MyDefault: Sized {
fn my_default() -> Self;
@@ -2261,6 +2260,39 @@ fn test_externally_tagged_enum_containing_flatten() {
);
}
#[test]
fn test_internally_tagged_enum_with_skipped_conflict() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "t")]
enum Data {
A,
#[serde(skip)]
#[allow(dead_code)]
B {
t: String,
},
C {
#[serde(default, skip)]
t: String,
},
}
let data = Data::C { t: String::new() };
assert_tokens(
&data,
&[
Token::Struct {
name: "Data",
len: 1,
},
Token::Str("t"),
Token::Str("C"),
Token::StructEnd,
],
);
}
#[test]
fn test_internally_tagged_enum_containing_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
@@ -2965,7 +2997,9 @@ fn test_expecting_message() {
#[derive(Deserialize)]
#[serde(expecting = "something strange...")]
struct Struct {
#[allow(dead_code)]
question: String,
#[allow(dead_code)]
answer: u32,
}
+2 -3
View File
@@ -5,10 +5,9 @@
)]
use serde::de::value::{BorrowedStrDeserializer, MapDeserializer};
use serde::de::IntoDeserializer;
use serde::{Deserialize, Deserializer};
use serde::de::{Deserialize, Deserializer, IntoDeserializer};
use serde_derive::Deserialize;
use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};
use std::borrow::Cow;
#[test]
+20 -8
View File
@@ -10,6 +10,10 @@
)]
#![cfg_attr(feature = "unstable", feature(never_type))]
use fnv::FnvHasher;
use serde::de::{Deserialize, DeserializeOwned, Deserializer, IntoDeserializer};
use serde_derive::Deserialize;
use serde_test::{assert_de_tokens, Configure, Token};
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::default::Default;
use std::ffi::{CStr, CString, OsString};
@@ -27,16 +31,10 @@ use std::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
AtomicUsize, Ordering,
};
use std::sync::{Arc, Weak as ArcWeak};
use std::time::{Duration, UNIX_EPOCH};
#[cfg(target_arch = "x86_64")]
use std::sync::atomic::{AtomicI64, AtomicU64};
use fnv::FnvHasher;
use serde::de::{DeserializeOwned, IntoDeserializer};
use serde::{Deserialize, Deserializer};
use serde_test::{assert_de_tokens, Configure, Token};
use std::sync::{Arc, Weak as ArcWeak};
use std::time::{Duration, UNIX_EPOCH};
#[macro_use]
mod macros;
@@ -46,6 +44,9 @@ mod macros;
#[derive(Copy, Clone, PartialEq, Debug, Deserialize)]
struct UnitStruct;
#[derive(Copy, Clone, PartialEq, Debug, Deserialize)]
struct GenericUnitStruct<const N: u8>;
#[derive(PartialEq, Debug, Deserialize)]
struct NewtypeStruct(i32);
@@ -883,6 +884,17 @@ fn test_unit_struct() {
test(UnitStruct, &[Token::UnitStruct { name: "UnitStruct" }]);
}
#[test]
fn test_generic_unit_struct() {
test(GenericUnitStruct::<8>, &[Token::Unit]);
test(
GenericUnitStruct::<8>,
&[Token::UnitStruct {
name: "GenericUnitStruct",
}],
);
}
#[test]
fn test_newtype_struct() {
test(
+2 -2
View File
@@ -5,8 +5,8 @@
)]
#![cfg_attr(feature = "unstable", feature(never_type))]
use serde::de::IntoDeserializer;
use serde::Deserialize;
use serde::de::{Deserialize, IntoDeserializer};
use serde_derive::Deserialize;
use serde_test::{assert_de_tokens_error, Token};
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::ffi::{CStr, CString};
+14 -5
View File
@@ -20,9 +20,9 @@
clippy::type_repetition_in_bounds
)]
use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::{Deserialize, DeserializeOwned, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;
use std::marker::PhantomData;
use std::option::Option as StdOption;
@@ -404,7 +404,7 @@ fn test_gen() {
}
mod vis {
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
pub struct S;
@@ -636,7 +636,7 @@ fn test_gen() {
mod restricted {
mod inner {
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Restricted {
@@ -662,6 +662,7 @@ fn test_gen() {
#[derive(Deserialize)]
struct ImplicitlyBorrowedOption<'a> {
#[allow(dead_code)]
option: std::option::Option<&'a str>,
}
@@ -692,7 +693,9 @@ fn test_gen() {
#[derive(Deserialize)]
struct RelObject<'a> {
#[allow(dead_code)]
ty: &'a str,
#[allow(dead_code)]
id: String,
}
@@ -736,6 +739,7 @@ fn test_gen() {
($field:ty) => {
#[derive(Deserialize)]
struct MacroRules<'a> {
#[allow(dead_code)]
field: $field,
}
};
@@ -752,6 +756,7 @@ fn test_gen() {
#[derive(Deserialize)]
struct BorrowLifetimeInsideMacro<'a> {
#[serde(borrow = "'a")]
#[allow(dead_code)]
f: mac!(Cow<'a, str>),
}
@@ -760,6 +765,10 @@ fn test_gen() {
#[serde(serialize_with = "vec_first_element")]
vec: Vec<Self>,
}
#[derive(Deserialize)]
#[serde(bound(deserialize = "[&'de str; N]: Copy"))]
struct GenericUnitStruct<const N: usize>;
}
//////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -2,7 +2,7 @@
#![allow(clippy::derive_partial_eq_without_eq)]
use serde::Deserialize;
use serde_derive::Deserialize;
use serde_test::{assert_de_tokens, Token};
#[test]
+4 -2
View File
@@ -2,9 +2,11 @@
use serde::de::value::{Error, MapDeserializer, SeqDeserializer};
use serde::de::{
DeserializeSeed, EnumAccess, IgnoredAny, IntoDeserializer, VariantAccess, Visitor,
Deserialize, DeserializeSeed, Deserializer, EnumAccess, IgnoredAny, IntoDeserializer,
VariantAccess, Visitor,
};
use serde::{forward_to_deserialize_any, Deserialize, Deserializer};
use serde::forward_to_deserialize_any;
use serde_derive::Deserialize;
#[derive(PartialEq, Debug, Deserialize)]
enum Target {
+57 -2
View File
@@ -8,11 +8,10 @@
mod bytes;
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
use serde_test::{
assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens, Token,
};
use std::collections::BTreeMap;
use std::marker::PhantomData;
@@ -1924,6 +1923,62 @@ fn test_rename_all() {
);
}
#[test]
fn test_rename_all_fields() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all_fields = "kebab-case")]
enum E {
V1,
V2(bool),
V3 {
a_field: bool,
another_field: bool,
#[serde(rename = "last-field")]
yet_another_field: bool,
},
#[serde(rename_all = "snake_case")]
V4 {
a_field: bool,
},
}
assert_tokens(
&E::V3 {
a_field: true,
another_field: true,
yet_another_field: true,
},
&[
Token::StructVariant {
name: "E",
variant: "V3",
len: 3,
},
Token::Str("a-field"),
Token::Bool(true),
Token::Str("another-field"),
Token::Bool(true),
Token::Str("last-field"),
Token::Bool(true),
Token::StructVariantEnd,
],
);
assert_tokens(
&E::V4 { a_field: true },
&[
Token::StructVariant {
name: "E",
variant: "V4",
len: 1,
},
Token::Str("a_field"),
Token::Bool(true),
Token::StructVariantEnd,
],
);
}
#[test]
fn test_untagged_newtype_variant_containing_unit_struct_not_map() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
+1 -1
View File
@@ -1,6 +1,6 @@
#![allow(clippy::redundant_field_names)]
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
mod remote {
pub struct Unit;
-1
View File
@@ -1,5 +1,4 @@
use serde_test::{assert_tokens, Configure, Token};
use std::net;
#[macro_use]
+1 -1
View File
@@ -1,6 +1,6 @@
#![allow(clippy::used_underscore_binding)]
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
#[test]
fn test_self() {
+7 -9
View File
@@ -1,6 +1,9 @@
#![allow(clippy::derive_partial_eq_without_eq, clippy::unreadable_literal)]
#![cfg_attr(feature = "unstable", feature(never_type))]
use fnv::FnvHasher;
use serde_derive::Serialize;
use serde_test::{assert_ser_tokens, assert_ser_tokens_error, Configure, Token};
use std::cell::RefCell;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::ffi::CString;
@@ -9,21 +12,16 @@ use std::num::Wrapping;
use std::ops::Bound;
use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak as RcWeak};
#[cfg(unix)]
use std::str;
use std::sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
AtomicUsize,
};
use std::sync::{Arc, Mutex, RwLock, Weak as ArcWeak};
use std::time::{Duration, UNIX_EPOCH};
#[cfg(unix)]
use std::str;
#[cfg(target_arch = "x86_64")]
use std::sync::atomic::{AtomicI64, AtomicU64};
use fnv::FnvHasher;
use serde::Serialize;
use serde_test::{assert_ser_tokens, assert_ser_tokens_error, Configure, Token};
use std::sync::{Arc, Mutex, RwLock, Weak as ArcWeak};
use std::time::{Duration, UNIX_EPOCH};
#[macro_use]
mod macros;
+1 -1
View File
@@ -5,7 +5,7 @@
#[test]
fn test_gen_custom_serde() {
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(serde_derive::Serialize, serde_derive::Deserialize)]
#[serde(crate = "fake_serde")]
struct Foo;
+2 -2
View File
@@ -1,8 +1,8 @@
#![allow(clippy::derive_partial_eq_without_eq, clippy::similar_names)]
use serde::de::value::{self, MapAccessDeserializer};
use serde::de::{IntoDeserializer, MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use serde::de::{Deserialize, Deserializer, IntoDeserializer, MapAccess, Visitor};
use serde_derive::Deserialize;
use serde_test::{assert_de_tokens, Token};
use std::fmt;
@@ -1,5 +1,4 @@
use serde_derive::Serialize;
use std::collections::HashMap;
#[derive(Serialize)]
@@ -1,5 +1,5 @@
error: #[serde(flatten)] cannot be used on newtype structs
--> tests/ui/conflict/flatten-newtype-struct.rs:6:12
--> tests/ui/conflict/flatten-newtype-struct.rs:5:12
|
6 | struct Foo(#[serde(flatten)] HashMap<String, String>);
5 | struct Foo(#[serde(flatten)] HashMap<String, String>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1,5 +1,4 @@
use serde_derive::Serialize;
use std::collections::HashMap;
#[derive(Serialize)]
@@ -1,5 +1,5 @@
error: #[serde(flatten)] cannot be used on tuple structs
--> tests/ui/conflict/flatten-tuple-struct.rs:6:17
--> tests/ui/conflict/flatten-tuple-struct.rs:5:17
|
6 | struct Foo(u32, #[serde(flatten)] HashMap<String, String>);
5 | struct Foo(u32, #[serde(flatten)] HashMap<String, String>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1,5 +1,5 @@
error: #[serde(default)] can only be used on structs with named fields
--> tests/ui/default-attribute/enum.rs:5:1
--> tests/ui/default-attribute/enum.rs:4:9
|
5 | enum E {
| ^^^^
4 | #[serde(default)]
| ^^^^^^^
@@ -1,5 +1,5 @@
error: #[serde(default = "...")] can only be used on structs with named fields
--> tests/ui/default-attribute/enum_path.rs:5:1
--> tests/ui/default-attribute/enum_path.rs:4:9
|
5 | enum E {
| ^^^^
4 | #[serde(default = "default_e")]
| ^^^^^^^^^^^^^^^^^^^^^
@@ -1,5 +1,5 @@
error: #[serde(default = "...")] can only be used on structs with named fields
--> tests/ui/default-attribute/nameless_struct_fields_path.rs:5:9
--> tests/ui/default-attribute/nameless_struct_fields_path.rs:4:9
|
5 | struct T(u8, u8);
| ^^^^^^^^
4 | #[serde(default = "default_t")]
| ^^^^^^^^^^^^^^^^^^^^^
@@ -1,5 +1,5 @@
error: #[serde(untagged)] can only be used on enums
--> tests/ui/enum-representation/untagged-struct.rs:5:1
--> tests/ui/enum-representation/untagged-struct.rs:4:9
|
5 | struct S;
| ^^^^^^
4 | #[serde(untagged)]
| ^^^^^^^^
+1 -1
View File
@@ -1,4 +1,4 @@
use serde::Serialize;
use serde_derive::Serialize;
#[derive(Serialize)]
#[serde(bound = ""huh)]
@@ -1,5 +1,5 @@
error: #[serde(tag = "...")] can only be used on enums and structs with named fields
--> tests/ui/struct-representation/internally-tagged-tuple.rs:5:9
--> tests/ui/struct-representation/internally-tagged-tuple.rs:4:9
|
5 | struct S(u8, u8);
| ^^^^^^^^
4 | #[serde(tag = "type")]
| ^^^^^^^^^^^^
@@ -1,7 +1,5 @@
error: #[serde(tag = "...")] can only be used on enums and structs with named fields
--> tests/ui/struct-representation/internally-tagged-unit.rs:3:10
--> tests/ui/struct-representation/internally-tagged-unit.rs:4:9
|
3 | #[derive(Serialize)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info)
4 | #[serde(tag = "type")]
| ^^^^^^^^^^^^
+1 -1
View File
@@ -1,4 +1,4 @@
use serde::{Deserialize, Serialize};
use serde_derive::{Deserialize, Serialize};
use serde_test::{assert_tokens, Token};
#[test]