Compare commits

...

40 Commits

Author SHA1 Message Date
David Tolnay e1edb0282a Release 1.0.81 2018-12-07 18:30:35 -08:00
David Tolnay 5484f69164 Merge pull request #1438 from daboross/fix-untagged-enum-integer-variant-encoding
Accept integers variant encoding in Content
2018-12-07 18:17:53 -08:00
David Ross cf1e0825c1 Support only u8 for enum identifiers within Content. 2018-12-05 17:01:48 -08:00
David Ross 86faa44915 Support only u8,u32 for enum variant identifiers in Content.
u8 correctly supports msgpack-rust, and u32 supports bincode and
presumably all other similar binary formats.
2018-12-05 15:59:47 -08:00
David Ross a0b23cbf02 Accept integers variant encoding in Content
This allows ContentDeserializer and ContentRefDeserializer to
deserialize unsigned integers in deserialize_identifier, and
furthermore allows enums inside untagged enums to be correctly decoded
in formats which encode the enum variant as an integer.

Fixes https://github.com/serde-rs/serde/issues/1437.
2018-12-04 19:40:27 -08:00
David Tolnay e8ffb22c0d Merge pull request #1424 from hcpl/spanned-error-messages
Use more spans for error messages
2018-12-01 23:16:49 -08:00
David Tolnay 4d04ae0111 Sync links from serde.rs website 2018-12-01 13:01:48 -08:00
hcpl 14a3da9b16 Improve UI test coverage
With this commit I believe I've covered all `compile_error!`-based
errors.
2018-11-30 03:07:31 +02:00
hcpl 034db9f20f Improve overall quality of compile_error! errors
Also updates UI tests.
2018-11-30 02:51:49 +02:00
hcpl 8f3f073017 Use more spans for error messages 2018-11-25 16:44:41 +02:00
David Tolnay 58b3af4c29 Copyright/license headers
The following changes are included:

- Delete per-file license notices at the top of each file.
- Delete the first paragraph of LICENSE-MIT (an inaccurate
  pseudo-copyright line), leaving only the text of the MIT license.

Nothing about the license of Serde code has changed, only our
understanding of how to correctly communicate that license has changed.

This mirrors an equivalent change being applied in the rust-lang/rust
repository.
2018-11-24 15:53:09 -08:00
David Tolnay 4821d09a48 Move all compile-fail tests to ui tests
The update-references.sh script makes these much easier to update in
bulk compared to compile-fail tests.
2018-11-24 15:43:19 -08:00
David Tolnay b3d9d51b51 Simplify compiletest setup 2018-11-24 15:35:49 -08:00
David Tolnay 6b33abb179 Set up Travis build names 2018-11-24 15:12:48 -08:00
David Tolnay a043b2a763 Point serde_derive_internals documentation to docs.rs 2018-11-21 14:22:33 -08:00
David Tolnay 0c3d4a8a37 Release serde_derive_internals 0.24.0 2018-11-21 14:17:55 -08:00
David Tolnay 9afc5fef11 Format with rustfmt 1.0.0-nightly 2018-11-21 01:13:17 -08:00
David Tolnay a8a54c0568 Remove 1.26-dev docs.rs workaround
They are now building with 1.31.0-nightly.
2018-11-11 12:13:25 -08:00
David Tolnay 451ee2d78e Clean up calls to into_iter per into_iter_on_ref lint 2018-11-10 20:10:37 -08:00
David Tolnay 820107d15e Move emscripten CI to allow_failures
Not sure what is going on with this failure that just started happening with no
code change on our end. Wait and see if it goes away.

