mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-23 03:38:00 +00:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ab68132b1f | |||
| e70bbd9dde | |||
| d5e5c520ac | |||
| 2a557a1e36 | |||
| ab0848f780 | |||
| 2b1303f59c | |||
| 7f9ba155cb | |||
| a4e0c2f055 | |||
| 3bbf70575b | |||
| ad680cbd44 | |||
| ff0cfb1f1f | |||
| 9b08915a18 | |||
| 501aa3ee1d | |||
| eebf0f8db8 | |||
| a7e4911ddb | |||
| eb08f037f5 | |||
| aa03fd5d1a | |||
| e198afb0c1 | |||
| bc8de251cf | |||
| 99e8686189 | |||
| 826f656e28 | |||
| ab7c003b64 | |||
| 422191fcb0 | |||
| 4ba748c902 | |||
| 14ed6f2dab | |||
| 30606a43aa | |||
| 9be3d32016 | |||
| 5daf1b89a1 | |||
| f8f5d0ca2f | |||
| 57873cce28 | |||
| 4ed0362c8e | |||
| 4cecaf8d02 | |||
| 50c696aabe | |||
| 2f58a20bc6 | |||
| 030459a040 | |||
| e9b530a000 | |||
| ea1a729088 | |||
| 857dcea774 | |||
| b98a9a8f9b | |||
| 3b135431fd | |||
| 945d12c0b4 | |||
| e36915300f | |||
| 85c05d301a | |||
| c2474bf6ee | |||
| a52f436788 | |||
| ad3335e5d6 | |||
| 40c670e625 | |||
| 0dccbb1f11 |
+52
-31
@@ -1,45 +1,66 @@
|
||||
# Contributing to Serde
|
||||
|
||||
Serde welcomes contribution from everyone. Here are the guidelines if you are
|
||||
thinking of helping us:
|
||||
Serde welcomes contribution from everyone in the form of suggestions, bug
|
||||
reports, pull requests, and feedback. This document gives some guidance if you
|
||||
are thinking of helping us.
|
||||
|
||||
## Contributions
|
||||
Please reach out here in a GitHub issue or in the #serde IRC channel on
|
||||
[`irc.mozilla.org`] if we can do anything to help you contribute.
|
||||
|
||||
Contributions to Serde or its dependencies should be made in the form of GitHub
|
||||
pull requests. Each pull request will be reviewed by a core contributor
|
||||
(someone with permission to land patches) and either landed in the main tree or
|
||||
given feedback for changes that would be required. All contributions should
|
||||
follow this format, even those from core contributors.
|
||||
[`irc.mozilla.org`]: https://wiki.mozilla.org/IRC
|
||||
|
||||
Should you wish to work on an issue, please claim it first by commenting on
|
||||
the GitHub issue that you want to work on it. This is to prevent duplicated
|
||||
efforts from contributors on the same issue.
|
||||
## Submitting bug reports and feature requests
|
||||
|
||||
## Pull Request Checklist
|
||||
Serde development is spread across lots of repositories, but this serde-rs/serde
|
||||
repository is always a safe choice for opening any issues related to Serde.
|
||||
|
||||
- Branch from the master branch and, if needed, rebase to the current master
|
||||
branch before submitting your pull request. If it doesn't merge cleanly with
|
||||
master you may be asked to rebase your changes.
|
||||
When reporting a bug or asking for help, please include enough details so that
|
||||
the people helping you can reproduce the behavior you are seeing. For some tips
|
||||
on how to approach this, read about how to produce a [Minimal, Complete, and
|
||||
Verifiable example].
|
||||
|
||||
- Commits should be as small as possible, while ensuring that each commit is
|
||||
correct independently (i.e., each commit should compile and pass tests).
|
||||
[Minimal, Complete, and Verifiable example]: https://stackoverflow.com/help/mcve
|
||||
|
||||
- If your patch is not getting reviewed or you need a specific person to review
|
||||
it, you can @-reply a reviewer asking for a review in the pull request or a
|
||||
comment, or you can ask for a review in `#serde` on `irc.mozilla.org`.
|
||||
When making a feature request, please make it clear what problem you intend to
|
||||
solve with the feature, any ideas for how Serde could support solving that
|
||||
problem, any possible alternatives, and any disadvantages.
|
||||
|
||||
- Add tests relevant to the fixed bug or new feature.
|
||||
## Running the test suite
|
||||
|
||||
We encourage you to check that the test suite passes locally before submitting a
|
||||
pull request with your changes. If anything does not pass, typically it will be
|
||||
easier to iterate and fix it locally than waiting for the CI servers to run
|
||||
tests for you.
|
||||
|
||||
##### In the [`serde`] directory
|
||||
|
||||
```sh
|
||||
# Test all the example code in Serde documentation
|
||||
cargo test
|
||||
```
|
||||
|
||||
##### In the [`test_suite/deps`] directory
|
||||
|
||||
```sh
|
||||
# This is a prerequisite for running the full test suite
|
||||
cargo clean && cargo update && cargo build
|
||||
```
|
||||
|
||||
##### In the [`test_suite`] directory
|
||||
|
||||
```sh
|
||||
# Run the full test suite, including tests of unstable functionality
|
||||
cargo test --features unstable
|
||||
```
|
||||
|
||||
[`serde`]: https://github.com/serde-rs/serde/tree/master/serde
|
||||
[`test_suite/deps`]: https://github.com/serde-rs/serde/tree/master/test_suite/deps
|
||||
[`test_suite`]: https://github.com/serde-rs/serde/tree/master/test_suite
|
||||
|
||||
## Conduct
|
||||
|
||||
In all Serde-related forums, we follow the [Rust Code of
|
||||
Conduct](https://www.rust-lang.org/conduct.html). For escalation or moderation
|
||||
issues, please contact Erick (erick.tryzelaar@gmail.com) instead of the Rust
|
||||
moderation team.
|
||||
In all Serde-related forums, we follow the [Rust Code of Conduct]. For
|
||||
escalation or moderation issues please contact Erick (erick.tryzelaar@gmail.com)
|
||||
instead of the Rust moderation team.
|
||||
|
||||
## Communication
|
||||
|
||||
Beyond opening tickets on the
|
||||
[serde-rs/serde](https://github.com/serde-rs/serde) project, Serde contributors
|
||||
frequent the `#serde` channel on
|
||||
[`irc.mozilla.org`](https://wiki.mozilla.org/IRC).
|
||||
[Rust Code of Conduct]: https://www.rust-lang.org/conduct.html
|
||||
|
||||
@@ -20,9 +20,30 @@ You may be looking for:
|
||||
|
||||
## Serde in action
|
||||
|
||||
<a href="http://play.integer32.com/?gist=9003c5b88c1f4989941925d7190c6eec" target="_blank">
|
||||
<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png">
|
||||
</a>
|
||||
<details>
|
||||
<summary>
|
||||
Click to show Cargo.toml.
|
||||
<a href="http://play.integer32.com/?gist=9003c5b88c1f4989941925d7190c6eec" target="_blank">Run this code in the playground.</a>
|
||||
</summary>
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
|
||||
# The core APIs, including the Serialize and Deserialize traits. Always
|
||||
# required when using Serde.
|
||||
serde = "1.0"
|
||||
|
||||
# Support for #[derive(Serialize, Deserialize)]. Required if you want Serde
|
||||
# to work for structs and enums defined in your crate.
|
||||
serde_derive = "1.0"
|
||||
|
||||
# Each data format lives in its own crate; the sample code below uses JSON
|
||||
# but you may be using a different one.
|
||||
serde_json = "1.0"
|
||||
```
|
||||
|
||||
</details>
|
||||
<p></p>
|
||||
|
||||
```rust
|
||||
#[macro_use]
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "1.0.14" # remember to update html_root_url
|
||||
version = "1.0.18" # 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"
|
||||
|
||||
+198
-74
@@ -869,37 +869,206 @@ map_impl!(
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
macro_rules! parse_impl {
|
||||
($ty:ty) => {
|
||||
macro_rules! parse_ip_impl {
|
||||
($ty:ty; $size: expr) => {
|
||||
impl<'de> Deserialize<'de> for $ty {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = try!(String::deserialize(deserializer));
|
||||
s.parse().map_err(Error::custom)
|
||||
if deserializer.is_human_readable() {
|
||||
let s = try!(String::deserialize(deserializer));
|
||||
s.parse().map_err(Error::custom)
|
||||
} else {
|
||||
<[u8; $size]>::deserialize(deserializer).map(<$ty>::from)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::IpAddr);
|
||||
macro_rules! variant_identifier {
|
||||
(
|
||||
$name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* )
|
||||
$expecting_message: expr,
|
||||
$variants_name: ident
|
||||
) => {
|
||||
enum $name_kind {
|
||||
$( $variant ),*
|
||||
}
|
||||
|
||||
static $variants_name: &'static [&'static str] = &[ $( stringify!($variant) ),*];
|
||||
|
||||
impl<'de> Deserialize<'de> for $name_kind {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct KindVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for KindVisitor {
|
||||
type Value = $name_kind;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str($expecting_message)
|
||||
}
|
||||
|
||||
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
$(
|
||||
$index => Ok($name_kind :: $variant),
|
||||
)*
|
||||
_ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
$(
|
||||
stringify!($variant) => Ok($name_kind :: $variant),
|
||||
)*
|
||||
_ => Err(Error::unknown_variant(value, $variants_name)),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
$(
|
||||
$bytes => Ok($name_kind :: $variant),
|
||||
)*
|
||||
_ => {
|
||||
match str::from_utf8(value) {
|
||||
Ok(value) => Err(Error::unknown_variant(value, $variants_name)),
|
||||
Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_identifier(KindVisitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::Ipv4Addr);
|
||||
macro_rules! deserialize_enum {
|
||||
(
|
||||
$name: ident $name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* )
|
||||
$expecting_message: expr,
|
||||
$deserializer: expr
|
||||
) => {
|
||||
variant_identifier!{
|
||||
$name_kind ( $($variant; $bytes; $index),* )
|
||||
$expecting_message,
|
||||
VARIANTS
|
||||
}
|
||||
|
||||
struct EnumVisitor;
|
||||
impl<'de> Visitor<'de> for EnumVisitor {
|
||||
type Value = $name;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(concat!("a ", stringify!($name)))
|
||||
}
|
||||
|
||||
|
||||
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: EnumAccess<'de>,
|
||||
{
|
||||
match try!(data.variant()) {
|
||||
$(
|
||||
($name_kind :: $variant, v) => v.newtype_variant().map($name :: $variant),
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
$deserializer.deserialize_enum(stringify!($name), VARIANTS, EnumVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::Ipv6Addr);
|
||||
impl<'de> Deserialize<'de> for net::IpAddr {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
let s = try!(String::deserialize(deserializer));
|
||||
s.parse().map_err(Error::custom)
|
||||
} else {
|
||||
use lib::net::IpAddr;
|
||||
deserialize_enum!{
|
||||
IpAddr IpAddrKind (V4; b"V4"; 0, V6; b"V6"; 1)
|
||||
"`V4` or `V6`",
|
||||
deserializer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::SocketAddr);
|
||||
parse_ip_impl!(net::Ipv4Addr; 4);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::SocketAddrV4);
|
||||
parse_ip_impl!(net::Ipv6Addr; 16);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_impl!(net::SocketAddrV6);
|
||||
macro_rules! parse_socket_impl {
|
||||
($ty:ty, $new: expr) => {
|
||||
impl<'de> Deserialize<'de> for $ty {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
let s = try!(String::deserialize(deserializer));
|
||||
s.parse().map_err(Error::custom)
|
||||
} else {
|
||||
<(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de> Deserialize<'de> for net::SocketAddr {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
let s = try!(String::deserialize(deserializer));
|
||||
s.parse().map_err(Error::custom)
|
||||
} else {
|
||||
use lib::net::SocketAddr;
|
||||
deserialize_enum!{
|
||||
SocketAddr SocketAddrKind (V4; b"V4"; 0, V6; b"V6"; 1)
|
||||
"`V4` or `V6`",
|
||||
deserializer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_socket_impl!(net::SocketAddrV4, net::SocketAddrV4::new);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
parse_socket_impl!(net::SocketAddrV6, |ip, port| net::SocketAddrV6::new(ip, port, 0, 0));
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -984,70 +1153,10 @@ impl<'de> Deserialize<'de> for PathBuf {
|
||||
// #[derive(Deserialize)]
|
||||
// #[serde(variant_identifier)]
|
||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||
enum OsStringKind {
|
||||
Unix,
|
||||
Windows,
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||
static OSSTR_VARIANTS: &'static [&'static str] = &["Unix", "Windows"];
|
||||
|
||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||
impl<'de> Deserialize<'de> for OsStringKind {
|
||||
fn deserialize<D>(deserializer: D) -> Result<OsStringKind, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct KindVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for KindVisitor {
|
||||
type Value = OsStringKind;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("`Unix` or `Windows`")
|
||||
}
|
||||
|
||||
fn visit_u32<E>(self, value: u32) -> Result<OsStringKind, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
0 => Ok(OsStringKind::Unix),
|
||||
1 => Ok(OsStringKind::Windows),
|
||||
_ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<OsStringKind, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
"Unix" => Ok(OsStringKind::Unix),
|
||||
"Windows" => Ok(OsStringKind::Windows),
|
||||
_ => Err(Error::unknown_variant(value, OSSTR_VARIANTS)),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, value: &[u8]) -> Result<OsStringKind, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
b"Unix" => Ok(OsStringKind::Unix),
|
||||
b"Windows" => Ok(OsStringKind::Windows),
|
||||
_ => {
|
||||
match str::from_utf8(value) {
|
||||
Ok(value) => Err(Error::unknown_variant(value, OSSTR_VARIANTS)),
|
||||
Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_identifier(KindVisitor)
|
||||
}
|
||||
variant_identifier!{
|
||||
OsStringKind (Unix; b"Unix"; 0, Windows; b"Windows"; 1)
|
||||
"`Unix` or `Windows`",
|
||||
OSSTR_VARIANTS
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||
@@ -1716,3 +1825,18 @@ where
|
||||
deserializer.deserialize_enum("Result", VARIANTS, ResultVisitor(PhantomData))
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de, T> Deserialize<'de> for Wrapping<T>
|
||||
where
|
||||
T: Deserialize<'de>
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Wrapping<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Deserialize::deserialize(deserializer).map(Wrapping)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1011,6 +1011,74 @@ pub trait Deserializer<'de>: Sized {
|
||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>;
|
||||
|
||||
/// Determine whether `Deserialize` implementations should expect to
|
||||
/// deserialize their human-readable form.
|
||||
///
|
||||
/// Some types have a human-readable form that may be somewhat expensive to
|
||||
/// construct, as well as a binary form that is compact and efficient.
|
||||
/// Generally text-based formats like JSON and YAML will prefer to use the
|
||||
/// human-readable one and binary formats like Bincode will prefer the
|
||||
/// compact one.
|
||||
///
|
||||
/// ```
|
||||
/// # use std::ops::Add;
|
||||
/// # use std::str::FromStr;
|
||||
/// #
|
||||
/// # struct Timestamp;
|
||||
/// #
|
||||
/// # impl Timestamp {
|
||||
/// # const EPOCH: Timestamp = Timestamp;
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl FromStr for Timestamp {
|
||||
/// # type Err = String;
|
||||
/// # fn from_str(_: &str) -> Result<Self, Self::Err> {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// # struct Duration;
|
||||
/// #
|
||||
/// # impl Duration {
|
||||
/// # fn seconds(_: u64) -> Self { unimplemented!() }
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl Add<Duration> for Timestamp {
|
||||
/// # type Output = Timestamp;
|
||||
/// # fn add(self, _: Duration) -> Self::Output {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// use serde::de::{self, Deserialize, Deserializer};
|
||||
///
|
||||
/// impl<'de> Deserialize<'de> for Timestamp {
|
||||
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
/// where D: Deserializer<'de>
|
||||
/// {
|
||||
/// if deserializer.is_human_readable() {
|
||||
/// // Deserialize from a human-readable string like "2015-05-15T17:01:00Z".
|
||||
/// let s = String::deserialize(deserializer)?;
|
||||
/// Timestamp::from_str(&s).map_err(de::Error::custom)
|
||||
/// } else {
|
||||
/// // Deserialize from a compact binary representation, seconds since
|
||||
/// // the Unix epoch.
|
||||
/// let n = u64::deserialize(deserializer)?;
|
||||
/// Ok(Timestamp::EPOCH + Duration::seconds(n))
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The default implementation of this method returns `true`. Data formats
|
||||
/// may override this to `false` to request a compact form for types that
|
||||
/// support one. Note that modifying this method to change a format from
|
||||
/// human-readable to compact or vice versa should be regarded as a breaking
|
||||
/// change, as a value serialized in human-readable mode is not required to
|
||||
/// deserialize from the same data in compact mode.
|
||||
#[inline]
|
||||
fn is_human_readable(&self) -> bool { true }
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -733,7 +733,7 @@ where
|
||||
T: IntoDeserializer<'de, E>,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = SeqDeserializer<<Vec<T> as IntoIterator>::IntoIter, E>;
|
||||
type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
SeqDeserializer::new(self.into_iter())
|
||||
@@ -746,7 +746,7 @@ where
|
||||
T: IntoDeserializer<'de, E> + Eq + Ord,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = SeqDeserializer<<BTreeSet<T> as IntoIterator>::IntoIter, E>;
|
||||
type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
SeqDeserializer::new(self.into_iter())
|
||||
@@ -754,12 +754,13 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de, T, E> IntoDeserializer<'de, E> for HashSet<T>
|
||||
impl<'de, T, S, E> IntoDeserializer<'de, E> for HashSet<T, S>
|
||||
where
|
||||
T: IntoDeserializer<'de, E> + Eq + Hash,
|
||||
S: BuildHasher,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = SeqDeserializer<<HashSet<T> as IntoIterator>::IntoIter, E>;
|
||||
type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
SeqDeserializer::new(self.into_iter())
|
||||
@@ -1152,7 +1153,7 @@ where
|
||||
V: IntoDeserializer<'de, E>,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = MapDeserializer<'de, <BTreeMap<K, V> as IntoIterator>::IntoIter, E>;
|
||||
type Deserializer = MapDeserializer<'de, <Self as IntoIterator>::IntoIter, E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
MapDeserializer::new(self.into_iter())
|
||||
@@ -1160,13 +1161,14 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de, K, V, E> IntoDeserializer<'de, E> for HashMap<K, V>
|
||||
impl<'de, K, V, S, E> IntoDeserializer<'de, E> for HashMap<K, V, S>
|
||||
where
|
||||
K: IntoDeserializer<'de, E> + Eq + Hash,
|
||||
V: IntoDeserializer<'de, E>,
|
||||
S: BuildHasher,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = MapDeserializer<'de, <HashMap<K, V> as IntoIterator>::IntoIter, E>;
|
||||
type Deserializer = MapDeserializer<'de, <Self as IntoIterator>::IntoIter, E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
MapDeserializer::new(self.into_iter())
|
||||
|
||||
+4
-1
@@ -79,7 +79,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Serde types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.14")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.18")]
|
||||
|
||||
// Support using Serde without the standard library!
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
@@ -95,6 +95,7 @@
|
||||
// Whitelisted clippy lints
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(
|
||||
cast_lossless,
|
||||
const_static_lifetime,
|
||||
doc_markdown,
|
||||
linkedlist,
|
||||
type_complexity,
|
||||
@@ -207,6 +208,8 @@ mod lib {
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::io::Write;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::num::Wrapping;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::path::{Path, PathBuf};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
+33
-9
@@ -834,26 +834,43 @@ mod content {
|
||||
type Value = TaggedContent<'de, T>;
|
||||
|
||||
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.write_str("any value")
|
||||
fmt.write_str("internally tagged enum")
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
|
||||
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
|
||||
where
|
||||
V: MapAccess<'de>,
|
||||
S: SeqAccess<'de>,
|
||||
{
|
||||
let tag = match try!(seq.next_element()) {
|
||||
Some(tag) => tag,
|
||||
None => {
|
||||
return Err(de::Error::missing_field(self.tag_name));
|
||||
}
|
||||
};
|
||||
let rest = de::value::SeqAccessDeserializer::new(seq);
|
||||
Ok(TaggedContent {
|
||||
tag: tag,
|
||||
content: try!(Content::deserialize(rest)),
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let mut tag = None;
|
||||
let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint()));
|
||||
let mut vec = Vec::with_capacity(size_hint::cautious(map.size_hint()));
|
||||
while let Some(k) =
|
||||
try!(visitor.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
|
||||
try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
|
||||
match k {
|
||||
TagOrContent::Tag => {
|
||||
if tag.is_some() {
|
||||
return Err(de::Error::duplicate_field(self.tag_name));
|
||||
}
|
||||
tag = Some(try!(visitor.next_value()));
|
||||
tag = Some(try!(map.next_value()));
|
||||
}
|
||||
TagOrContent::Content(k) => {
|
||||
let v = try!(visitor.next_value());
|
||||
let v = try!(map.next_value());
|
||||
vec.push((k, v));
|
||||
}
|
||||
}
|
||||
@@ -1802,9 +1819,16 @@ mod content {
|
||||
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name)
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, _: V) -> Result<(), V::Error>
|
||||
fn visit_seq<S>(self, _: S) -> Result<(), S::Error>
|
||||
where
|
||||
V: MapAccess<'de>,
|
||||
S: SeqAccess<'de>,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_map<M>(self, _: M) -> Result<(), M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+68
-18
@@ -506,9 +506,18 @@ impl Serialize for net::IpAddr {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
net::IpAddr::V4(ref a) => a.serialize(serializer),
|
||||
net::IpAddr::V6(ref a) => a.serialize(serializer),
|
||||
if serializer.is_human_readable() {
|
||||
match *self {
|
||||
net::IpAddr::V4(ref a) => a.serialize(serializer),
|
||||
net::IpAddr::V6(ref a) => a.serialize(serializer),
|
||||
}
|
||||
} else {
|
||||
match *self {
|
||||
net::IpAddr::V4(ref a) =>
|
||||
serializer.serialize_newtype_variant("IpAddr", 0, "V4", a),
|
||||
net::IpAddr::V6(ref a) =>
|
||||
serializer.serialize_newtype_variant("IpAddr", 1, "V6", a),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -519,9 +528,13 @@ impl Serialize for net::Ipv4Addr {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
/// "101.102.103.104".len()
|
||||
const MAX_LEN: usize = 15;
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
if serializer.is_human_readable() {
|
||||
const MAX_LEN: usize = 15;
|
||||
debug_assert_eq!(MAX_LEN, "101.102.103.104".len());
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
} else {
|
||||
self.octets().serialize(serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,9 +544,13 @@ impl Serialize for net::Ipv6Addr {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
/// "1000:1002:1003:1004:1005:1006:1007:1008".len()
|
||||
const MAX_LEN: usize = 39;
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
if serializer.is_human_readable() {
|
||||
const MAX_LEN: usize = 39;
|
||||
debug_assert_eq!(MAX_LEN, "1001:1002:1003:1004:1005:1006:1007:1008".len());
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
} else {
|
||||
self.octets().serialize(serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,9 +560,18 @@ impl Serialize for net::SocketAddr {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
net::SocketAddr::V4(ref addr) => addr.serialize(serializer),
|
||||
net::SocketAddr::V6(ref addr) => addr.serialize(serializer),
|
||||
if serializer.is_human_readable() {
|
||||
match *self {
|
||||
net::SocketAddr::V4(ref addr) => addr.serialize(serializer),
|
||||
net::SocketAddr::V6(ref addr) => addr.serialize(serializer),
|
||||
}
|
||||
} else {
|
||||
match *self {
|
||||
net::SocketAddr::V4(ref addr) =>
|
||||
serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr),
|
||||
net::SocketAddr::V6(ref addr) =>
|
||||
serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -556,9 +582,13 @@ impl Serialize for net::SocketAddrV4 {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
/// "101.102.103.104:65000".len()
|
||||
const MAX_LEN: usize = 21;
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
if serializer.is_human_readable() {
|
||||
const MAX_LEN: usize = 21;
|
||||
debug_assert_eq!(MAX_LEN, "101.102.103.104:65000".len());
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
} else {
|
||||
(self.ip(), self.port()).serialize(serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,9 +598,13 @@ impl Serialize for net::SocketAddrV6 {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
/// "[1000:1002:1003:1004:1005:1006:1007:1008]:65000".len()
|
||||
const MAX_LEN: usize = 47;
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
if serializer.is_human_readable() {
|
||||
const MAX_LEN: usize = 47;
|
||||
debug_assert_eq!(MAX_LEN, "[1001:1002:1003:1004:1005:1006:1007:1008]:65000".len());
|
||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||
} else {
|
||||
(self.ip(), self.port()).serialize(serializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,3 +664,19 @@ impl Serialize for OsString {
|
||||
self.as_os_str().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T> Serialize for Wrapping<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1363,6 +1363,56 @@ pub trait Serializer: Sized {
|
||||
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Display;
|
||||
|
||||
/// Determine whether `Serialize` implementations should serialize in
|
||||
/// human-readable form.
|
||||
///
|
||||
/// Some types have a human-readable form that may be somewhat expensive to
|
||||
/// construct, as well as a binary form that is compact and efficient.
|
||||
/// Generally text-based formats like JSON and YAML will prefer to use the
|
||||
/// human-readable one and binary formats like Bincode will prefer the
|
||||
/// compact one.
|
||||
///
|
||||
/// ```
|
||||
/// # use std::fmt::{self, Display};
|
||||
/// #
|
||||
/// # struct Timestamp;
|
||||
/// #
|
||||
/// # impl Timestamp {
|
||||
/// # fn seconds_since_epoch(&self) -> u64 { unimplemented!() }
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl Display for Timestamp {
|
||||
/// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// use serde::{Serialize, Serializer};
|
||||
///
|
||||
/// impl Serialize for Timestamp {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
/// where S: Serializer
|
||||
/// {
|
||||
/// if serializer.is_human_readable() {
|
||||
/// // Serialize to a human-readable string "2015-05-15T17:01:00Z".
|
||||
/// self.to_string().serialize(serializer)
|
||||
/// } else {
|
||||
/// // Serialize to a compact binary representation.
|
||||
/// self.seconds_since_epoch().serialize(serializer)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The default implementation of this method returns `true`. Data formats
|
||||
/// may override this to `false` to request a compact form for types that
|
||||
/// support one. Note that modifying this method to change a format from
|
||||
/// human-readable to compact or vice versa should be regarded as a breaking
|
||||
/// change, as a value serialized in human-readable mode is not required to
|
||||
/// deserialize from the same data in compact mode.
|
||||
#[inline]
|
||||
fn is_human_readable(&self) -> bool { true }
|
||||
}
|
||||
|
||||
/// Returned from `Serializer::serialize_seq`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "1.0.14" # remember to update html_root_url
|
||||
version = "1.0.18" # 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)]"
|
||||
@@ -22,3 +22,6 @@ proc-macro = true
|
||||
quote = "0.3.8"
|
||||
serde_derive_internals = { version = "=0.16.0", default-features = false, path = "../serde_derive_internals" }
|
||||
syn = { version = "0.11", features = ["visit"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0", path = "../serde" }
|
||||
|
||||
+42
-18
@@ -203,7 +203,9 @@ impl BorrowedLifetimes {
|
||||
fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes {
|
||||
let mut lifetimes = BTreeSet::new();
|
||||
for field in cont.body.all_fields() {
|
||||
lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned());
|
||||
if !field.attrs.skip_deserializing() {
|
||||
lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned());
|
||||
}
|
||||
}
|
||||
if lifetimes.iter().any(|b| b.ident == "'static") {
|
||||
BorrowedLifetimes::Static
|
||||
@@ -222,7 +224,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
||||
if fields.iter().any(|field| field.ident.is_none()) {
|
||||
panic!("struct has unnamed fields");
|
||||
}
|
||||
deserialize_struct(None, params, fields, &cont.attrs, None)
|
||||
deserialize_struct(None, params, fields, &cont.attrs, None, Untagged::No)
|
||||
}
|
||||
Body::Struct(Style::Tuple, ref fields) |
|
||||
Body::Struct(Style::Newtype, ref fields) => {
|
||||
@@ -488,15 +490,20 @@ fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &F
|
||||
}
|
||||
}
|
||||
|
||||
enum Untagged {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
fn deserialize_struct(
|
||||
variant_ident: Option<&syn::Ident>,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Option<Tokens>,
|
||||
untagged: Untagged,
|
||||
) -> Fragment {
|
||||
let is_enum = variant_ident.is_some();
|
||||
let is_untagged = deserializer.is_some();
|
||||
|
||||
let this = ¶ms.this;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,);
|
||||
@@ -559,18 +566,19 @@ fn deserialize_struct(
|
||||
quote!(mut __seq)
|
||||
};
|
||||
|
||||
let visit_seq = if is_untagged {
|
||||
// untagged struct variants do not get a visit_seq method
|
||||
None
|
||||
} else {
|
||||
Some(quote! {
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::SeqAccess<#delife>
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
})
|
||||
// untagged struct variants do not get a visit_seq method
|
||||
let visit_seq = match untagged {
|
||||
Untagged::Yes => None,
|
||||
Untagged::No => {
|
||||
Some(quote! {
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error>
|
||||
where __A: _serde::de::SeqAccess<#delife>
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
@@ -1148,7 +1156,7 @@ fn deserialize_externally_tagged_variant(
|
||||
deserialize_tuple(Some(variant_ident), params, &variant.fields, cattrs, None)
|
||||
}
|
||||
Style::Struct => {
|
||||
deserialize_struct(Some(variant_ident), params, &variant.fields, cattrs, None)
|
||||
deserialize_struct(Some(variant_ident), params, &variant.fields, cattrs, None, Untagged::No)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1175,8 +1183,23 @@ fn deserialize_internally_tagged_variant(
|
||||
_serde::export::Ok(#this::#variant_ident)
|
||||
}
|
||||
}
|
||||
Style::Newtype | Style::Struct => {
|
||||
deserialize_untagged_variant(params, variant, cattrs, deserializer)
|
||||
Style::Newtype => {
|
||||
deserialize_untagged_newtype_variant(
|
||||
variant_ident,
|
||||
params,
|
||||
&variant.fields[0],
|
||||
deserializer,
|
||||
)
|
||||
}
|
||||
Style::Struct => {
|
||||
deserialize_struct(
|
||||
Some(variant_ident),
|
||||
params,
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
Some(deserializer),
|
||||
Untagged::No,
|
||||
)
|
||||
}
|
||||
Style::Tuple => unreachable!("checked in serde_derive_internals"),
|
||||
}
|
||||
@@ -1238,6 +1261,7 @@ fn deserialize_untagged_variant(
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
Some(deserializer),
|
||||
Untagged::Yes,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,21 @@
|
||||
|
||||
//! This crate provides Serde's two derive macros.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! ```rust
|
||||
//! # #[macro_use]
|
||||
//! # extern crate serde_derive;
|
||||
//! #
|
||||
//! #[derive(Serialize, Deserialize)]
|
||||
//! # struct S;
|
||||
//! #
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
//!
|
||||
//! Please refer to [https://serde.rs/derive.html] for how to set this up.
|
||||
//!
|
||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.14")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.18")]
|
||||
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_test"
|
||||
version = "1.0.14" # remember to update html_root_url
|
||||
version = "1.0.18" # 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"
|
||||
|
||||
@@ -47,8 +47,20 @@ pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
||||
where
|
||||
T: Serialize + Deserialize<'de> + PartialEq + Debug,
|
||||
{
|
||||
assert_ser_tokens(value, tokens);
|
||||
assert_de_tokens(value, tokens);
|
||||
assert_tokens_readable(value, tokens, None);
|
||||
}
|
||||
|
||||
// Not public API
|
||||
#[doc(hidden)]
|
||||
/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
|
||||
///
|
||||
/// See: `assert_tokens`
|
||||
pub fn assert_tokens_readable<'de, T>(value: &T, tokens: &'de [Token], human_readable: Option<bool>)
|
||||
where
|
||||
T: Serialize + Deserialize<'de> + PartialEq + Debug,
|
||||
{
|
||||
assert_ser_tokens_readable(value, tokens, human_readable);
|
||||
assert_de_tokens_readable(value, tokens, human_readable);
|
||||
}
|
||||
|
||||
/// Asserts that `value` serializes to the given `tokens`.
|
||||
@@ -84,7 +96,19 @@ pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let mut ser = Serializer::new(tokens);
|
||||
assert_ser_tokens_readable(value, tokens, None)
|
||||
}
|
||||
|
||||
// Not public API
|
||||
#[doc(hidden)]
|
||||
/// Asserts that `value` serializes to the given `tokens`.
|
||||
///
|
||||
/// See: `assert_ser_tokens`
|
||||
pub fn assert_ser_tokens_readable<T>(value: &T, tokens: &[Token], human_readable: Option<bool>)
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let mut ser = Serializer::readable(tokens, human_readable);
|
||||
match value.serialize(&mut ser) {
|
||||
Ok(_) => {}
|
||||
Err(err) => panic!("value failed to serialize: {}", err),
|
||||
@@ -183,7 +207,16 @@ pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
||||
where
|
||||
T: Deserialize<'de> + PartialEq + Debug,
|
||||
{
|
||||
let mut de = Deserializer::new(tokens);
|
||||
assert_de_tokens_readable(value, tokens, None)
|
||||
}
|
||||
|
||||
// Not public API
|
||||
#[doc(hidden)]
|
||||
pub fn assert_de_tokens_readable<'de, T>(value: &T, tokens: &'de [Token], human_readable: Option<bool>)
|
||||
where
|
||||
T: Deserialize<'de> + PartialEq + Debug,
|
||||
{
|
||||
let mut de = Deserializer::readable(tokens, human_readable);
|
||||
match T::deserialize(&mut de) {
|
||||
Ok(v) => assert_eq!(v, *value),
|
||||
Err(e) => panic!("tokens failed to deserialize: {}", e),
|
||||
|
||||
+20
-1
@@ -16,6 +16,7 @@ use token::Token;
|
||||
#[derive(Debug)]
|
||||
pub struct Deserializer<'de> {
|
||||
tokens: &'de [Token],
|
||||
is_human_readable: Option<bool>,
|
||||
}
|
||||
|
||||
macro_rules! assert_next_token {
|
||||
@@ -48,7 +49,13 @@ macro_rules! end_of_tokens {
|
||||
|
||||
impl<'de> Deserializer<'de> {
|
||||
pub fn new(tokens: &'de [Token]) -> Self {
|
||||
Deserializer { tokens: tokens }
|
||||
Deserializer::readable(tokens, None)
|
||||
}
|
||||
|
||||
// Not public API
|
||||
#[doc(hidden)]
|
||||
pub fn readable(tokens: &'de [Token], is_human_readable: Option<bool>) -> Self {
|
||||
Deserializer { tokens: tokens, is_human_readable: is_human_readable }
|
||||
}
|
||||
|
||||
fn peek_token_opt(&self) -> Option<Token> {
|
||||
@@ -364,6 +371,18 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
_ => self.deserialize_any(visitor),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_human_readable(&self) -> bool {
|
||||
match self.is_human_readable {
|
||||
Some(is) => is,
|
||||
None => {
|
||||
panic!("There is no serde_test API currently for testing types \
|
||||
that have different human-readable and compact \
|
||||
representation. See \
|
||||
https://github.com/serde-rs/serde/issues/1065.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.14")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.18")]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
@@ -168,8 +168,12 @@ mod token;
|
||||
mod assert;
|
||||
|
||||
pub use token::Token;
|
||||
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error, assert_de_tokens,
|
||||
assert_de_tokens_error};
|
||||
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error,
|
||||
assert_de_tokens, assert_de_tokens_error};
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
pub use assert::{assert_tokens_readable, assert_de_tokens_readable, assert_ser_tokens_readable};
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
|
||||
+20
-1
@@ -15,12 +15,19 @@ use token::Token;
|
||||
#[derive(Debug)]
|
||||
pub struct Serializer<'a> {
|
||||
tokens: &'a [Token],
|
||||
is_human_readable: Option<bool>,
|
||||
}
|
||||
|
||||
impl<'a> Serializer<'a> {
|
||||
/// Creates the serializer.
|
||||
pub fn new(tokens: &'a [Token]) -> Self {
|
||||
Serializer { tokens: tokens }
|
||||
Serializer::readable(tokens, None)
|
||||
}
|
||||
|
||||
// Not public API
|
||||
#[doc(hidden)]
|
||||
pub fn readable(tokens: &'a [Token], is_human_readable: Option<bool>) -> Self {
|
||||
Serializer { tokens: tokens, is_human_readable: is_human_readable }
|
||||
}
|
||||
|
||||
/// Pulls the next token off of the serializer, ignoring it.
|
||||
@@ -282,6 +289,18 @@ impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> {
|
||||
Ok(Variant { ser: self, end: Token::StructVariantEnd })
|
||||
}
|
||||
}
|
||||
|
||||
fn is_human_readable(&self) -> bool {
|
||||
match self.is_human_readable {
|
||||
Some(is) => is,
|
||||
None => {
|
||||
panic!("There is no serde_test API currently for testing types \
|
||||
that have different human-readable and compact \
|
||||
representation. See \
|
||||
https://github.com/serde-rs/serde/issues/1065.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Variant<'s, 'a: 's> {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// 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,3 +1,11 @@
|
||||
// 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, compiler_builtins_lib)]
|
||||
#![no_std]
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ mod remote {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)] //~ ERROR: missing field `b` in initializer of `remote::S`
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "remote::S")]
|
||||
struct S {
|
||||
a: u8, //~^^^ ERROR: missing field `b` in initializer of `remote::S`
|
||||
|
||||
@@ -19,8 +19,7 @@ mod remote {
|
||||
#[serde(remote = "remote::S")]
|
||||
struct S {
|
||||
//~^^^ ERROR: struct `remote::S` has no field named `b`
|
||||
//~^^^^ ERROR: struct `remote::S` has no field named `b`
|
||||
b: u8, //~^^^^^ ERROR: no field `b` on type `&remote::S`
|
||||
b: u8, //~^^^^ ERROR: no field `b` on type `&remote::S`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -73,3 +73,29 @@ macro_rules! hashmap {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! seq_impl {
|
||||
(seq $first:expr,) => {
|
||||
seq_impl!(seq $first)
|
||||
};
|
||||
($first:expr,) => {
|
||||
seq_impl!($first)
|
||||
};
|
||||
(seq $first:expr) => {
|
||||
$first.into_iter()
|
||||
};
|
||||
($first:expr) => {
|
||||
Some($first).into_iter()
|
||||
};
|
||||
(seq $first:expr , $( $elem: tt)*) => {
|
||||
$first.into_iter().chain(seq!( $($elem)* ))
|
||||
};
|
||||
($first:expr , $($elem: tt)*) => {
|
||||
Some($first).into_iter().chain(seq!( $($elem)* ))
|
||||
}
|
||||
}
|
||||
macro_rules! seq {
|
||||
($($tt: tt)*) => {
|
||||
seq_impl!($($tt)*).collect::<Vec<_>>()
|
||||
};
|
||||
}
|
||||
|
||||
+135
-37
@@ -17,6 +17,7 @@ use std::default::Default;
|
||||
use std::ffi::{CString, OsString};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::num::Wrapping;
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
use std::ffi::CStr;
|
||||
@@ -28,7 +29,7 @@ extern crate fnv;
|
||||
use self::fnv::FnvHasher;
|
||||
|
||||
extern crate serde_test;
|
||||
use self::serde_test::{Token, assert_de_tokens, assert_de_tokens_error};
|
||||
use self::serde_test::{Token, assert_de_tokens, assert_de_tokens_error, assert_de_tokens_readable};
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
@@ -109,25 +110,37 @@ enum EnumSkipAll {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! declare_test {
|
||||
($name:ident { $($value:expr => $tokens:expr,)+ }) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
$(
|
||||
// Test ser/de roundtripping
|
||||
assert_de_tokens(&$value, $tokens);
|
||||
|
||||
// Test that the tokens are ignorable
|
||||
assert_de_tokens_ignore($tokens);
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! declare_tests {
|
||||
(
|
||||
readable: $readable:tt
|
||||
$($name:ident { $($value:expr => $tokens:expr,)+ })+
|
||||
) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $name() {
|
||||
$(
|
||||
// Test ser/de roundtripping
|
||||
assert_de_tokens_readable(&$value, $tokens, Some($readable));
|
||||
|
||||
// Test that the tokens are ignorable
|
||||
assert_de_tokens_ignore($tokens);
|
||||
)+
|
||||
}
|
||||
)+
|
||||
};
|
||||
|
||||
($($name:ident { $($value:expr => $tokens:expr,)+ })+) => {
|
||||
$(
|
||||
declare_test!($name { $($value => $tokens,)+ });
|
||||
#[test]
|
||||
fn $name() {
|
||||
$(
|
||||
// Test ser/de roundtripping
|
||||
assert_de_tokens(&$value, $tokens);
|
||||
|
||||
// Test that the tokens are ignorable
|
||||
assert_de_tokens_ignore($tokens);
|
||||
)+
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
@@ -725,17 +738,6 @@ declare_tests! {
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_net_ipv4addr {
|
||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_ipv6addr {
|
||||
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
|
||||
}
|
||||
test_net_socketaddr {
|
||||
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
|
||||
}
|
||||
test_path {
|
||||
Path::new("/usr/local/lib") => &[
|
||||
Token::BorrowedStr("/usr/local/lib"),
|
||||
@@ -761,6 +763,105 @@ declare_tests! {
|
||||
Token::Bool(true),
|
||||
],
|
||||
}
|
||||
test_wrapping {
|
||||
Wrapping(1usize) => &[
|
||||
Token::U32(1),
|
||||
],
|
||||
Wrapping(1usize) => &[
|
||||
Token::U64(1),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
declare_tests! {
|
||||
readable: true
|
||||
test_net_ipv4addr_readable {
|
||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_ipv6addr_readable {
|
||||
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
|
||||
}
|
||||
test_net_ipaddr_readable {
|
||||
"1.2.3.4".parse::<net::IpAddr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_socketaddr_readable {
|
||||
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
|
||||
}
|
||||
}
|
||||
|
||||
declare_tests! {
|
||||
readable: false
|
||||
test_net_ipv4addr_compact {
|
||||
net::Ipv4Addr::from(*b"1234") => &seq![
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd
|
||||
],
|
||||
}
|
||||
test_net_ipv6addr_compact {
|
||||
net::Ipv6Addr::from(*b"1234567890123456") => &seq![
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd
|
||||
],
|
||||
}
|
||||
test_net_ipaddr_compact {
|
||||
net::IpAddr::from(*b"1234") => &seq![
|
||||
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd
|
||||
],
|
||||
}
|
||||
test_net_socketaddr_compact {
|
||||
net::SocketAddr::from((*b"1234567890123456", 1234)) => &seq![
|
||||
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
|
||||
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd
|
||||
],
|
||||
net::SocketAddr::from((*b"1234", 1234)) => &seq![
|
||||
Token::NewtypeVariant { name: "SocketAddr", variant: "V4" },
|
||||
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd
|
||||
],
|
||||
net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234) => &seq![
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd
|
||||
],
|
||||
net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0) => &seq![
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
@@ -836,15 +937,6 @@ fn test_cstr() {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
#[test]
|
||||
fn test_net_ipaddr() {
|
||||
assert_de_tokens(
|
||||
&"1.2.3.4".parse::<net::IpAddr>().unwrap(),
|
||||
&[Token::Str("1.2.3.4")],
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
#[test]
|
||||
fn test_cstr_internal_null() {
|
||||
@@ -1086,4 +1178,10 @@ declare_error_tests! {
|
||||
],
|
||||
"invalid type: sequence, expected unit struct UnitStruct",
|
||||
}
|
||||
test_wrapping_overflow<Wrapping<u16>> {
|
||||
&[
|
||||
Token::U32(65_536),
|
||||
],
|
||||
"invalid value: integer `65536`, expected u16",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
|
||||
#![cfg_attr(feature = "unstable", feature(non_ascii_idents))]
|
||||
|
||||
// Clippy false positive
|
||||
// https://github.com/Manishearth/rust-clippy/issues/292
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
@@ -515,6 +511,14 @@ fn test_gen() {
|
||||
Tuple(&'a str, &'static str),
|
||||
Newtype(&'static str),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct SkippedStaticStr {
|
||||
#[serde(skip_deserializing)]
|
||||
skipped: &'static str,
|
||||
other: isize,
|
||||
}
|
||||
assert::<SkippedStaticStr>();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -591,11 +591,10 @@ fn test_internally_tagged_enum() {
|
||||
#[serde(tag = "type")]
|
||||
enum InternallyTagged {
|
||||
A { a: u8 },
|
||||
B { b: u8 },
|
||||
C,
|
||||
D(BTreeMap<String, String>),
|
||||
E(Newtype),
|
||||
F(Struct),
|
||||
B,
|
||||
C(BTreeMap<String, String>),
|
||||
D(Newtype),
|
||||
E(Struct),
|
||||
}
|
||||
|
||||
assert_tokens(
|
||||
@@ -613,35 +612,62 @@ fn test_internally_tagged_enum() {
|
||||
],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::B { b: 2 },
|
||||
assert_de_tokens(
|
||||
&InternallyTagged::A { a: 1 },
|
||||
&[
|
||||
Token::Struct { name: "InternallyTagged", len: 2 },
|
||||
|
||||
Token::Str("type"),
|
||||
Token::Str("B"),
|
||||
|
||||
Token::Str("b"),
|
||||
Token::U8(2),
|
||||
|
||||
Token::StructEnd,
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::Str("A"),
|
||||
Token::U8(1),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::C,
|
||||
&InternallyTagged::B,
|
||||
&[
|
||||
Token::Struct { name: "InternallyTagged", len: 1 },
|
||||
|
||||
Token::Str("type"),
|
||||
Token::Str("C"),
|
||||
Token::Str("B"),
|
||||
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&InternallyTagged::B,
|
||||
&[
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::Str("B"),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::D(BTreeMap::new()),
|
||||
&InternallyTagged::C(BTreeMap::new()),
|
||||
&[
|
||||
Token::Map { len: Some(1) },
|
||||
|
||||
Token::Str("type"),
|
||||
Token::Str("C"),
|
||||
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<InternallyTagged>(
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::Str("C"),
|
||||
Token::Map { len: Some(0) },
|
||||
Token::MapEnd,
|
||||
Token::SeqEnd,
|
||||
],
|
||||
"invalid type: sequence, expected a map",
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::D(Newtype(BTreeMap::new())),
|
||||
&[
|
||||
Token::Map { len: Some(1) },
|
||||
|
||||
@@ -653,24 +679,12 @@ fn test_internally_tagged_enum() {
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::E(Newtype(BTreeMap::new())),
|
||||
&[
|
||||
Token::Map { len: Some(1) },
|
||||
|
||||
Token::Str("type"),
|
||||
Token::Str("E"),
|
||||
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&InternallyTagged::F(Struct { f: 6 }),
|
||||
&InternallyTagged::E(Struct { f: 6 }),
|
||||
&[
|
||||
Token::Struct { name: "Struct", len: 2 },
|
||||
|
||||
Token::Str("type"),
|
||||
Token::Str("F"),
|
||||
Token::Str("E"),
|
||||
|
||||
Token::Str("f"),
|
||||
Token::U8(6),
|
||||
@@ -679,6 +693,16 @@ fn test_internally_tagged_enum() {
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&InternallyTagged::E(Struct { f: 6 }),
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::Str("E"),
|
||||
Token::U8(6),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<InternallyTagged>(
|
||||
&[Token::Map { len: Some(0) }, Token::MapEnd],
|
||||
"missing field `type`",
|
||||
@@ -693,7 +717,7 @@ fn test_internally_tagged_enum() {
|
||||
|
||||
Token::MapEnd,
|
||||
],
|
||||
"unknown variant `Z`, expected one of `A`, `B`, `C`, `D`, `E`, `F`",
|
||||
"unknown variant `Z`, expected one of `A`, `B`, `C`, `D`, `E`",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// 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.
|
||||
|
||||
extern crate serde_test;
|
||||
use self::serde_test::{Token, assert_tokens_readable};
|
||||
|
||||
use std::net;
|
||||
|
||||
#[macro_use]
|
||||
#[allow(unused_macros)]
|
||||
mod macros;
|
||||
|
||||
#[test]
|
||||
fn ip_addr_roundtrip() {
|
||||
|
||||
assert_tokens_readable(
|
||||
&net::IpAddr::from(*b"1234"),
|
||||
&seq![
|
||||
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
Some(false),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn socked_addr_roundtrip() {
|
||||
|
||||
assert_tokens_readable(
|
||||
&net::SocketAddr::from((*b"1234567890123456", 1234)),
|
||||
&seq![
|
||||
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
|
||||
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
Some(false),
|
||||
);
|
||||
}
|
||||
+101
-21
@@ -16,6 +16,7 @@ use std::time::{Duration, UNIX_EPOCH};
|
||||
use std::ffi::CString;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::num::Wrapping;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::str;
|
||||
@@ -23,7 +24,8 @@ use std::str;
|
||||
extern crate serde;
|
||||
|
||||
extern crate serde_test;
|
||||
use self::serde_test::{Token, assert_ser_tokens, assert_ser_tokens_error};
|
||||
use self::serde_test::{Token, assert_ser_tokens, assert_ser_tokens_error,
|
||||
assert_ser_tokens_readable};
|
||||
|
||||
extern crate fnv;
|
||||
use self::fnv::FnvHasher;
|
||||
@@ -65,6 +67,20 @@ enum Enum {
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! declare_tests {
|
||||
(
|
||||
readable: $readable:tt
|
||||
$($name:ident { $($value:expr => $tokens:expr,)+ })+
|
||||
) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $name() {
|
||||
$(
|
||||
assert_ser_tokens_readable(&$value, $tokens, Some($readable));
|
||||
)+
|
||||
}
|
||||
)+
|
||||
};
|
||||
|
||||
($($name:ident { $($value:expr => $tokens:expr,)+ })+) => {
|
||||
$(
|
||||
#[test]
|
||||
@@ -354,17 +370,6 @@ declare_tests! {
|
||||
Token::StructEnd,
|
||||
],
|
||||
}
|
||||
test_net_ipv4addr {
|
||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_ipv6addr {
|
||||
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
|
||||
}
|
||||
test_net_socketaddr {
|
||||
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
|
||||
}
|
||||
test_path {
|
||||
Path::new("/usr/local/lib") => &[
|
||||
Token::Str("/usr/local/lib"),
|
||||
@@ -395,6 +400,90 @@ declare_tests! {
|
||||
Token::Bool(true),
|
||||
],
|
||||
}
|
||||
test_wrapping {
|
||||
Wrapping(1usize) => &[
|
||||
Token::U64(1),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
declare_tests! {
|
||||
readable: true
|
||||
test_net_ipv4addr_readable {
|
||||
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_ipv6addr_readable {
|
||||
"::1".parse::<net::Ipv6Addr>().unwrap() => &[Token::Str("::1")],
|
||||
}
|
||||
test_net_ipaddr_readable {
|
||||
"1.2.3.4".parse::<net::IpAddr>().unwrap() => &[Token::Str("1.2.3.4")],
|
||||
}
|
||||
test_net_socketaddr_readable {
|
||||
"1.2.3.4:1234".parse::<net::SocketAddr>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"1.2.3.4:1234".parse::<net::SocketAddrV4>().unwrap() => &[Token::Str("1.2.3.4:1234")],
|
||||
"[::1]:1234".parse::<net::SocketAddrV6>().unwrap() => &[Token::Str("[::1]:1234")],
|
||||
}
|
||||
}
|
||||
|
||||
declare_tests! {
|
||||
readable: false
|
||||
test_net_ipv4addr_compact {
|
||||
net::Ipv4Addr::from(*b"1234") => &seq![
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
}
|
||||
test_net_ipv6addr_compact {
|
||||
net::Ipv6Addr::from(*b"1234567890123456") => &seq![
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
}
|
||||
test_net_ipaddr_compact {
|
||||
net::IpAddr::from(*b"1234") => &seq![
|
||||
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
}
|
||||
test_net_socketaddr_compact {
|
||||
net::SocketAddr::from((*b"1234567890123456", 1234)) => &seq![
|
||||
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
|
||||
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
net::SocketAddrV4::new(net::Ipv4Addr::from(*b"1234"), 1234) => &seq![
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 4 },
|
||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
net::SocketAddrV6::new(net::Ipv6Addr::from(*b"1234567890123456"), 1234, 0, 0) => &seq![
|
||||
Token::Tuple { len: 2 },
|
||||
|
||||
Token::Tuple { len: 16 },
|
||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
||||
Token::TupleEnd,
|
||||
|
||||
Token::U16(1234),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
// Serde's implementation is not unstable, but the constructors are.
|
||||
@@ -422,15 +511,6 @@ declare_tests! {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
#[test]
|
||||
fn test_net_ipaddr() {
|
||||
assert_ser_tokens(
|
||||
&"1.2.3.4".parse::<net::IpAddr>().unwrap(),
|
||||
&[Token::Str("1.2.3.4")],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_cannot_serialize_paths() {
|
||||
|
||||
Reference in New Issue
Block a user