On asmjs-unknown-emscripten:

    Assertion failed: compiled without a main, but one is present. if you added
    it from JS, use Module["onRuntimeInitialized"]

    undefined:109
        throw ex;
        ^

    abort("Assertion failed: compiled without a main, but one is present. if you
    added it from JS, use Module[\"onRuntimeInitialized\"]") at Error

On wasm32-unknown-emscripten:

    Assertion failed: compiled without a main, but one is present. if you added
    it from JS, use Module["onRuntimeInitialized"]

    failed to asynchronously prepare wasm: abort("Assertion failed: compiled
    without a main, but one is present. if you added it from JS, use
    Module[\"onRuntimeInitialized\"]") at Error
2018-11-10 20:06:18 -08:00
David Tolnay a51f831ae4 Drop nightly dependency of compiletest 2018-10-27 23:59:48 -07:00
David Tolnay 1b45e5766a Release 1.0.80 2018-10-14 03:08:53 -07:00
David Tolnay 59c8951341 Merge pull request #1411 from dtolnay/vec
Optimize Vec::deserialize_in_place to deserialize elements in place
2018-10-14 03:08:04 -07:00
David Tolnay aca61b5dda Optimize Vec::deserialize_in_place to deserialize elements in place 2018-10-14 02:51:24 -07:00
David Tolnay 908affd24f Remove unused code in seq and map impls 2018-10-14 02:31:56 -07:00
David Tolnay f878d2ebd5 Do not require clippy for a green build 2018-10-06 21:26:25 -07:00
David Tolnay 778e516270 Feature panic_handler has been stabilized 2018-10-06 21:12:14 -07:00
David Tolnay 6d58492ad0 Fix links to redirected derive documentation 2018-10-03 23:14:49 -07:00
David Tolnay fecfabb168 Merge pull request #1399 from derekdreery/more_docs
Some docs
2018-09-30 08:16:24 -07:00
Richard Dodd 80765eb453 Make suggested changes 2018-09-30 15:17:47 +01:00
Richard Dodd f1073dca04 Make the recommended changed from code review. 2018-09-30 12:34:52 +01:00
Richard Dodd da65fe5a52 Some docs 2018-09-29 15:06:23 +01:00
David Tolnay 3f0f739e17 Merge pull request #1391 from dtolnay/ci
Move CI commands into travis.yml and appveyor.yml
2018-09-15 17:00:27 -07:00
David Tolnay 5023e2ad52 Fix escaping issues in emscripten CI commands 2018-09-15 16:37:46 -07:00
David Tolnay 810cde1c84 Split travis builds into individual steps 2018-09-15 16:15:59 -07:00
David Tolnay 9436efb80e Move CI commands into travis.yml and appveyor.yml 2018-09-15 16:04:57 -07:00
David Tolnay 48230890c5 Merge pull request #1390 from dtolnay/asmjs
Run test suite on asmjs
2018-09-15 15:50:11 -07:00
David Tolnay f1e8dcf38e Run test suite on asmjs 2018-09-15 15:25:55 -07:00
David Tolnay 2cf10a6003 Remove separate proc-macro2/nightly build
This feature is automatically enabled on sufficiently new compilers.
2018-09-15 15:25:19 -07:00
David Tolnay 23a53d8008 Remove unused proc-macro2 dependency in test suite 2018-09-15 15:12:47 -07:00
319 changed files with 2827 additions and 2313 deletions
+90 -20
View File
@@ -1,25 +1,95 @@
sudo: false
language: rust
cache: cargo
# run builds for all the trains (and more)
rust:
- stable
- beta
- nightly
- 1.13.0
- 1.15.0
- 1.20.0
- 1.21.0
- 1.25.0
- 1.26.0
matrix:
include:
- rust: nightly
env: CLIPPY=true
- rust: nightly
env: EMSCRIPTEN=true
script: nvm install 9 && ./travis.sh
- rust: stable
script:
- cd "${TRAVIS_BUILD_DIR}/serde"
- cargo build --features rc
- cargo build --no-default-features
- cd "${TRAVIS_BUILD_DIR}/serde_test"
- cargo build
- cargo test
script: ./travis.sh
- rust: beta
script:
- cd "${TRAVIS_BUILD_DIR}/serde"
- cargo build --features rc
- cd "${TRAVIS_BUILD_DIR}/test_suite"
- cargo test
- rust: nightly
script:
- cd "${TRAVIS_BUILD_DIR}/serde"
- cargo build
- cargo build --no-default-features
- cargo build --no-default-features --features alloc
- cargo build --no-default-features --features rc,alloc
- cargo test --features rc,unstable
- cd "${TRAVIS_BUILD_DIR}/test_suite/deps"
- cargo build
- cd "${TRAVIS_BUILD_DIR}/test_suite"
- cargo test --features unstable
- cd "${TRAVIS_BUILD_DIR}/test_suite/no_std"
- cargo build
- rust: 1.13.0
script:
- cd "${TRAVIS_BUILD_DIR}/serde"
- cargo build --features rc
- cargo build --no-default-features
- cd "${TRAVIS_BUILD_DIR}/serde_test"
- cargo build
- rust: 1.15.0
script:
- cd "${TRAVIS_BUILD_DIR}/serde_derive"
- cargo build
- rust: 1.20.0
- rust: 1.21.0
- rust: 1.25.0
- rust: 1.26.0
- rust: nightly
name: Clippy
script:
- rustup component add clippy-preview || travis_terminate 0
- cargo clippy -- -Dclippy
- cd "${TRAVIS_BUILD_DIR}/serde"
- cargo clippy --features rc,unstable -- -Dclippy
- cd "${TRAVIS_BUILD_DIR}/serde_derive"
- cargo clippy -- -Dclippy
- cd "${TRAVIS_BUILD_DIR}/serde_test"
- cargo clippy -- -Dclippy
- cd "${TRAVIS_BUILD_DIR}/test_suite"
- cargo clippy --features unstable -- -Dclippy
- cd "${TRAVIS_BUILD_DIR}/test_suite/no_std"
- cargo clippy -- -Dclippy
- rust: nightly
name: Emscripten
script:
- CARGO_WEB_RELEASE=$(curl -L -s -H Accept:application/json https://github.com/koute/cargo-web/releases/latest)
- CARGO_WEB_VERSION=$(echo "${CARGO_WEB_RELEASE}" | jq -r .tag_name)
- CARGO_WEB_URL="https://github.com/koute/cargo-web/releases/download/${CARGO_WEB_VERSION}/cargo-web-x86_64-unknown-linux-gnu.gz"
- nvm install 9
- mkdir -p ~/.cargo/bin
- curl -L "${CARGO_WEB_URL}" | gzip -d > ~/.cargo/bin/cargo-web
- chmod +x ~/.cargo/bin/cargo-web
- cd "${TRAVIS_BUILD_DIR}/test_suite"
- cargo web test --target=asmjs-unknown-emscripten --nodejs
- cargo web test --target=wasm32-unknown-emscripten --nodejs
allow_failures:
- rust: nightly
name: Clippy
- rust: nightly
name: Emscripten
script:
- cd "${TRAVIS_BUILD_DIR}/serde"
- cargo build --no-default-features
- cargo build
-2
View File
@@ -1,5 +1,3 @@
Copyright (c) 2014 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
+1 -1
View File
@@ -15,7 +15,7 @@ You may be looking for:
- [An overview of Serde](https://serde.rs/)
- [Data formats supported by Serde](https://serde.rs/#data-formats)
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/codegen.html)
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
- [Examples](https://serde.rs/examples.html)
- [API documentation](https://docs.serde.rs/serde/)
- [Release notes](https://github.com/serde-rs/serde/releases)
+26 -2
View File
@@ -13,5 +13,29 @@ install:
build: false
test_script:
- sh -c 'PATH=`rustc --print sysroot`/bin:$PATH ./travis.sh'
for:
- matrix:
only:
- APPVEYOR_RUST_CHANNEL: stable
test_script:
- cd %APPVEYOR_BUILD_FOLDER%\serde
- cargo build --features rc
- cargo build --no-default-features
- cd %APPVEYOR_BUILD_FOLDER%\serde_test
- cargo build
- cargo test
- matrix:
only:
- APPVEYOR_RUST_CHANNEL: nightly
test_script:
- cd %APPVEYOR_BUILD_FOLDER%\serde
- cargo build
- cargo build --no-default-features
- cargo build --no-default-features --features alloc
- cargo build --no-default-features --features rc,alloc
- cargo test --features rc,unstable
- cd %APPVEYOR_BUILD_FOLDER%\test_suite\deps
- cargo build
- cd %APPVEYOR_BUILD_FOLDER%\test_suite
- cargo test --features unstable
+1 -1
View File
@@ -8,7 +8,7 @@ You may be looking for:
- [An overview of Serde](https://serde.rs/)
- [Data formats supported by Serde](https://serde.rs/#data-formats)
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/codegen.html)
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
- [Examples](https://serde.rs/examples.html)
- [API documentation](https://docs.serde.rs/serde/)
- [Release notes](https://github.com/serde-rs/serde/releases)
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.79" # remember to update html_root_url
version = "1.0.81" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework"
-5
View File
@@ -71,11 +71,6 @@ fn rustc_minor_version() -> Option<u32> {
Err(_) => return None,
};
// Temporary workaround to support the old 1.26-dev compiler on docs.rs.
if version.contains("0eb87c9bf") {
return Some(25);
}
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return None;
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lib::*;
macro_rules! int_to_int {
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lib::*;
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
+99 -46
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lib::*;
use de::{
@@ -696,7 +688,6 @@ macro_rules! seq_impl {
(
$ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >,
$access:ident,
$ctor:expr,
$clear:expr,
$with_capacity:expr,
$reserve:expr,
@@ -793,7 +784,6 @@ fn nop_reserve<T>(_seq: T, _n: usize) {}
seq_impl!(
BinaryHeap<T: Ord>,
seq,
BinaryHeap::new(),
BinaryHeap::clear,
BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())),
BinaryHeap::reserve,
@@ -803,7 +793,6 @@ seq_impl!(
seq_impl!(
BTreeSet<T: Eq + Ord>,
seq,
BTreeSet::new(),
BTreeSet::clear,
BTreeSet::new(),
nop_reserve,
@@ -813,7 +802,6 @@ seq_impl!(
seq_impl!(
LinkedList<T>,
seq,
LinkedList::new(),
LinkedList::clear,
LinkedList::new(),
nop_reserve,
@@ -824,28 +812,15 @@ seq_impl!(
seq_impl!(
HashSet<T: Eq + Hash, S: BuildHasher + Default>,
seq,
HashSet::with_hasher(S::default()),
HashSet::clear,
HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()),
HashSet::reserve,
HashSet::insert);
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
Vec<T>,
seq,
Vec::new(),
Vec::clear,
Vec::with_capacity(size_hint::cautious(seq.size_hint())),
Vec::reserve,
Vec::push
);
#[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!(
VecDeque<T>,
seq,
VecDeque::new(),
VecDeque::clear,
VecDeque::with_capacity(size_hint::cautious(seq.size_hint())),
VecDeque::reserve,
@@ -854,6 +829,99 @@ seq_impl!(
////////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, T> Deserialize<'de> for Vec<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct VecVisitor<T> {
marker: PhantomData<T>,
}
impl<'de, T> Visitor<'de> for VecVisitor<T>
where
T: Deserialize<'de>,
{
type Value = Vec<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a sequence")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut values = Vec::with_capacity(size_hint::cautious(seq.size_hint()));
while let Some(value) = try!(seq.next_element()) {
values.push(value);
}
Ok(values)
}
}
let visitor = VecVisitor {
marker: PhantomData,
};
deserializer.deserialize_seq(visitor)
}
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
struct VecInPlaceVisitor<'a, T: 'a>(&'a mut Vec<T>);
impl<'a, 'de, T> Visitor<'de> for VecInPlaceVisitor<'a, T>
where
T: Deserialize<'de>,
{
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a sequence")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let hint = size_hint::cautious(seq.size_hint());
if let Some(additional) = hint.checked_sub(self.0.len()) {
self.0.reserve(additional);
}
for i in 0..self.0.len() {
let next = {
let next_place = InPlaceSeed(&mut self.0[i]);
try!(seq.next_element_seed(next_place))
};
if next.is_none() {
self.0.truncate(i);
return Ok(());
}
}
while let Some(value) = try!(seq.next_element()) {
self.0.push(value);
}
Ok(())
}
}
deserializer.deserialize_seq(VecInPlaceVisitor(place))
}
}
////////////////////////////////////////////////////////////////////////////////
struct ArrayVisitor<A> {
marker: PhantomData<A>,
}
@@ -1113,7 +1181,6 @@ macro_rules! map_impl {
(
$ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >,
$access:ident,
$ctor:expr,
$with_capacity:expr
) => {
impl<'de, K, V $(, $typaram)*> Deserialize<'de> for $ty<K, V $(, $typaram)*>
@@ -1168,14 +1235,12 @@ macro_rules! map_impl {
map_impl!(
BTreeMap<K: Ord, V>,
map,
BTreeMap::new(),
BTreeMap::new());
#[cfg(feature = "std")]
map_impl!(
HashMap<K: Eq + Hash, V, S: BuildHasher + Default>,
map,
HashMap::with_hasher(S::default()),
HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default()));
////////////////////////////////////////////////////////////////////////////////
@@ -1354,7 +1419,7 @@ impl<'de> Deserialize<'de> for net::IpAddr {
deserializer.deserialize_str(IpAddrVisitor)
} else {
use lib::net::IpAddr;
deserialize_enum!{
deserialize_enum! {
IpAddr IpAddrKind (V4; b"V4"; 0, V6; b"V6"; 1)
"`V4` or `V6`",
deserializer
@@ -1431,7 +1496,7 @@ impl<'de> Deserialize<'de> for net::SocketAddr {
deserializer.deserialize_str(SocketAddrVisitor)
} else {
use lib::net::SocketAddr;
deserialize_enum!{
deserialize_enum! {
SocketAddr SocketAddrKind (V4; b"V4"; 0, V6; b"V6"; 1)
"`V4` or `V6`",
deserializer
@@ -1531,7 +1596,7 @@ impl<'de> Deserialize<'de> for PathBuf {
// #[derive(Deserialize)]
// #[serde(variant_identifier)]
#[cfg(all(feature = "std", any(unix, windows)))]
variant_identifier!{
variant_identifier! {
OsStringKind (Unix; b"Unix"; 0, Windows; b"Windows"; 1)
"`Unix` or `Windows`",
OSSTR_VARIANTS
@@ -1689,11 +1754,7 @@ where
////////////////////////////////////////////////////////////////////////////////
#[cfg(all(
de_rc_dst,
feature = "rc",
any(feature = "std", feature = "alloc")
))]
#[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))]
macro_rules! box_forwarded_impl {
(
$(#[doc = $doc:tt])*
@@ -1714,11 +1775,7 @@ macro_rules! box_forwarded_impl {
};
}
#[cfg(all(
de_rc_dst,
feature = "rc",
any(feature = "std", feature = "alloc")
))]
#[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))]
box_forwarded_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde.
///
@@ -1730,11 +1787,7 @@ box_forwarded_impl! {
Rc
}
#[cfg(all(
de_rc_dst,
feature = "rc",
any(feature = "std", feature = "alloc")
))]
#[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))]
box_forwarded_impl! {
/// This impl requires the [`"rc"`] Cargo feature of Serde.
///
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Generic data structure deserialization framework.
//!
//! The two most important traits in this module are [`Deserialize`] and
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lib::*;
const TAG_CONT: u8 = 0b1000_0000;
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Building blocks for deserializing basic values using the `IntoDeserializer`
//! trait.
//!
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub use lib::clone::Clone;
pub use lib::convert::{From, Into};
pub use lib::default::Default;
+11 -18
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! # Serde
//!
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
@@ -50,17 +42,17 @@
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
//! - [TOML], a minimal configuration format used by [Cargo].
//! - [Pickle], a format common in the Python world.
//! - [Hjson], a variant of JSON designed to be readable and writable by humans.
//! - [RON], a Rusty Object Notation.
//! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [Avro], a binary format used within Apache Hadoop, with support for schema
//! definition.
//! - [Hjson], a variant of JSON designed to be readable and writable by humans.
//! - [JSON5], A superset of JSON including some productions from ES5.
//! - [URL], the x-www-form-urlencoded format.
//! - [XML], the flexible machine-friendly W3C standard.
//! *(deserialization only)*
//! - [Envy], a way to deserialize environment variables into Rust structs.
//! *(deserialization only)*
//! - [Redis], deserialize values from Redis when using [redis-rs].
//! *(deserialization only)*
//! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into
//! Rust structs. *(deserialization only)*
//!
//! [JSON]: https://github.com/serde-rs/json
//! [Bincode]: https://github.com/TyOverby/bincode
@@ -69,20 +61,21 @@
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
//! [TOML]: https://github.com/alexcrichton/toml-rs
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
//! [Hjson]: https://github.com/laktak/hjson-rust
//! [RON]: https://github.com/ron-rs/ron
//! [BSON]: https://github.com/zonyitoo/bson-rs
//! [Avro]: https://github.com/flavray/avro-rs
//! [Hjson]: https://github.com/laktak/hjson-rust
//! [JSON5]: https://github.com/callum-oakley/json5-rs
//! [URL]: https://github.com/nox/serde_urlencoded
//! [XML]: https://github.com/RReverser/serde-xml-rs
//! [Envy]: https://github.com/softprops/envy
//! [Redis]: https://github.com/OneSignal/serde-redis
//! [Envy Store]: https://github.com/softprops/envy-store
//! [Cargo]: http://doc.crates.io/manifest.html
//! [redis-rs]: https://crates.io/crates/redis
//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.79")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.81")]
// 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
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Super explicit first paragraph because this shows up at the top level and
// trips up people who are just looking for basic Serialize / Deserialize
// documentation.
+8 -14
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lib::*;
use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor};
@@ -1427,6 +1419,7 @@ mod content {
Content::Str(v) => visitor.visit_borrowed_str(v),
Content::ByteBuf(v) => visitor.visit_byte_buf(v),
Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
Content::U8(v) => visitor.visit_u8(v),
_ => Err(self.invalid_type(&visitor)),
}
}
@@ -1763,7 +1756,7 @@ mod content {
V: Visitor<'de>,
E: de::Error,
{
let seq = content.into_iter().map(ContentRefDeserializer::new);
let seq = content.iter().map(ContentRefDeserializer::new);
let mut seq_visitor = de::value::SeqDeserializer::new(seq);
let value = try!(visitor.visit_seq(&mut seq_visitor));
try!(seq_visitor.end());
@@ -1778,7 +1771,7 @@ mod content {
V: Visitor<'de>,
E: de::Error,
{
let map = content.into_iter().map(|&(ref k, ref v)| {
let map = content.iter().map(|&(ref k, ref v)| {
(
ContentRefDeserializer::new(k),
ContentRefDeserializer::new(v),
@@ -2085,7 +2078,7 @@ mod content {
{
let (variant, value) = match *self.content {
Content::Map(ref value) => {
let mut iter = value.into_iter();
let mut iter = value.iter();
let &(ref variant, ref value) = match iter.next() {
Some(v) => v,
None => {
@@ -2129,6 +2122,7 @@ mod content {
Content::Str(v) => visitor.visit_borrowed_str(v),
Content::ByteBuf(ref v) => visitor.visit_bytes(v),
Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
Content::U8(v) => visitor.visit_u8(v),
_ => Err(self.invalid_type(&visitor)),
}
}
@@ -2272,9 +2266,9 @@ mod content {
where
E: de::Error,
{
fn new(vec: &'a [Content<'de>]) -> Self {
fn new(slice: &'a [Content<'de>]) -> Self {
SeqRefDeserializer {
iter: vec.into_iter(),
iter: slice.iter(),
err: PhantomData,
}
}
@@ -2350,7 +2344,7 @@ mod content {
{
fn new(map: &'a [(Content<'de>, Content<'de>)]) -> Self {
MapRefDeserializer {
iter: map.into_iter(),
iter: map.iter(),
value: None,
err: PhantomData,
}
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[doc(hidden)]
#[macro_export]
macro_rules! __private_serialize {
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
mod macros;
pub mod de;
+9 -20
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lib::*;
use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
@@ -409,10 +401,9 @@ mod content {
}
fn end(mut self) -> Result<M::Ok, M::Error> {
try!(
self.map
.serialize_value(&Content::TupleStruct(self.name, self.fields))
);
try!(self
.map
.serialize_value(&Content::TupleStruct(self.name, self.fields)));
self.map.end()
}
}
@@ -454,10 +445,9 @@ mod content {
}
fn end(mut self) -> Result<M::Ok, M::Error> {
try!(
self.map
.serialize_value(&Content::Struct(self.name, self.fields))
);
try!(self
.map
.serialize_value(&Content::Struct(self.name, self.fields)));
self.map.end()
}
}
@@ -1328,10 +1318,9 @@ where
}
fn end(self) -> Result<(), Self::Error> {
try!(
self.map
.serialize_value(&Content::Struct(self.name, self.fields))
);
try!(self
.map
.serialize_value(&Content::Struct(self.name, self.fields)));
Ok(())
}
}
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lib::*;
use ser::{Error, Serialize, SerializeTuple, Serializer};
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! This module contains `Impossible` serializer and its implementations.
use lib::*;
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Generic data structure serialization framework.
//!
//! The two most important traits in this module are [`Serialize`] and
+3 -3
View File
@@ -1,12 +1,12 @@
[package]
name = "serde_derive"
version = "1.0.79" # remember to update html_root_url
version = "1.0.81" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://serde.rs/codegen.html"
documentation = "https://serde.rs/derive.html"
keywords = ["serde", "serialization", "no_std"]
readme = "crates-io.md"
include = ["Cargo.toml", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
@@ -26,7 +26,7 @@ proc-macro = true
[dependencies]
proc-macro2 = "0.4"
quote = "0.6.3"
syn = { version = "0.15", features = ["visit"] }
syn = { version = "0.15.22", features = ["visit"] }
[dev-dependencies]
serde = { version = "1.0", path = "../serde" }
+25 -24
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::collections::HashSet;
use syn;
@@ -32,7 +24,8 @@ pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
..param.clone()
}),
_ => param.clone(),
}).collect(),
})
.collect(),
..generics.clone()
}
}
@@ -45,7 +38,7 @@ pub fn with_where_predicates(
generics
.make_where_clause()
.predicates
.extend(predicates.into_iter().cloned());
.extend(predicates.iter().cloned());
generics
}
@@ -168,15 +161,17 @@ pub fn with_bound(
associated_type_usage: Vec::new(),
};
match cont.data {
Data::Enum(ref variants) => for variant in variants.iter() {
let relevant_fields = variant
.fields
.iter()
.filter(|field| filter(&field.attrs, Some(&variant.attrs)));
for field in relevant_fields {
visitor.visit_field(field.original);
Data::Enum(ref variants) => {
for variant in variants.iter() {
let relevant_fields = variant
.fields
.iter()
.filter(|field| filter(&field.attrs, Some(&variant.attrs)));
for field in relevant_fields {
visitor.visit_field(field.original);
}
}
},
}
Data::Struct(_, ref fields) => {
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
visitor.visit_field(field.original);
@@ -193,7 +188,8 @@ pub fn with_bound(
.map(|id| syn::TypePath {
qself: None,
path: id.into(),
}).chain(associated_type_usage.into_iter().cloned())
})
.chain(associated_type_usage.into_iter().cloned())
.map(|bounded_ty| {
syn::WherePredicate::Type(syn::PredicateType {
lifetimes: None,
@@ -206,7 +202,8 @@ pub fn with_bound(
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: bound.clone(),
})].into_iter()
})]
.into_iter()
.collect(),
})
});
@@ -239,7 +236,8 @@ pub fn with_self_bound(
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: bound.clone(),
})].into_iter()
})]
.into_iter()
.collect(),
}));
generics
@@ -269,7 +267,8 @@ pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Gen
syn::GenericParam::Const(_) => {}
}
param
})).collect();
}))
.collect();
syn::Generics {
params: params,
@@ -305,11 +304,13 @@ fn type_of_item(cont: &Container) -> syn::Type {
syn::GenericParam::Const(_) => {
panic!("Serde does not support const generics yet");
}
}).collect(),
})
.collect(),
gt_token: <Token![>]>::default(),
},
),
}].into_iter()
}]
.into_iter()
.collect(),
},
})
+34 -24
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use proc_macro2::{Literal, Span, TokenStream};
use quote::ToTokens;
use syn::punctuated::Punctuated;
@@ -21,9 +13,12 @@ use try;
use std::collections::BTreeSet;
pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream, String> {
pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
let ctxt = Ctxt::new();
let cont = Container::from_ast(&ctxt, input, Derive::Deserialize);
let cont = match Container::from_ast(&ctxt, input, Derive::Deserialize) {
Some(cont) => cont,
None => return Err(ctxt.check().unwrap_err()),
};
precondition(&ctxt, &cont);
try!(ctxt.check());
@@ -94,7 +89,7 @@ fn precondition_sized(cx: &Ctxt, cont: &Container) {
if let Data::Struct(_, ref fields) = cont.data {
if let Some(last) = fields.last() {
if let syn::Type::Slice(_) = *last.ty {
cx.error("cannot deserialize a dynamically sized struct");
cx.error_spanned_by(cont.original, "cannot deserialize a dynamically sized struct");
}
}
}
@@ -104,7 +99,10 @@ fn precondition_no_de_lifetime(cx: &Ctxt, cont: &Container) {
if let BorrowedLifetimes::Borrowed(_) = borrowed_lifetimes(cont) {
for param in cont.generics.lifetimes() {
if param.lifetime.to_string() == "'de" {
cx.error("cannot deserialize when there is a lifetime parameter called 'de");
cx.error_spanned_by(
&param.lifetime,
"cannot deserialize when there is a lifetime parameter called 'de",
);
return;
}
}
@@ -365,7 +363,10 @@ fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
let path = match transparent_field.attrs.deserialize_with() {
Some(path) => quote!(#path),
None => quote!(_serde::Deserialize::deserialize),
None => {
let span = transparent_field.original.span();
quote_spanned!(span=> _serde::Deserialize::deserialize)
},
};
let assign = fields.iter().map(|field| {
@@ -805,8 +806,10 @@ fn deserialize_newtype_struct(
let value = match field.attrs.deserialize_with() {
None => {
let span = field.original.span();
let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize);
quote! {
try!(<#field_ty as _serde::Deserialize>::deserialize(__e))
try!(#func(__e))
}
}
Some(path) => {
@@ -1369,7 +1372,8 @@ fn deserialize_adjacently_tagged_enum(
quote! {
__Field::#variant_index => #block
}
}).collect();
})
.collect();
let expecting = format!("adjacently tagged enum {}", params.type_name());
let type_name = cattrs.name().deserialize_name();
@@ -1810,10 +1814,10 @@ fn deserialize_externally_tagged_newtype_variant(
match field.attrs.deserialize_with() {
None => {
let field_ty = field.ty;
let span = field.original.span();
let func = quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>);
quote_expr! {
_serde::export::Result::map(
_serde::de::VariantAccess::newtype_variant::<#field_ty>(__variant),
#this::#variant_ident)
_serde::export::Result::map(#func(__variant), #this::#variant_ident)
}
}
Some(path) => {
@@ -1838,10 +1842,10 @@ fn deserialize_untagged_newtype_variant(
let field_ty = field.ty;
match field.attrs.deserialize_with() {
None => {
let span = field.original.span();
let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize);
quote_expr! {
_serde::export::Result::map(
<#field_ty as _serde::Deserialize>::deserialize(#deserializer),
#this::#variant_ident)
_serde::export::Result::map(#func(#deserializer), #this::#variant_ident)
}
}
Some(path) => {
@@ -1962,7 +1966,8 @@ fn deserialize_custom_identifier(
variant.attrs.name().deserialize_name(),
variant.ident.clone(),
)
}).collect();
})
.collect();
let names = names_idents.iter().map(|&(ref name, _)| name);
@@ -2447,7 +2452,10 @@ fn deserialize_map(
.map(|&(field, ref name)| {
let field_ty = field.ty;
let func = match field.attrs.deserialize_with() {
None => quote!(_serde::de::Deserialize::deserialize),
None => {
let span = field.original.span();
quote_spanned!(span=> _serde::de::Deserialize::deserialize)
},
Some(path) => quote!(#path),
};
quote! {
@@ -2799,7 +2807,9 @@ fn wrap_deserialize_variant_with(
fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
match *field.attrs.default() {
attr::Default::Default => {
return quote_expr!(_serde::export::Default::default());
let span = field.original.span();
let func = quote_spanned!(span=> _serde::export::Default::default);
return quote_expr!(#func());
}
attr::Default::Path(ref path) => {
return quote_expr!(#path());
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::token;
+45 -23
View File
@@ -1,10 +1,4 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A Serde ast, parsed from the Syn ast and ready to generate Rust code.
use internals::attr;
use internals::check;
@@ -12,25 +6,39 @@ use internals::{Ctxt, Derive};
use syn;
use syn::punctuated::Punctuated;
/// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`,
/// parsed into an internal representation.
pub struct Container<'a> {
/// The struct or enum name (without generics).
pub ident: syn::Ident,
/// Attributes on the structure, parsed for Serde.
pub attrs: attr::Container,
/// The contents of the struct or enum.
pub data: Data<'a>,
/// Any generics on the struct or enum.
pub generics: &'a syn::Generics,
/// Original input.
pub original: &'a syn::DeriveInput,
}
/// The fields of a struct or enum.
///
/// Analagous to `syn::Data`.
pub enum Data<'a> {
Enum(Vec<Variant<'a>>),
Struct(Style, Vec<Field<'a>>),
}
/// A variant of an enum.
pub struct Variant<'a> {
pub ident: syn::Ident,
pub attrs: attr::Variant,
pub style: Style,
pub fields: Vec<Field<'a>>,
pub original: &'a syn::Variant,
}
/// A field of a struct.
pub struct Field<'a> {
pub member: syn::Member,
pub attrs: attr::Field,
@@ -40,14 +48,19 @@ pub struct Field<'a> {
#[derive(Copy, Clone)]
pub enum Style {
/// Named fields.
Struct,
/// Many unnamed fields.
Tuple,
/// One unnamed field.
Newtype,
/// No fields.
Unit,
}
impl<'a> Container<'a> {
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput, derive: Derive) -> Container<'a> {
/// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`.
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput, derive: Derive) -> Option<Container<'a>> {
let mut attrs = attr::Container::from_ast(cx, item);
let mut data = match item.data {
@@ -59,27 +72,32 @@ impl<'a> Container<'a> {
Data::Struct(style, fields)
}
syn::Data::Union(_) => {
panic!("Serde does not support derive for unions");
cx.error_spanned_by(item, "Serde does not support derive for unions");
return None;
}
};
let mut has_flatten = false;
match data {
Data::Enum(ref mut variants) => for variant in variants {
variant.attrs.rename_by_rule(attrs.rename_all());
for field in &mut variant.fields {
Data::Enum(ref mut variants) => {
for variant in variants {
variant.attrs.rename_by_rule(attrs.rename_all());
for field in &mut variant.fields {
if field.attrs.flatten() {
has_flatten = true;
}
field.attrs.rename_by_rule(variant.attrs.rename_all());
}
}
}
Data::Struct(_, ref mut fields) => {
for field in fields {
if field.attrs.flatten() {
has_flatten = true;
}
field.attrs.rename_by_rule(variant.attrs.rename_all());
field.attrs.rename_by_rule(attrs.rename_all());
}
},
Data::Struct(_, ref mut fields) => for field in fields {
if field.attrs.flatten() {
has_flatten = true;
}
field.attrs.rename_by_rule(attrs.rename_all());
},
}
}
if has_flatten {
@@ -91,9 +109,10 @@ impl<'a> Container<'a> {
attrs: attrs,
data: data,
generics: &item.generics,
original: item,
};
check::check(cx, &mut item, derive);
item
Some(item)
}
}
@@ -128,8 +147,10 @@ fn enum_from_ast<'a>(
attrs: attrs,
style: style,
fields: fields,
original: variant,
}
}).collect()
})
.collect()
}
fn struct_from_ast<'a>(
@@ -172,5 +193,6 @@ fn fields_from_ast<'a>(
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
ty: &field.ty,
original: field,
}).collect()
})
.collect()
}
+308 -172
View File
@@ -1,13 +1,6 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use internals::Ctxt;
use proc_macro2::{Group, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::collections::BTreeSet;
use std::str::FromStr;
use syn;
@@ -27,10 +20,11 @@ use syn::NestedMeta::{Literal, Meta};
pub use internals::case::RenameRule;
#[derive(Copy, Clone)]
#[derive(Clone)]
struct Attr<'c, T> {
cx: &'c Ctxt,
name: &'static str,
tokens: TokenStream,
value: Option<T>,
}
@@ -39,22 +33,28 @@ impl<'c, T> Attr<'c, T> {
Attr {
cx: cx,
name: name,
tokens: TokenStream::new(),
value: None,
}
}
fn set(&mut self, value: T) {
fn set<A: ToTokens>(&mut self, obj: A, value: T) {
let tokens = obj.into_token_stream();
if self.value.is_some() {
self.cx
.error(format!("duplicate serde attribute `{}`", self.name));
self.cx.error_spanned_by(
tokens,
format!("duplicate serde attribute `{}`", self.name),
);
} else {
self.tokens = tokens;
self.value = Some(value);
}
}
fn set_opt(&mut self, value: Option<T>) {
fn set_opt<A: ToTokens>(&mut self, obj: A, value: Option<T>) {
if let Some(value) = value {
self.set(value);
self.set(obj, value);
}
}
@@ -67,6 +67,13 @@ impl<'c, T> Attr<'c, T> {
fn get(self) -> Option<T> {
self.value
}
fn get_with_tokens(self) -> Option<(TokenStream, T)> {
match self.value {
Some(v) => Some((self.tokens, v)),
None => None,
}
}
}
struct BoolAttr<'c>(Attr<'c, ()>);
@@ -76,8 +83,8 @@ impl<'c> BoolAttr<'c> {
BoolAttr(Attr::none(cx, name))
}
fn set_true(&mut self) {
self.0.set(());
fn set_true<A: ToTokens>(&mut self, obj: A) {
self.0.set(obj, ());
}
fn get(&self) -> bool {
@@ -106,7 +113,7 @@ impl Name {
}
}
/// Represents container (e.g. struct) attribute information
/// Represents struct or enum attribute information.
pub struct Container {
name: Name,
transparent: bool,
@@ -207,16 +214,16 @@ impl Container {
// Parse `#[serde(rename = "foo")]`
Meta(NameValue(ref m)) if m.ident == "rename" => {
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
ser_name.set(s.value());
de_name.set(s.value());
ser_name.set(&m.ident, s.value());
de_name.set(&m.ident, s.value());
}
}
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
Meta(List(ref m)) if m.ident == "rename" => {
if let Ok((ser, de)) = get_renames(cx, &m.nested) {
ser_name.set_opt(ser.map(syn::LitStr::value));
de_name.set_opt(de.map(syn::LitStr::value));
ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value));
de_name.set_opt(&m.ident, de.map(syn::LitStr::value));
}
}
@@ -224,11 +231,11 @@ impl Container {
Meta(NameValue(ref m)) if m.ident == "rename_all" => {
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
match RenameRule::from_str(&s.value()) {
Ok(rename_rule) => rename_all.set(rename_rule),
Err(()) => cx.error(format!(
Ok(rename_rule) => rename_all.set(&m.ident, rename_rule),
Err(()) => cx.error_spanned_by(s, format!(
"unknown rename rule for #[serde(rename_all \
= {:?})]",
s.value()
s.value(),
)),
}
}
@@ -236,23 +243,33 @@ impl Container {
// Parse `#[serde(transparent)]`
Meta(Word(ref word)) if word == "transparent" => {
transparent.set_true();
transparent.set_true(word);
}
// Parse `#[serde(deny_unknown_fields)]`
Meta(Word(ref word)) if word == "deny_unknown_fields" => {
deny_unknown_fields.set_true();
deny_unknown_fields.set_true(word);
}
// Parse `#[serde(default)]`
Meta(Word(ref word)) if word == "default" => match item.data {
syn::Data::Struct(syn::DataStruct {
fields: syn::Fields::Named(_),
..
}) => {
default.set(Default::Default);
}
_ => cx.error(
syn::Data::Struct(syn::DataStruct { ref fields, .. }) => match *fields {
syn::Fields::Named(_) => {
default.set(word, Default::Default);
}
syn::Fields::Unnamed(_) | syn::Fields::Unit => cx.error_spanned_by(
fields,
"#[serde(default)] can only be used on structs \
with named fields",
)
},
syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx.error_spanned_by(
enum_token,
"#[serde(default)] can only be used on structs \
with named fields",
),
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => cx.error_spanned_by(
union_token,
"#[serde(default)] can only be used on structs \
with named fields",
),
@@ -262,13 +279,23 @@ impl Container {
Meta(NameValue(ref m)) if m.ident == "default" => {
if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
match item.data {
syn::Data::Struct(syn::DataStruct {
fields: syn::Fields::Named(_),
..
}) => {
default.set(Default::Path(path));
}
_ => cx.error(
syn::Data::Struct(syn::DataStruct { ref fields, .. }) => match *fields {
syn::Fields::Named(_) => {
default.set(&m.ident, Default::Path(path));
}
syn::Fields::Unnamed(_) | syn::Fields::Unit => cx.error_spanned_by(
fields,
"#[serde(default = \"...\")] can only be used \
on structs with named fields",
)
},
syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx.error_spanned_by(
enum_token,
"#[serde(default = \"...\")] can only be used \
on structs with named fields",
),
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => cx.error_spanned_by(
union_token,
"#[serde(default = \"...\")] can only be used \
on structs with named fields",
),
@@ -281,26 +308,35 @@ impl Container {
if let Ok(where_predicates) =
parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
{
ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates);
ser_bound.set(&m.ident, where_predicates.clone());
de_bound.set(&m.ident, where_predicates);
}
}
// Parse `#[serde(bound(serialize = "...", deserialize = "..."))]`
Meta(List(ref m)) if m.ident == "bound" => {
if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
ser_bound.set_opt(ser);
de_bound.set_opt(de);
ser_bound.set_opt(&m.ident, ser);
de_bound.set_opt(&m.ident, de);
}
}
// Parse `#[serde(untagged)]`
Meta(Word(ref word)) if word == "untagged" => match item.data {
syn::Data::Enum(_) => {
untagged.set_true();
untagged.set_true(word);
}
syn::Data::Struct(_) | syn::Data::Union(_) => {
cx.error("#[serde(untagged)] can only be used on enums")
syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => {
cx.error_spanned_by(
struct_token,
"#[serde(untagged)] can only be used on enums",
);
}
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => {
cx.error_spanned_by(
union_token,
"#[serde(untagged)] can only be used on enums",
);
}
},
@@ -309,11 +345,20 @@ impl Container {
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
match item.data {
syn::Data::Enum(_) => {
internal_tag.set(s.value());
}
syn::Data::Struct(_) | syn::Data::Union(_) => {
cx.error("#[serde(tag = \"...\")] can only be used on enums")
internal_tag.set(&m.ident, s.value());
}
syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => {
cx.error_spanned_by(
struct_token,
"#[serde(tag = \"...\")] can only be used on enums",
);
},
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => {
cx.error_spanned_by(
union_token,
"#[serde(tag = \"...\")] can only be used on enums",
);
},
}
}
}
@@ -323,12 +368,20 @@ impl Container {
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
match item.data {
syn::Data::Enum(_) => {
content.set(s.value());
content.set(&m.ident, s.value());
}
syn::Data::Struct(_) | syn::Data::Union(_) => cx.error(
"#[serde(content = \"...\")] can only be used on \
enums",
),
syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => {
cx.error_spanned_by(
struct_token,
"#[serde(content = \"...\")] can only be used on enums",
);
},
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => {
cx.error_spanned_by(
union_token,
"#[serde(content = \"...\")] can only be used on enums",
);
},
}
}
}
@@ -336,14 +389,14 @@ impl Container {
// Parse `#[serde(from = "Type")]
Meta(NameValue(ref m)) if m.ident == "from" => {
if let Ok(from_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) {
type_from.set_opt(Some(from_ty));
type_from.set_opt(&m.ident, Some(from_ty));
}
}
// Parse `#[serde(into = "Type")]
Meta(NameValue(ref m)) if m.ident == "into" => {
if let Ok(into_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) {
type_into.set_opt(Some(into_ty));
type_into.set_opt(&m.ident, Some(into_ty));
}
}
@@ -351,32 +404,32 @@ impl Container {
Meta(NameValue(ref m)) if m.ident == "remote" => {
if let Ok(path) = parse_lit_into_path(cx, &m.ident, &m.lit) {
if is_primitive_path(&path, "Self") {
remote.set(item.ident.clone().into());
remote.set(&m.ident, item.ident.clone().into());
} else {
remote.set(path);
remote.set(&m.ident, path);
}
}
}
// Parse `#[serde(field_identifier)]`
Meta(Word(ref word)) if word == "field_identifier" => {
field_identifier.set_true();
field_identifier.set_true(word);
}
// Parse `#[serde(variant_identifier)]`
Meta(Word(ref word)) if word == "variant_identifier" => {
variant_identifier.set_true();
variant_identifier.set_true(word);
}
Meta(ref meta_item) => {
cx.error(format!(
cx.error_spanned_by(meta_item.name(), format!(
"unknown serde container attribute `{}`",
meta_item.name()
));
}
Literal(_) => {
cx.error("unexpected literal in serde container attribute");
Literal(ref lit) => {
cx.error_spanned_by(lit, "unexpected literal in serde container attribute");
}
}
}
@@ -393,11 +446,11 @@ impl Container {
rename_all: rename_all.get().unwrap_or(RenameRule::None),
ser_bound: ser_bound.get(),
de_bound: de_bound.get(),
tag: decide_tag(cx, item, &untagged, internal_tag, content),
tag: decide_tag(cx, item, untagged, internal_tag, content),
type_from: type_from.get(),
type_into: type_into.get(),
remote: remote.get(),
identifier: decide_identifier(cx, item, &field_identifier, &variant_identifier),
identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
has_flatten: false,
}
}
@@ -462,14 +515,14 @@ impl Container {
fn decide_tag(
cx: &Ctxt,
item: &syn::DeriveInput,
untagged: &BoolAttr,
untagged: BoolAttr,
internal_tag: Attr<String>,
content: Attr<String>,
) -> EnumTag {
match (untagged.get(), internal_tag.get(), content.get()) {
(false, None, None) => EnumTag::External,
(true, None, None) => EnumTag::None,
(false, Some(tag), None) => {
match (untagged.0.get_with_tokens(), internal_tag.get_with_tokens(), content.get_with_tokens()) {
(None, None, None) => EnumTag::External,
(Some(_), None, None) => EnumTag::None,
(None, Some((_, tag)), None) => {
// Check that there are no tuple variants.
if let syn::Data::Enum(ref data) = item.data {
for variant in &data.variants {
@@ -477,7 +530,8 @@ fn decide_tag(
syn::Fields::Named(_) | syn::Fields::Unit => {}
syn::Fields::Unnamed(ref fields) => {
if fields.unnamed.len() != 1 {
cx.error(
cx.error_spanned_by(
variant,
"#[serde(tag = \"...\")] cannot be used with tuple \
variants",
);
@@ -489,24 +543,52 @@ fn decide_tag(
}
EnumTag::Internal { tag: tag }
}
(true, Some(_), None) => {
cx.error("enum cannot be both untagged and internally tagged");
(Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => {
cx.error_spanned_by(
untagged_tokens,
"enum cannot be both untagged and internally tagged",
);
cx.error_spanned_by(
tag_tokens,
"enum cannot be both untagged and internally tagged",
);
EnumTag::External // doesn't matter, will error
}
(false, None, Some(_)) => {
cx.error("#[serde(tag = \"...\", content = \"...\")] must be used together");
(None, None, Some((content_tokens, _))) => {
cx.error_spanned_by(
content_tokens,
"#[serde(tag = \"...\", content = \"...\")] must be used together",
);
EnumTag::External
}
(true, None, Some(_)) => {
cx.error("untagged enum cannot have #[serde(content = \"...\")]");
(Some((untagged_tokens, _)), None, Some((content_tokens, _))) => {
cx.error_spanned_by(
untagged_tokens,
"untagged enum cannot have #[serde(content = \"...\")]",
);
cx.error_spanned_by(
content_tokens,
"untagged enum cannot have #[serde(content = \"...\")]",
);
EnumTag::External
}
(false, Some(tag), Some(content)) => EnumTag::Adjacent {
(None, Some((_, tag)), Some((_, content))) => EnumTag::Adjacent {
tag: tag,
content: content,
},
(true, Some(_), Some(_)) => {
cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]");
(Some((untagged_tokens, _)), Some((tag_tokens, _)), Some((content_tokens, _))) => {
cx.error_spanned_by(
untagged_tokens,
"untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]",
);
cx.error_spanned_by(
tag_tokens,
"untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]",
);
cx.error_spanned_by(
content_tokens,
"untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]",
);
EnumTag::External
}
}
@@ -515,23 +597,50 @@ fn decide_tag(
fn decide_identifier(
cx: &Ctxt,
item: &syn::DeriveInput,
field_identifier: &BoolAttr,
variant_identifier: &BoolAttr,
field_identifier: BoolAttr,
variant_identifier: BoolAttr,
) -> Identifier {
match (&item.data, field_identifier.get(), variant_identifier.get()) {
(_, false, false) => Identifier::No,
(_, true, true) => {
cx.error("`field_identifier` and `variant_identifier` cannot both be set");
match (&item.data, field_identifier.0.get_with_tokens(), variant_identifier.0.get_with_tokens()) {
(_, None, None) => Identifier::No,
(_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => {
cx.error_spanned_by(
field_identifier_tokens,
"#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set",
);
cx.error_spanned_by(
variant_identifier_tokens,
"#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set",
);
Identifier::No
}
(&syn::Data::Enum(_), true, false) => Identifier::Field,
(&syn::Data::Enum(_), false, true) => Identifier::Variant,
(&syn::Data::Struct(_), true, false) | (&syn::Data::Union(_), true, false) => {
cx.error("`field_identifier` can only be used on an enum");
(&syn::Data::Enum(_), Some(_), None) => Identifier::Field,
(&syn::Data::Enum(_), None, Some(_)) => Identifier::Variant,
(&syn::Data::Struct(syn::DataStruct { ref struct_token, .. }), Some(_), None) => {
cx.error_spanned_by(
struct_token,
"#[serde(field_identifier)] can only be used on an enum",
);
Identifier::No
}
(&syn::Data::Struct(_), false, true) | (&syn::Data::Union(_), false, true) => {
cx.error("`variant_identifier` can only be used on an enum");
(&syn::Data::Union(syn::DataUnion { ref union_token, .. }), Some(_), None) => {
cx.error_spanned_by(
union_token,
"#[serde(field_identifier)] can only be used on an enum",
);
Identifier::No
}
(&syn::Data::Struct(syn::DataStruct { ref struct_token, .. }), None, Some(_)) => {
cx.error_spanned_by(
struct_token,
"#[serde(variant_identifier)] can only be used on an enum",
);
Identifier::No
}
(&syn::Data::Union(syn::DataUnion { ref union_token, .. }), None, Some(_)) => {
cx.error_spanned_by(
union_token,
"#[serde(variant_identifier)] can only be used on an enum",
);
Identifier::No
}
}
@@ -573,16 +682,16 @@ impl Variant {
// Parse `#[serde(rename = "foo")]`
Meta(NameValue(ref m)) if m.ident == "rename" => {
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
ser_name.set(s.value());
de_name.set(s.value());
ser_name.set(&m.ident, s.value());
de_name.set(&m.ident, s.value());
}
}
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
Meta(List(ref m)) if m.ident == "rename" => {
if let Ok((ser, de)) = get_renames(cx, &m.nested) {
ser_name.set_opt(ser.map(syn::LitStr::value));
de_name.set_opt(de.map(syn::LitStr::value));
ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value));
de_name.set_opt(&m.ident, de.map(syn::LitStr::value));
}
}
@@ -590,8 +699,8 @@ impl Variant {
Meta(NameValue(ref m)) if m.ident == "rename_all" => {
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
match RenameRule::from_str(&s.value()) {
Ok(rename_rule) => rename_all.set(rename_rule),
Err(()) => cx.error(format!(
Ok(rename_rule) => rename_all.set(&m.ident, rename_rule),
Err(()) => cx.error_spanned_by(s, format!(
"unknown rename rule for #[serde(rename_all \
= {:?})]",
s.value()
@@ -602,23 +711,23 @@ impl Variant {
// Parse `#[serde(skip)]`
Meta(Word(ref word)) if word == "skip" => {
skip_serializing.set_true();
skip_deserializing.set_true();
skip_serializing.set_true(word);
skip_deserializing.set_true(word);
}
// Parse `#[serde(skip_deserializing)]`
Meta(Word(ref word)) if word == "skip_deserializing" => {
skip_deserializing.set_true();
skip_deserializing.set_true(word);
}
// Parse `#[serde(skip_serializing)]`
Meta(Word(ref word)) if word == "skip_serializing" => {
skip_serializing.set_true();
skip_serializing.set_true(word);
}
// Parse `#[serde(other)]`
Meta(Word(ref word)) if word == "other" => {
other.set_true();
other.set_true(word);
}
// Parse `#[serde(bound = "T: SomeBound")]`
@@ -626,16 +735,16 @@ impl Variant {
if let Ok(where_predicates) =
parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
{
ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates);
ser_bound.set(&m.ident, where_predicates.clone());
de_bound.set(&m.ident, where_predicates);
}
}
// Parse `#[serde(bound(serialize = "...", deserialize = "..."))]`
Meta(List(ref m)) if m.ident == "bound" => {
if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
ser_bound.set_opt(ser);
de_bound.set_opt(de);
ser_bound.set_opt(&m.ident, ser);
de_bound.set_opt(&m.ident, de);
}
}
@@ -647,49 +756,55 @@ impl Variant {
.path
.segments
.push(Ident::new("serialize", Span::call_site()).into());
serialize_with.set(ser_path);
serialize_with.set(&m.ident, ser_path);
let mut de_path = path;
de_path
.path
.segments
.push(Ident::new("deserialize", Span::call_site()).into());
deserialize_with.set(de_path);
deserialize_with.set(&m.ident, de_path);
}
}
// Parse `#[serde(serialize_with = "...")]`
Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
serialize_with.set(path);
serialize_with.set(&m.ident, path);
}
}
// Parse `#[serde(deserialize_with = "...")]`
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
deserialize_with.set(path);
deserialize_with.set(&m.ident, path);
}
}
// Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]`
Meta(ref m) if m.name() == "borrow" => match variant.fields {
syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => {
borrow.set(m.clone());
borrow.set(m.name(), m.clone());
}
_ => {
cx.error("#[serde(borrow)] may only be used on newtype variants");
cx.error_spanned_by(
variant,
"#[serde(borrow)] may only be used on newtype variants",
);
}
},
Meta(ref meta_item) => {
cx.error(format!(
cx.error_spanned_by(meta_item.name(), format!(
"unknown serde variant attribute `{}`",
meta_item.name()
));
}
Literal(_) => {
cx.error("unexpected literal in serde variant attribute");
Literal(ref lit) => {
cx.error_spanned_by(
lit,
"unexpected literal in serde variant attribute",
);
}
}
}
@@ -845,65 +960,65 @@ impl Field {
// Parse `#[serde(rename = "foo")]`
Meta(NameValue(ref m)) if m.ident == "rename" => {
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
ser_name.set(s.value());
de_name.set(s.value());
ser_name.set(&m.ident, s.value());
de_name.set(&m.ident, s.value());
}
}
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
Meta(List(ref m)) if m.ident == "rename" => {
if let Ok((ser, de)) = get_renames(cx, &m.nested) {
ser_name.set_opt(ser.map(syn::LitStr::value));
de_name.set_opt(de.map(syn::LitStr::value));
ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value));
de_name.set_opt(&m.ident, de.map(syn::LitStr::value));
}
}
// Parse `#[serde(default)]`
Meta(Word(ref word)) if word == "default" => {
default.set(Default::Default);
default.set(word, Default::Default);
}
// Parse `#[serde(default = "...")]`
Meta(NameValue(ref m)) if m.ident == "default" => {
if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
default.set(Default::Path(path));
default.set(&m.ident, Default::Path(path));
}
}
// Parse `#[serde(skip_serializing)]`
Meta(Word(ref word)) if word == "skip_serializing" => {
skip_serializing.set_true();
skip_serializing.set_true(word);
}
// Parse `#[serde(skip_deserializing)]`
Meta(Word(ref word)) if word == "skip_deserializing" => {
skip_deserializing.set_true();
skip_deserializing.set_true(word);
}
// Parse `#[serde(skip)]`
Meta(Word(ref word)) if word == "skip" => {
skip_serializing.set_true();
skip_deserializing.set_true();
skip_serializing.set_true(word);
skip_deserializing.set_true(word);
}
// Parse `#[serde(skip_serializing_if = "...")]`
Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => {
if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
skip_serializing_if.set(path);
skip_serializing_if.set(&m.ident, path);
}
}
// Parse `#[serde(serialize_with = "...")]`
Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
serialize_with.set(path);
serialize_with.set(&m.ident, path);
}
}
// Parse `#[serde(deserialize_with = "...")]`
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
deserialize_with.set(path);
deserialize_with.set(&m.ident, path);
}
}
@@ -915,13 +1030,13 @@ impl Field {
.path
.segments
.push(Ident::new("serialize", Span::call_site()).into());
serialize_with.set(ser_path);
serialize_with.set(&m.ident, ser_path);
let mut de_path = path;
de_path
.path
.segments
.push(Ident::new("deserialize", Span::call_site()).into());
deserialize_with.set(de_path);
deserialize_with.set(&m.ident, de_path);
}
}
@@ -930,39 +1045,39 @@ impl Field {
if let Ok(where_predicates) =
parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
{
ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates);
ser_bound.set(&m.ident, where_predicates.clone());
de_bound.set(&m.ident, where_predicates);
}
}
// Parse `#[serde(bound(serialize = "...", deserialize = "..."))]`
Meta(List(ref m)) if m.ident == "bound" => {
if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
ser_bound.set_opt(ser);
de_bound.set_opt(de);
ser_bound.set_opt(&m.ident, ser);
de_bound.set_opt(&m.ident, de);
}
}
// Parse `#[serde(borrow)]`
Meta(Word(ref word)) if word == "borrow" => {
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) {
borrowed_lifetimes.set(borrowable);
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) {
borrowed_lifetimes.set(word, borrowable);
}
}
// Parse `#[serde(borrow = "'a + 'b")]`
Meta(NameValue(ref m)) if m.ident == "borrow" => {
if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, &m.ident, &m.lit) {
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) {
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) {
for lifetime in &lifetimes {
if !borrowable.contains(lifetime) {
cx.error(format!(
cx.error_spanned_by(field, format!(
"field `{}` does not have lifetime {}",
ident, lifetime
));
}
}
borrowed_lifetimes.set(lifetimes);
borrowed_lifetimes.set(&m.ident, lifetimes);
}
}
}
@@ -970,24 +1085,27 @@ impl Field {
// Parse `#[serde(getter = "...")]`
Meta(NameValue(ref m)) if m.ident == "getter" => {
if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
getter.set(path);
getter.set(&m.ident, path);
}
}
// Parse `#[serde(flatten)]`
Meta(Word(ref word)) if word == "flatten" => {
flatten.set_true();
flatten.set_true(word);
}
Meta(ref meta_item) => {
cx.error(format!(
cx.error_spanned_by(meta_item.name(), format!(
"unknown serde field attribute `{}`",
meta_item.name()
));
}
Literal(_) => {
cx.error("unexpected literal in serde field attribute");
Literal(ref lit) => {
cx.error_spanned_by(
lit,
"unexpected literal in serde field attribute",
);
}
}
}
@@ -1170,18 +1288,18 @@ where
match *meta {
Meta(NameValue(ref meta)) if meta.ident == "serialize" => {
if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) {
ser_meta.set(v);
ser_meta.set(&meta.ident, v);
}
}
Meta(NameValue(ref meta)) if meta.ident == "deserialize" => {
if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) {
de_meta.set(v);
de_meta.set(&meta.ident, v);
}
}
_ => {
cx.error(format!(
cx.error_spanned_by(meta, format!(
"malformed {0} attribute, expected `{0}(serialize = ..., \
deserialize = ...)`",
attr_name
@@ -1231,7 +1349,7 @@ fn get_lit_str<'a>(
if let syn::Lit::Str(ref lit) = *lit {
Ok(lit)
} else {
cx.error(format!(
cx.error_spanned_by(lit, format!(
"expected serde {} attribute to be a string: `{} = \"...\"`",
attr_name, meta_item_name
));
@@ -1242,7 +1360,10 @@ fn get_lit_str<'a>(
fn parse_lit_into_path(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result<syn::Path, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
parse_lit_str(string)
.map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value())))
.map_err(|_| cx.error_spanned_by(
lit,
format!("failed to parse path: {:?}", string.value()),
))
}
fn parse_lit_into_expr_path(
@@ -1252,7 +1373,10 @@ fn parse_lit_into_expr_path(
) -> Result<syn::ExprPath, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
parse_lit_str(string)
.map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value())))
.map_err(|_| cx.error_spanned_by(
lit,
format!("failed to parse path: {:?}", string.value()),
))
}
fn parse_lit_into_where(
@@ -1270,14 +1394,14 @@ fn parse_lit_into_where(
parse_lit_str::<syn::WhereClause>(&where_string)
.map(|wh| wh.predicates.into_iter().collect())
.map_err(|err| cx.error(err))
.map_err(|err| cx.error_spanned_by(lit, err))
}
fn parse_lit_into_ty(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result<syn::Type, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
parse_lit_str(string).map_err(|_| {
cx.error(format!(
cx.error_spanned_by(lit, format!(
"failed to parse type: {} = {:?}",
attr_name,
string.value()
@@ -1294,7 +1418,7 @@ fn parse_lit_into_lifetimes(
) -> Result<BTreeSet<syn::Lifetime>, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
if string.value().is_empty() {
cx.error("at least one lifetime must be borrowed");
cx.error_spanned_by(lit, "at least one lifetime must be borrowed");
return Err(());
}
@@ -1310,13 +1434,16 @@ fn parse_lit_into_lifetimes(
let mut set = BTreeSet::new();
for lifetime in lifetimes {
if !set.insert(lifetime.clone()) {
cx.error(format!("duplicate borrowed lifetime `{}`", lifetime));
cx.error_spanned_by(
lit,
format!("duplicate borrowed lifetime `{}`", lifetime),
);
}
}
return Ok(set);
}
cx.error(format!(
cx.error_spanned_by(lit, format!(
"failed to parse borrowed lifetimes: {:?}",
string.value()
));
@@ -1372,10 +1499,12 @@ fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
return false;
}
};
seg.ident == "Cow" && args.len() == 2 && match (&args[0], &args[1]) {
(&syn::GenericArgument::Lifetime(_), &syn::GenericArgument::Type(ref arg)) => elem(arg),
_ => false,
}
seg.ident == "Cow"
&& args.len() == 2
&& match (&args[0], &args[1]) {
(&syn::GenericArgument::Lifetime(_), &syn::GenericArgument::Type(ref arg)) => elem(arg),
_ => false,
}
}
fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
@@ -1397,10 +1526,12 @@ fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
return false;
}
};
seg.ident == "Option" && args.len() == 1 && match args[0] {
syn::GenericArgument::Type(ref arg) => elem(arg),
_ => false,
}
seg.ident == "Option"
&& args.len() == 1
&& match args[0] {
syn::GenericArgument::Type(ref arg) => elem(arg),
_ => false,
}
}
// Whether the type looks like it might be `&T` where elem="T". This can have
@@ -1465,12 +1596,15 @@ fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool {
fn borrowable_lifetimes(
cx: &Ctxt,
name: &str,
ty: &syn::Type,
field: &syn::Field,
) -> Result<BTreeSet<syn::Lifetime>, ()> {
let mut lifetimes = BTreeSet::new();
collect_lifetimes(ty, &mut lifetimes);
collect_lifetimes(&field.ty, &mut lifetimes);
if lifetimes.is_empty() {
cx.error(format!("field `{}` has no lifetimes to borrow", name));
cx.error_spanned_by(
field,
format!("field `{}` has no lifetimes to borrow", name),
);
Err(())
} else {
Ok(lifetimes)
@@ -1492,9 +1626,11 @@ fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
out.extend(ty.lifetime.iter().cloned());
collect_lifetimes(&ty.elem, out);
}
syn::Type::Tuple(ref ty) => for elem in &ty.elems {
collect_lifetimes(elem, out);
},
syn::Type::Tuple(ref ty) => {
for elem in &ty.elems {
collect_lifetimes(elem, out);
}
}
syn::Type::Path(ref ty) => {
if let Some(ref qself) = ty.qself {
collect_lifetimes(&qself.ty, out);
+5 -7
View File
@@ -1,10 +1,5 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! 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)]
@@ -14,6 +9,7 @@ use std::str::FromStr;
use self::RenameRule::*;
/// The different possible ways to change case of fields in a struct, or variants in an enum.
#[derive(PartialEq)]
pub enum RenameRule {
/// Don't apply a default rename rule.
@@ -40,6 +36,7 @@ pub enum RenameRule {
}
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 {
None | PascalCase => variant.to_owned(),
@@ -64,6 +61,7 @@ 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 {
None | LowerCase | SnakeCase => field.to_owned(),
+89 -45
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use internals::ast::{Container, Data, Field, Style};
use internals::attr::{EnumTag, Identifier};
use internals::{Ctxt, Derive};
@@ -29,12 +21,16 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
match cont.data {
Data::Enum(_) => {
if cont.data.has_getter() {
cx.error("#[serde(getter = \"...\")] is not allowed in an enum");
cx.error_spanned_by(
cont.original,
"#[serde(getter = \"...\")] is not allowed in an enum",
);
}
}
Data::Struct(_, _) => {
if cont.data.has_getter() && cont.attrs.remote().is_none() {
cx.error(
cx.error_spanned_by(
cont.original,
"#[serde(getter = \"...\")] can only be used in structs \
that have #[serde(remote = \"...\")]",
);
@@ -67,26 +63,35 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
}
match style {
Style::Tuple => {
cx.error("#[serde(flatten)] cannot be used on tuple structs");
cx.error_spanned_by(
field.original,
"#[serde(flatten)] cannot be used on tuple structs",
);
}
Style::Newtype => {
cx.error("#[serde(flatten)] cannot be used on newtype structs");
cx.error_spanned_by(
field.original,
"#[serde(flatten)] cannot be used on newtype structs",
);
}
_ => {}
}
if field.attrs.skip_serializing() {
cx.error(
"#[serde(flatten] can not be combined with \
cx.error_spanned_by(
field.original,
"#[serde(flatten)] can not be combined with \
#[serde(skip_serializing)]",
);
} else if field.attrs.skip_serializing_if().is_some() {
cx.error(
"#[serde(flatten] can not be combined with \
cx.error_spanned_by(
field.original,
"#[serde(flatten)] can not be combined with \
#[serde(skip_serializing_if = \"...\")]",
);
} else if field.attrs.skip_deserializing() {
cx.error(
"#[serde(flatten] can not be combined with \
cx.error_spanned_by(
field.original,
"#[serde(flatten)] can not be combined with \
#[serde(skip_deserializing)]",
);
}
@@ -115,24 +120,36 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
) {
// The `other` attribute may not be used in a variant_identifier.
(_, Identifier::Variant, true, _) => {
cx.error("#[serde(other)] may not be used on a variant_identifier");
cx.error_spanned_by(
variant.original,
"#[serde(other)] may not be used on a variant identifier",
);
}
// Variant with `other` attribute cannot appear in untagged enum
(_, Identifier::No, true, &EnumTag::None) => {
cx.error("#[serde(other)] cannot appear on untagged enum");
cx.error_spanned_by(
variant.original,
"#[serde(other)] cannot appear on untagged enum",
);
}
// Variant with `other` attribute must be the last one.
(Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => {
if i < variants.len() - 1 {
cx.error("#[serde(other)] must be the last variant");
cx.error_spanned_by(
variant.original,
"#[serde(other)] must be on the last variant",
);
}
}
// Variant with `other` attribute must be a unit variant.
(_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => {
cx.error("#[serde(other)] must be on a unit variant");
cx.error_spanned_by(
variant.original,
"#[serde(other)] must be on a unit variant",
);
}
// Any sort of variant is allowed if this is not an identifier.
@@ -144,16 +161,25 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
// The last field is allowed to be a newtype catch-all.
(Style::Newtype, Identifier::Field, false, _) => {
if i < variants.len() - 1 {
cx.error(format!("`{}` must be the last variant", variant.ident));
cx.error_spanned_by(
variant.original,
format!("`{}` must be the last variant", variant.ident),
);
}
}
(_, Identifier::Field, false, _) => {
cx.error("field_identifier may only contain unit variants");
cx.error_spanned_by(
variant.original,
"#[serde(field_identifier)] may only contain unit variants",
);
}
(_, Identifier::Variant, false, _) => {
cx.error("variant_identifier may only contain unit variants");
cx.error_spanned_by(
variant.original,
"#[serde(variant_identifier)] may only contain unit variants",
);
}
}
}
@@ -172,7 +198,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
for variant in variants.iter() {
if variant.attrs.serialize_with().is_some() {
if variant.attrs.skip_serializing() {
cx.error(format!(
cx.error_spanned_by(variant.original, format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \
#[serde(skip_serializing)]",
variant.ident
@@ -183,7 +209,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
let member = member_message(&field.member);
if field.attrs.skip_serializing() {
cx.error(format!(
cx.error_spanned_by(variant.original, format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing)]",
variant.ident, member
@@ -191,7 +217,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
}
if field.attrs.skip_serializing_if().is_some() {
cx.error(format!(
cx.error_spanned_by(variant.original, format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing_if)]",
variant.ident, member
@@ -202,7 +228,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
if variant.attrs.deserialize_with().is_some() {
if variant.attrs.skip_deserializing() {
cx.error(format!(
cx.error_spanned_by(variant.original, format!(
"variant `{}` cannot have both #[serde(deserialize_with)] and \
#[serde(skip_deserializing)]",
variant.ident
@@ -213,7 +239,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
if field.attrs.skip_deserializing() {
let member = member_message(&field.member);
cx.error(format!(
cx.error_spanned_by(variant.original, format!(
"variant `{}` cannot have both #[serde(deserialize_with)] \
and a field {} marked with #[serde(skip_deserializing)]",
variant.ident, member
@@ -239,10 +265,10 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
};
let diagnose_conflict = || {
let message = format!("variant field name `{}` conflicts with internal tag", tag);
cx.error(message);
};
let diagnose_conflict = || cx.error_spanned_by(
cont.original,
format!("variant field name `{}` conflicts with internal tag", tag),
);
for variant in variants {
match variant.style {
@@ -277,11 +303,10 @@ fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
};
if type_tag == content_tag {
let message = format!(
cx.error_spanned_by(cont.original, format!(
"enum tags `{}` for type and content conflict with each other",
type_tag
);
cx.error(message);
));
}
}
@@ -292,20 +317,32 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
}
if cont.attrs.type_from().is_some() {
cx.error("#[serde(transparent)] is not allowed with #[serde(from = \"...\")]");
cx.error_spanned_by(
cont.original,
"#[serde(transparent)] is not allowed with #[serde(from = \"...\")]",
);
}
if cont.attrs.type_into().is_some() {
cx.error("#[serde(transparent)] is not allowed with #[serde(into = \"...\")]");
cx.error_spanned_by(
cont.original,
"#[serde(transparent)] is not allowed with #[serde(into = \"...\")]",
);
}
let fields = match cont.data {
Data::Enum(_) => {
cx.error("#[serde(transparent)] is not allowed on an enum");
cx.error_spanned_by(
cont.original,
"#[serde(transparent)] is not allowed on an enum",
);
return;
}
Data::Struct(Style::Unit, _) => {
cx.error("#[serde(transparent)] is not allowed on a unit struct");
cx.error_spanned_by(
cont.original,
"#[serde(transparent)] is not allowed on a unit struct",
);
return;
}
Data::Struct(_, ref mut fields) => fields,
@@ -316,7 +353,8 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
for field in fields {
if allow_transparent(field, derive) {
if transparent_field.is_some() {
cx.error(
cx.error_spanned_by(
cont.original,
"#[serde(transparent)] requires struct to have at most one transparent field",
);
return;
@@ -329,10 +367,16 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
Some(transparent_field) => transparent_field.attrs.mark_transparent(),
None => match derive {
Derive::Serialize => {
cx.error("#[serde(transparent)] requires at least one field that is not skipped");
cx.error_spanned_by(
cont.original,
"#[serde(transparent)] requires at least one field that is not skipped",
);
}
Derive::Deserialize => {
cx.error("#[serde(transparent)] requires at least one field that is neither skipped nor has a default");
cx.error_spanned_by(
cont.original,
"#[serde(transparent)] requires at least one field that is neither skipped nor has a default",
);
}
},
}
@@ -341,7 +385,7 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
fn member_message(member: &Member) -> String {
match *member {
Member::Named(ref ident) => format!("`{}`", ident),
Member::Unnamed(ref i) => i.index.to_string(),
Member::Unnamed(ref i) => format!("#{}", i.index),
}
}
+23 -22
View File
@@ -1,48 +1,49 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
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.
///
/// Dropping this object will cause a panic. It must be consumed using `check`.
///
/// References can be shared since this type uses run-time exclusive mut checking.
#[derive(Default)]
pub struct Ctxt {
errors: RefCell<Option<Vec<String>>>,
// The contents will be set to `None` during checking. This is so that checking can be
// enforced.
errors: RefCell<Option<Vec<syn::Error>>>,
}
impl Ctxt {
/// Create a new context object.
///
/// This object contains no errors, but will still trigger a panic if it is not `check`ed.
pub fn new() -> Self {
Ctxt {
errors: RefCell::new(Some(Vec::new())),
}
}
pub fn error<T: Display>(&self, msg: T) {
/// Add an error to the context object with a tokenenizable object.
///
/// The object is used for spanning in error messages.
pub fn error_spanned_by<A: ToTokens, T: Display>(&self, obj: A, msg: T) {
self.errors
.borrow_mut()
.as_mut()
.unwrap()
.push(msg.to_string());
// Curb monomorphization from generating too many identical methods.
.push(syn::Error::new_spanned(obj.into_token_stream(), msg));
}
pub fn check(self) -> Result<(), String> {
let mut errors = self.errors.borrow_mut().take().unwrap();
/// Consume this object, producing a formatted error string if there are errors.
pub fn check(self) -> Result<(), Vec<syn::Error>> {
let errors = self.errors.borrow_mut().take().unwrap();
match errors.len() {
0 => Ok(()),
1 => Err(errors.pop().unwrap()),
n => {
let mut msg = format!("{} errors:", n);
for err in errors {
msg.push_str("\n\t# ");
msg.push_str(&err);
}
Err(msg)
}
_ => Err(errors),
}
}
}
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub mod ast;
pub mod attr;
+6 -15
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! This crate provides Serde's two derive macros.
//!
//! ```rust
@@ -22,7 +14,7 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.79")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.81")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
@@ -85,7 +77,7 @@ mod try;
pub fn derive_serialize(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
ser::expand_derive_serialize(&input)
.unwrap_or_else(compile_error)
.unwrap_or_else(to_compile_errors)
.into()
}
@@ -93,12 +85,11 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream {
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
de::expand_derive_deserialize(&input)
.unwrap_or_else(compile_error)
.unwrap_or_else(to_compile_errors)
.into()
}
fn compile_error(message: String) -> proc_macro2::TokenStream {
quote! {
compile_error!(#message);
}
fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
let compile_errors = errors.iter().map(syn::Error::to_compile_error);
quote!(#(#compile_errors)*)
}
+2 -1
View File
@@ -62,7 +62,8 @@ fn pretend_fields_used(cont: &Container) -> TokenStream {
Some(quote!(#type_ident::#variant_ident #pat))
}
_ => None,
}).collect::<Vec<_>>(),
})
.collect::<Vec<_>>(),
Data::Struct(Style::Struct, ref fields) => {
let pat = struct_pattern(fields);
vec![quote!(#type_ident #pat)]
+41 -26
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use proc_macro2::{Span, TokenStream};
use syn::spanned::Spanned;
use syn::{self, Ident, Index, Member};
@@ -17,9 +9,12 @@ use internals::{attr, Ctxt, Derive};
use pretend;
use try;
pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream, String> {
pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
let ctxt = Ctxt::new();
let cont = Container::from_ast(&ctxt, input, Derive::Serialize);
let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) {
Some(cont) => cont,
None => return Err(ctxt.check().unwrap_err()),
};
precondition(&ctxt, &cont);
try!(ctxt.check());
@@ -80,10 +75,10 @@ fn precondition(cx: &Ctxt, cont: &Container) {
match cont.attrs.identifier() {
attr::Identifier::No => {}
attr::Identifier::Field => {
cx.error("field identifiers cannot be serialized");
cx.error_spanned_by(cont.original, "field identifiers cannot be serialized");
}
attr::Identifier::Variant => {
cx.error("variant identifiers cannot be serialized");
cx.error_spanned_by(cont.original, "variant identifiers cannot be serialized");
}
}
}
@@ -208,7 +203,10 @@ fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
let path = match transparent_field.attrs.serialize_with() {
Some(path) => quote!(#path),
None => quote!(_serde::Serialize::serialize),
None => {
let span = transparent_field.original.span();
quote_spanned!(span=> _serde::Serialize::serialize)
},
};
quote_block! {
@@ -288,7 +286,8 @@ fn serialize_tuple_struct(
let field_expr = get_member(params, field, &Member::Unnamed(index));
quote!(if #path(#field_expr) { 0 } else { 1 })
}
}).fold(quote!(0), |sum, expr| quote!(#sum + #expr));
})
.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));
@@ -331,7 +330,8 @@ fn serialize_struct_as_struct(
let field_expr = get_member(params, field, &field.member);
quote!(if #path(#field_expr) { 0 } else { 1 })
}
}).fold(quote!(0), |sum, expr| quote!(#sum + #expr));
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
quote_block! {
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(__serializer, #type_name, #len));
@@ -365,7 +365,8 @@ fn serialize_struct_as_map(
let field_expr = get_member(params, field, &field.member);
quote!(if #path(#field_expr) { 0 } else { 1 })
}
}).fold(quote!(0), |sum, expr| quote!(#sum + #expr));
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
quote!(_serde::export::Some(#len))
};
@@ -386,7 +387,8 @@ fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Cont
.enumerate()
.map(|(variant_index, variant)| {
serialize_variant(params, variant, variant_index as u32, cattrs)
}).collect();
})
.collect();
quote_expr! {
match *#self_var {
@@ -509,8 +511,10 @@ fn serialize_externally_tagged_variant(
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
}
let span = field.original.span();
let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_variant);
quote_expr! {
_serde::Serializer::serialize_newtype_variant(
#func(
__serializer,
#type_name,
#variant_index,
@@ -583,8 +587,10 @@ fn serialize_internally_tagged_variant(
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
}
let span = field.original.span();
let func = quote_spanned!(span=> _serde::private::ser::serialize_tagged_newtype);
quote_expr! {
_serde::private::ser::serialize_tagged_newtype(
#func(
__serializer,
#enum_ident_str,
#variant_ident_str,
@@ -641,12 +647,14 @@ fn serialize_adjacently_tagged_variant(
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
}
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!(_serde::ser::SerializeStruct::serialize_field(
try!(#func(
&mut __struct, #content, #field_expr));
_serde::ser::SerializeStruct::end(__struct)
};
@@ -742,8 +750,10 @@ fn serialize_untagged_variant(
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
}
let span = field.original.span();
let func = quote_spanned!(span=> _serde::Serialize::serialize);
quote_expr! {
_serde::Serialize::serialize(#field_expr, __serializer)
#func(#field_expr, __serializer)
}
}
Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields),
@@ -790,7 +800,8 @@ fn serialize_tuple_variant(
let field_expr = Ident::new(&format!("__field{}", i), Span::call_site());
quote!(if #path(#field_expr) { 0 } else { 1 })
}
}).fold(quote!(0), |sum, expr| quote!(#sum + #expr));
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
match context {
TupleVariant::ExternallyTagged {
@@ -867,7 +878,8 @@ fn serialize_struct_variant<'a>(
Some(path) => quote!(if #path(#member) { 0 } else { 1 }),
None => quote!(1),
}
}).fold(quote!(0), |sum, expr| quote!(#sum + #expr));
})
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
match context {
StructVariant::ExternallyTagged {
@@ -1046,7 +1058,8 @@ fn serialize_tuple_struct_visitor(
None => ser,
Some(skip) => quote!(if !#skip { #ser }),
}
}).collect()
})
.collect()
}
fn serialize_struct_visitor(
@@ -1080,8 +1093,9 @@ fn serialize_struct_visitor(
let span = field.original.span();
let ser = if field.attrs.flatten() {
let func = quote_spanned!(span=> _serde::Serialize::serialize);
quote! {
try!(_serde::Serialize::serialize(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state)));
try!(#func(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state)));
}
} else {
let func = struct_trait.serialize_field(span);
@@ -1140,7 +1154,8 @@ fn wrap_serialize_variant_with(
}
};
quote!(#id)
}).collect();
})
.collect();
wrap_serialize_with(
params,
serialize_with,
+3 -4
View File
@@ -1,15 +1,14 @@
[package]
name = "serde_derive_internals"
version = "0.23.1" # remember to update html_root_url
version = "0.24.1" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "AST representation used by Serde derive macros. Unstable."
homepage = "https://serde.rs"
repository = "https://github.com/serde-rs/serde"
documentation = "https://docs.serde.rs/serde_derive_internals/"
documentation = "https://docs.rs/serde_derive_internals"
keywords = ["serde", "serialization"]
readme = "crates-io.md"
include = ["Cargo.toml", "lib.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
include = ["Cargo.toml", "lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT"]
[lib]
path = "lib.rs"
-1
View File
@@ -1 +0,0 @@
../README.md
-1
View File
@@ -1 +0,0 @@
../crates-io.md
+1 -9
View File
@@ -1,12 +1,4 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.23.1")]
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.24.1")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(
feature = "cargo-clippy",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_test"
version = "1.0.79" # remember to update html_root_url
version = "1.0.81" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations"
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use serde::{Deserialize, Serialize};
use de::Deserializer;
+1 -1
View File
@@ -200,7 +200,7 @@ macro_rules! impl_serializer {
$is_human_readable
}
forward_serialize_methods!{
forward_serialize_methods! {
serialize_bool bool,
serialize_i8 i8,
serialize_i16 i16,
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
use serde::de::{
self, Deserialize, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::error;
use std::fmt::{self, Display};
+1 -9
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! This crate provides a convenient concise way to write unit tests for
//! implementations of [`Serialize`] and [`Deserialize`].
//!
@@ -161,7 +153,7 @@
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.79")]
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.81")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use serde::{ser, Serialize};
use error::Error;
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::fmt::{self, Debug, Display};
#[derive(Copy, Clone, PartialEq, Debug)]
+1 -2
View File
@@ -9,11 +9,10 @@ unstable = ["serde/unstable", "compiletest_rs"]
[dev-dependencies]
fnv = "1.0"
proc-macro2 = "0.4"
rustc-serialize = "0.3.16"
serde = { path = "../serde", features = ["rc"] }
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
serde_test = { path = "../serde_test" }
[dependencies]
compiletest_rs = { version = "0.3", optional = true }
compiletest_rs = { version = "0.3", optional = true, features = ["stable"] }
-8
View File
@@ -1,11 +1,3 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(/*=============================================]
#![=== Serde test suite requires a nightly compiler. ===]
#![====================================================*/)]
+1 -9
View File
@@ -1,12 +1,4 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(lang_items, start, panic_handler)]
#![feature(lang_items, start)]
#![no_std]
extern crate libc;
@@ -1,19 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Test<'a> {
#[serde(borrow = "zzz")]
//~^^^ ERROR: failed to parse borrowed lifetimes: "zzz"
s: &'a str,
}
fn main() {}
@@ -1,19 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Test<'a> {
#[serde(borrow = "'a + 'a")]
//~^^^ ERROR: duplicate borrowed lifetime `'a`
s: &'a str,
}
fn main() {}
@@ -1,22 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Str<'a>(&'a str);
#[derive(Deserialize)]
enum Test<'a> {
#[serde(borrow)]
//~^^^ ERROR: duplicate serde attribute `borrow`
S(#[serde(borrow)] Str<'a>),
}
fn main() {}
@@ -1,19 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Test<'a> {
#[serde(borrow = "")]
//~^^^ ERROR: at least one lifetime must be borrowed
s: &'a str,
}
fn main() {}
@@ -1,19 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Test {
#[serde(borrow)]
//~^^^ ERROR: field `s` has no lifetimes to borrow
s: String,
}
fn main() {}
@@ -1,22 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Str<'a>(&'a str);
#[derive(Deserialize)]
enum Test<'a> {
#[serde(borrow)]
//~^^^ ERROR: #[serde(borrow)] may only be used on newtype variants
S { s: Str<'a> },
}
fn main() {}
@@ -1,19 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Test<'a> {
#[serde(borrow = "'b")]
//~^^^ ERROR: field `s` does not have lifetime 'b
s: &'a str,
}
fn main() {}
@@ -1,20 +0,0 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
#[serde(tag = "conflict", content = "conflict")]
//~^^ ERROR: enum tags `conflict` for type and content conflict with each other
enum E {
A,
B,
}
fn main() {}
@@ -1,16 +0,0 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct Foo(#[serde(flatten)] HashMap<String, String>);
//~^^ ERROR: #[serde(flatten)] cannot be used on newtype structs
fn main() {}
@@ -1,24 +0,0 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct Foo {
#[serde(flatten, skip_deserializing)]
//~^^^ ERROR: #[serde(flatten] can not be combined with #[serde(skip_deserializing)]
other: Other,
}
#[derive(Deserialize)]
struct Other {
x: u32,
}
fn main() {}
@@ -1,24 +0,0 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct Foo {
#[serde(flatten, skip_serializing_if = "Option::is_none")]
//~^^^ ERROR: #[serde(flatten] can not be combined with #[serde(skip_serializing_if = "...")]
other: Option<Other>,
}
#[derive(Serialize)]
struct Other {
x: u32,
}
fn main() {}
@@ -1,24 +0,0 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct Foo {
#[serde(flatten, skip_serializing)]
//~^^^ ERROR: #[serde(flatten] can not be combined with #[serde(skip_serializing)]
other: Other,
}
#[derive(Serialize)]
struct Other {
x: u32,
}
fn main() {}
@@ -1,16 +0,0 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct Foo(u32, #[serde(flatten)] HashMap<String, String>);
//~^^ ERROR: #[serde(flatten)] cannot be used on tuple structs
fn main() {}
@@ -1,22 +0,0 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
#[serde(tag = "conflict")]
//~^^ ERROR: variant field name `conflict` conflicts with internal tag
enum E {
A {
#[serde(rename = "conflict")]
x: (),
},
}
fn main() {}
@@ -1,17 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
#[serde(default)]
//~^^ ERROR: #[serde(default)] can only be used on structs
enum E {
S { f: u8 },
}
@@ -1,17 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
#[serde(default)]
//~^^ ERROR: #[serde(default)] can only be used on structs
struct T(u8, u8);
fn main() {}
@@ -1,19 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct S {
#[serde(rename = "x", serialize = "y")]
//~^^^ ERROR: unknown serde field attribute `serialize`
x: (),
}
fn main() {}
@@ -1,20 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct S {
#[serde(rename = "x")]
#[serde(rename(deserialize = "y"))]
//~^^^^ ERROR: duplicate serde attribute `rename`
x: (),
}
fn main() {}
@@ -1,19 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct S {
#[serde(rename(serialize = "x"), rename(serialize = "y"))]
//~^^^ ERROR: duplicate serde attribute `rename`
x: (),
}
fn main() {}
@@ -1,20 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct S {
#[serde(rename(serialize = "x"))]
#[serde(rename = "y")]
//~^^^^ ERROR: duplicate serde attribute `rename`
x: (),
}
fn main() {}
@@ -1,19 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct S {
#[serde(rename(serialize = "x", serialize = "y"))]
//~^^^ ERROR: duplicate serde attribute `rename`
x: (),
}
fn main() {}
@@ -1,20 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct S {
#[serde(rename(serialize = "x"))]
#[serde(rename(serialize = "y"))]
//~^^^^ ERROR: duplicate serde attribute `rename`
x: (),
}
fn main() {}
@@ -1,19 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct S {
#[serde(with = "w", serialize_with = "s")]
//~^^^ ERROR: duplicate serde attribute `serialize_with`
x: (),
}
fn main() {}
@@ -1,19 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
#[serde(tag = "type")]
//~^^ ERROR: #[serde(tag = "...")] cannot be used with tuple variants
enum E {
Tuple(u8, u8),
}
fn main() {}
@@ -1,17 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
#[serde(tag = "type")]
//~^^ ERROR: #[serde(tag = "...")] can only be used on enums
struct S;
fn main() {}
@@ -1,21 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
#[serde(untagged)]
#[serde(tag = "type")]
//~^^^ ERROR: enum cannot be both untagged and internally tagged
enum E {
A(u8),
B(String),
}
fn main() {}
@@ -1,17 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
#[serde(untagged)]
//~^^ ERROR: #[serde(untagged)] can only be used on enums
struct S;
fn main() {}
@@ -1,20 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
#[serde(field_identifier, variant_identifier)]
//~^^ ERROR: `field_identifier` and `variant_identifier` cannot both be set
enum F {
A,
B,
}
fn main() {}
@@ -1,17 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
#[serde(field_identifier)]
//~^^ ERROR: `field_identifier` can only be used on an enum
struct S;
fn main() {}
@@ -1,20 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
#[serde(field_identifier)]
enum F {
A,
B(u8, u8),
//~^^^^^ ERROR: field_identifier may only contain unit variants
}
fn main() {}
@@ -1,21 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
#[serde(field_identifier)]
enum F {
A,
Other(String),
//~^^^^^ ERROR: `Other` must be the last variant
B,
}
fn main() {}
@@ -1,21 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
#[serde(field_identifier)]
enum F {
A,
#[serde(other)]
//~^^^^^ ERROR: #[serde(other)] must be on a unit variant
Other(u8, u8),
}
fn main() {}
@@ -1,22 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
#[serde(field_identifier)]
enum F {
A,
#[serde(other)]
//~^^^^^ ERROR: #[serde(other)] must be the last variant
Other,
B,
}
fn main() {}
@@ -1,20 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
#[serde(field_identifier)]
//~^^ ERROR: field identifiers cannot be serialized
enum F {
A,
B,
}
fn main() {}
@@ -1,17 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
#[serde(variant_identifier)]
//~^^ ERROR: `variant_identifier` can only be used on an enum
struct S;
fn main() {}
@@ -1,20 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
#[serde(variant_identifier)]
enum F {
A,
B(u8, u8),
//~^^^^^ ERROR: variant_identifier may only contain unit variants
}
fn main() {}
@@ -1,16 +0,0 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct S<'de> {
//~^^ ERROR: cannot deserialize when there is a lifetime parameter called 'de
s: &'de str,
}
@@ -1,17 +0,0 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
struct S {
string: String,
slice: [u8],
//~^^^^ ERROR: cannot deserialize a dynamically sized struct
}
@@ -1,26 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
mod remote {
pub struct S {
a: u8,
}
}
#[derive(Serialize)]
#[serde(remote = "remote::S")]
struct S {
#[serde(getter = "~~~")]
//~^^^^ ERROR: failed to parse path: "~~~"
a: u8,
}
fn main() {}
@@ -1,25 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
mod remote {
pub struct S {
a: u8,
}
}
#[derive(Serialize)]
#[serde(remote = "~~~")]
//~^^ ERROR: failed to parse path: "~~~"
struct S {
a: u8,
}
fn main() {}
@@ -1,28 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
mod remote {
pub enum E {
A { a: u8 },
}
}
#[derive(Serialize)]
#[serde(remote = "remote::E")]
pub enum E {
A {
#[serde(getter = "get_a")]
//~^^^^^ ERROR: #[serde(getter = "...")] is not allowed in an enum
a: u8,
},
}
fn main() {}
@@ -1,26 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
mod remote {
pub struct S {
pub a: u8,
pub b: u8,
}
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::S")]
struct S {
a: u8,
//~^^^ ERROR: missing field `b` in initializer of `remote::S`
}
fn main() {}
@@ -1,25 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
struct S {
#[serde(getter = "S::get")]
//~^^^ ERROR: #[serde(getter = "...")] can only be used in structs that have #[serde(remote = "...")]
a: u8,
}
impl S {
fn get(&self) -> u8 {
self.a
}
}
fn main() {}
@@ -1,26 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
mod remote {
pub struct S {
pub a: u8,
}
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::S")]
struct S {
b: u8,
//~^ ERROR: struct `remote::S` has no field named `b`
//~^^ ERROR: no field `b` on type `&remote::S`
}
fn main() {}
@@ -1,22 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
mod remote {
pub struct S(pub u16);
}
#[derive(Deserialize)]
#[serde(remote = "remote::S")]
struct S(u8);
//~^^^ ERROR: mismatched types
//~^^^^ expected u16, found u8
fn main() {}
@@ -1,33 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
mod remote {
pub struct S {
a: u8,
}
impl S {
pub fn get(&self) -> u16 {
self.a as u16
}
}
}
#[derive(Serialize)]
#[serde(remote = "remote::S")]
struct S {
#[serde(getter = "remote::S::get")]
//~^^^^ ERROR: mismatched types
a: u8,
//~^^^^^^ expected u8, found u16
}
fn main() {}
@@ -1,26 +0,0 @@
// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
mod remote {
pub struct S {
pub a: u16,
}
}
#[derive(Serialize)]
#[serde(remote = "remote::S")]
struct S {
a: u8,
//~^^^^ ERROR: mismatched types
//~^^^^^ expected u8, found u16
}
fn main() {}
@@ -1,20 +0,0 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
#[serde(transparent)]
//~^^ ERROR: #[serde(transparent)] requires struct to have at most one transparent field
struct S {
a: u8,
b: u8,
}
fn main() {}
@@ -1,22 +0,0 @@
// Copyright 2018 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[macro_use]
extern crate serde_derive;
#[derive(Deserialize)]
#[serde(transparent)]
//~^^ ERROR: #[serde(transparent)] requires at least one field that is neither skipped nor has a default
struct S {
#[serde(skip)]
a: u8,
#[serde(default)]
b: u8,
}
fn main() {}

Some files were not shown because too many files have changed in this diff Show More