mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-22 21:48:02 +00:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c3eced410f | |||
| 8a630fea7c | |||
| 2e597ed3f0 | |||
| 0963121beb | |||
| 15b2714058 | |||
| 9ce107de25 | |||
| e47284c0e0 | |||
| 800620e2aa | |||
| ba260b0e5f | |||
| 8452e313cc | |||
| deca49315a | |||
| 95407a4ca5 | |||
| 2fe9a860cd | |||
| e67d941b78 | |||
| d4042872f5 | |||
| 64af86b830 | |||
| 370c8a91cb | |||
| 972da59ebc | |||
| a42008f695 | |||
| e4ea2a56e9 | |||
| 7650a48fdd | |||
| d665a2f2b2 | |||
| 44e23254c9 | |||
| 552971196d | |||
| 0681cd5003 | |||
| d965367238 | |||
| a6df35b3d2 | |||
| 9fc180e62f | |||
| 5b815b7001 | |||
| 4831482695 | |||
| d3e5dd9cd7 | |||
| 26098ed877 | |||
| 42ed62cf24 | |||
| 9f0973aff7 | |||
| ccec002bf3 | |||
| f36a1e0895 | |||
| e6487cf6fa | |||
| 4f2e8d5dbb | |||
| 1c2a4bff1c | |||
| 85bccf42b6 | |||
| 959fee024f | |||
| 8ede8c8e2a | |||
| 83537c95e1 | |||
| fa9057fa31 | |||
| 0084d82a50 | |||
| b504b08782 | |||
| 775e8154e7 | |||
| 9c679d9082 | |||
| b0f9d2a0ba | |||
| f39b1db96a | |||
| 9ecb0839de | |||
| 8a4c116812 | |||
| 1d3e921ba6 | |||
| 8e8694261b | |||
| 4fdba725fe | |||
| 75eed8cdde | |||
| 6801a13650 | |||
| 25ab84d4b9 | |||
| e43d3f3e4f | |||
| b37d47c987 | |||
| eec7101894 | |||
| 5dd327fb02 | |||
| fd3d1396d3 | |||
| c47b4c8e0b | |||
| 2d793b82f6 | |||
| 237be46e29 | |||
| 3d7aad1e7b | |||
| e792874369 | |||
| 1669c69714 |
@@ -5,5 +5,4 @@ members = [
|
||||
"serde_derive_internals",
|
||||
"serde_test",
|
||||
"test_suite",
|
||||
"test_suite/no_std",
|
||||
]
|
||||
|
||||
+4
-11
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "1.0.5" # remember to update html_root_url
|
||||
version = "1.0.13" # 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"
|
||||
@@ -48,22 +48,15 @@ std = []
|
||||
# https://github.com/serde-rs/serde/issues/812
|
||||
unstable = []
|
||||
|
||||
# Provide impls for types that require memory allocation like Box<T> and Rc<T>.
|
||||
# This is a subset of std but may be enabled without depending on all of std.
|
||||
# Provide impls for types in the Rust core allocation and collections library
|
||||
# including String, Box<T>, Vec<T>, and Cow<T>. This is a subset of std but may
|
||||
# be enabled without depending on all of std.
|
||||
#
|
||||
# Requires a dependency on the unstable core allocation library:
|
||||
#
|
||||
# https://doc.rust-lang.org/alloc/
|
||||
alloc = ["unstable"]
|
||||
|
||||
# Provide impls for collection types like String and Cow<T>. This is a subset of
|
||||
# std but may be enabled without depending on all of std.
|
||||
#
|
||||
# Requires a dependency on the unstable collections library:
|
||||
#
|
||||
# https://doc.rust-lang.org/collections/
|
||||
collections = ["alloc"]
|
||||
|
||||
# Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types
|
||||
# does not preserve identity and may result in multiple copies of the same data.
|
||||
# Be sure that this is what you want before enabling this feature.
|
||||
|
||||
+193
-118
@@ -11,12 +11,12 @@ use lib::*;
|
||||
use de::{Deserialize, Deserializer, EnumAccess, Error, SeqAccess, Unexpected, VariantAccess,
|
||||
Visitor};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
use de::MapAccess;
|
||||
|
||||
use de::from_primitive::FromPrimitive;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
use private::de::size_hint;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -208,10 +208,10 @@ impl<'de> Deserialize<'de> for char {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
struct StringVisitor;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de> Visitor<'de> for StringVisitor {
|
||||
type Value = String;
|
||||
|
||||
@@ -254,7 +254,7 @@ impl<'de> Visitor<'de> for StringVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de> Deserialize<'de> for String {
|
||||
fn deserialize<D>(deserializer: D) -> Result<String, D::Error>
|
||||
where
|
||||
@@ -400,16 +400,22 @@ impl<'de> Deserialize<'de> for CString {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", feature = "unstable"))]
|
||||
impl<'de> Deserialize<'de> for Box<CStr> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
CString::deserialize(deserializer).map(CString::into_boxed_c_str)
|
||||
macro_rules! forwarded_impl {
|
||||
(( $($id: ident),* ), $ty: ty, $func: expr) => {
|
||||
impl<'de $(, $id : Deserialize<'de>,)*> Deserialize<'de> for $ty {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Deserialize::deserialize(deserializer).map($func)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", feature = "unstable"))]
|
||||
forwarded_impl!((), Box<CStr>, CString::into_boxed_c_str);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct OptionVisitor<T> {
|
||||
@@ -497,7 +503,7 @@ impl<'de, T> Deserialize<'de> for PhantomData<T> {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
macro_rules! seq_impl {
|
||||
(
|
||||
$ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >,
|
||||
@@ -552,7 +558,7 @@ macro_rules! seq_impl {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(
|
||||
BinaryHeap<T: Ord>,
|
||||
seq,
|
||||
@@ -560,7 +566,7 @@ seq_impl!(
|
||||
BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())),
|
||||
BinaryHeap::push);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(
|
||||
BTreeSet<T: Eq + Ord>,
|
||||
seq,
|
||||
@@ -568,7 +574,7 @@ seq_impl!(
|
||||
BTreeSet::new(),
|
||||
BTreeSet::insert);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(
|
||||
LinkedList<T>,
|
||||
seq,
|
||||
@@ -584,7 +590,7 @@ seq_impl!(
|
||||
HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()),
|
||||
HashSet::insert);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(
|
||||
Vec<T>,
|
||||
seq,
|
||||
@@ -592,7 +598,7 @@ seq_impl!(
|
||||
Vec::with_capacity(size_hint::cautious(seq.size_hint())),
|
||||
Vec::push);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(
|
||||
VecDeque<T>,
|
||||
seq,
|
||||
@@ -790,7 +796,7 @@ tuple_impls! {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
macro_rules! map_impl {
|
||||
(
|
||||
$ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >,
|
||||
@@ -846,7 +852,7 @@ macro_rules! map_impl {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
map_impl!(
|
||||
BTreeMap<K: Ord, V>,
|
||||
map,
|
||||
@@ -1098,68 +1104,21 @@ impl<'de> Deserialize<'de> for OsString {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, T> Deserialize<'de> for Box<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Box<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
T::deserialize(deserializer).map(Box::new)
|
||||
}
|
||||
}
|
||||
forwarded_impl!((T), Box<T>, Box::new);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<'de, T> Deserialize<'de> for Box<[T]>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Box<[T]>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Vec::<T>::deserialize(deserializer).map(Vec::into_boxed_slice)
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
forwarded_impl!((T), Box<[T]>, Vec::into_boxed_slice);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<'de> Deserialize<'de> for Box<str> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
String::deserialize(deserializer).map(String::into_boxed_str)
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
forwarded_impl!((), Box<str>, String::into_boxed_str);
|
||||
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
impl<'de, T> Deserialize<'de> for Arc<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Arc<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
T::deserialize(deserializer).map(Arc::new)
|
||||
}
|
||||
}
|
||||
#[cfg(all(not(feature = "unstable"), feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
forwarded_impl!((T), Arc<T>, Arc::new);
|
||||
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
impl<'de, T> Deserialize<'de> for Rc<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Rc<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
T::deserialize(deserializer).map(Rc::new)
|
||||
}
|
||||
}
|
||||
#[cfg(all(not(feature = "unstable"), feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
forwarded_impl!((T), Rc<T>, Rc::new);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T>
|
||||
where
|
||||
T: ToOwned,
|
||||
@@ -1176,6 +1135,31 @@ where
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
macro_rules! box_forwarded_impl {
|
||||
($t:ident) => {
|
||||
impl<'de, T: ?Sized> Deserialize<'de> for $t<T>
|
||||
where
|
||||
Box<T>: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Box::deserialize(deserializer).map(Into::into)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
box_forwarded_impl!(Rc);
|
||||
|
||||
#[cfg(all(feature = "unstable", feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
box_forwarded_impl!(Arc);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<'de, T> Deserialize<'de> for Cell<T>
|
||||
where
|
||||
T: Deserialize<'de> + Copy,
|
||||
@@ -1188,43 +1172,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for RefCell<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<RefCell<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
T::deserialize(deserializer).map(RefCell::new)
|
||||
}
|
||||
}
|
||||
forwarded_impl!((T), RefCell<T>, RefCell::new);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de, T> Deserialize<'de> for Mutex<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Mutex<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
T::deserialize(deserializer).map(Mutex::new)
|
||||
}
|
||||
}
|
||||
forwarded_impl!((T), Mutex<T>, Mutex::new);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de, T> Deserialize<'de> for RwLock<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<RwLock<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
T::deserialize(deserializer).map(RwLock::new)
|
||||
}
|
||||
}
|
||||
forwarded_impl!((T), RwLock<T>, RwLock::new);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1364,6 +1318,132 @@ impl<'de> Deserialize<'de> for Duration {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'de> Deserialize<'de> for SystemTime {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// Reuse duration
|
||||
enum Field {
|
||||
Secs,
|
||||
Nanos,
|
||||
};
|
||||
|
||||
impl<'de> Deserialize<'de> for Field {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct FieldVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for FieldVisitor {
|
||||
type Value = Field;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("`secs_since_epoch` or `nanos_since_epoch`")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Field, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
"secs_since_epoch" => Ok(Field::Secs),
|
||||
"nanos_since_epoch" => Ok(Field::Nanos),
|
||||
_ => Err(Error::unknown_field(value, FIELDS)),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, value: &[u8]) -> Result<Field, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
match value {
|
||||
b"secs_since_epoch" => Ok(Field::Secs),
|
||||
b"nanos_since_epoch" => Ok(Field::Nanos),
|
||||
_ => {
|
||||
let value = String::from_utf8_lossy(value);
|
||||
Err(Error::unknown_field(&value, FIELDS))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_identifier(FieldVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct DurationVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for DurationVisitor {
|
||||
type Value = Duration;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("struct SystemTime")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Duration, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
let secs: u64 = match try!(seq.next_element()) {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
return Err(Error::invalid_length(0, &self));
|
||||
}
|
||||
};
|
||||
let nanos: u32 = match try!(seq.next_element()) {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
return Err(Error::invalid_length(1, &self));
|
||||
}
|
||||
};
|
||||
Ok(Duration::new(secs, nanos))
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Duration, A::Error>
|
||||
where
|
||||
A: MapAccess<'de>,
|
||||
{
|
||||
let mut secs: Option<u64> = None;
|
||||
let mut nanos: Option<u32> = None;
|
||||
while let Some(key) = try!(map.next_key()) {
|
||||
match key {
|
||||
Field::Secs => {
|
||||
if secs.is_some() {
|
||||
return Err(<A::Error as Error>::duplicate_field("secs_since_epoch"));
|
||||
}
|
||||
secs = Some(try!(map.next_value()));
|
||||
}
|
||||
Field::Nanos => {
|
||||
if nanos.is_some() {
|
||||
return Err(<A::Error as Error>::duplicate_field("nanos_since_epoch"));
|
||||
}
|
||||
nanos = Some(try!(map.next_value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
let secs = match secs {
|
||||
Some(secs) => secs,
|
||||
None => return Err(<A::Error as Error>::missing_field("secs_since_epoch")),
|
||||
};
|
||||
let nanos = match nanos {
|
||||
Some(nanos) => nanos,
|
||||
None => return Err(<A::Error as Error>::missing_field("nanos_since_epoch")),
|
||||
};
|
||||
Ok(Duration::new(secs, nanos))
|
||||
}
|
||||
}
|
||||
|
||||
const FIELDS: &'static [&'static str] = &["secs_since_epoch", "nanos_since_epoch"];
|
||||
let duration = try!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor));
|
||||
Ok(UNIX_EPOCH + duration)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Similar to:
|
||||
//
|
||||
// #[derive(Deserialize)]
|
||||
@@ -1518,14 +1598,9 @@ where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value = try!(Deserialize::deserialize(deserializer));
|
||||
unsafe {
|
||||
let ptr = &value as *const T as *const u8;
|
||||
if slice::from_raw_parts(ptr, mem::size_of::<T>()).iter().all(|&b| b == 0) {
|
||||
return Err(Error::custom("expected a non-zero value"));
|
||||
}
|
||||
// Waiting for a safe way to construct NonZero<T>:
|
||||
// https://github.com/rust-lang/rust/issues/27730#issuecomment-269726075
|
||||
Ok(NonZero::new(value))
|
||||
match NonZero::new(value) {
|
||||
Some(nonzero) => Ok(nonzero),
|
||||
None => Err(Error::custom("expected a non-zero value")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -94,6 +94,7 @@
|
||||
//! - OsString
|
||||
//! - **Miscellaneous standard library types**:
|
||||
//! - Duration
|
||||
//! - SystemTime
|
||||
//! - Path
|
||||
//! - PathBuf
|
||||
//! - Range\<T\>
|
||||
@@ -1119,7 +1120,7 @@ pub trait Visitor<'de>: Sized {
|
||||
self.visit_i64(v as i64)
|
||||
}
|
||||
|
||||
/// The input contains an `i32`.
|
||||
/// The input contains an `i64`.
|
||||
///
|
||||
/// The default implementation fails with a type error.
|
||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||
@@ -1262,7 +1263,7 @@ pub trait Visitor<'de>: Sized {
|
||||
/// The default implementation forwards to `visit_str` and then drops the
|
||||
/// `String`.
|
||||
#[inline]
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
@@ -1321,7 +1322,7 @@ pub trait Visitor<'de>: Sized {
|
||||
///
|
||||
/// The default implementation forwards to `visit_bytes` and then drops the
|
||||
/// `Vec<u8>`.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
@@ -1423,7 +1424,7 @@ pub trait SeqAccess<'de> {
|
||||
/// `Ok(None)` if there are no more remaining items.
|
||||
///
|
||||
/// `Deserialize` implementations should typically use
|
||||
/// `SeqAcccess::next_element` instead.
|
||||
/// `SeqAccess::next_element` instead.
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>;
|
||||
|
||||
+126
-17
@@ -51,13 +51,13 @@ pub struct Error {
|
||||
err: ErrorImpl,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
type ErrorImpl = Box<str>;
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
type ErrorImpl = ();
|
||||
|
||||
impl de::Error for Error {
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: Display,
|
||||
@@ -65,7 +65,7 @@ impl de::Error for Error {
|
||||
Error { err: msg.to_string().into_boxed_str() }
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: Display,
|
||||
@@ -85,12 +85,12 @@ impl ser::Error for Error {
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
formatter.write_str(&self.err)
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
formatter.write_str("Serde deserialization error")
|
||||
}
|
||||
@@ -355,15 +355,84 @@ where
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer holding a `&str` with a lifetime tied to another
|
||||
/// deserializer.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BorrowedStrDeserializer<'de, E> {
|
||||
value: &'de str,
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<'de, E> BorrowedStrDeserializer<'de, E> {
|
||||
/// Create a new borrowed deserializer from the given string.
|
||||
pub fn new(value: &'de str) -> BorrowedStrDeserializer<'de, E> {
|
||||
BorrowedStrDeserializer {
|
||||
value: value,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> de::Deserializer<'de> for BorrowedStrDeserializer<'de, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_borrowed_str(self.value)
|
||||
}
|
||||
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
name: &str,
|
||||
variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
let _ = name;
|
||||
let _ = variants;
|
||||
visitor.visit_enum(self)
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> de::EnumAccess<'de> for BorrowedStrDeserializer<'de, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Error = E;
|
||||
type Variant = private::UnitOnly<E>;
|
||||
|
||||
fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error>
|
||||
where
|
||||
T: de::DeserializeSeed<'de>,
|
||||
{
|
||||
seed.deserialize(self).map(private::unit_only)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer holding a `String`.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StringDeserializer<E> {
|
||||
value: String,
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, E> IntoDeserializer<'de, E> for String
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -378,7 +447,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, E> de::Deserializer<'de> for StringDeserializer<E>
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -413,7 +482,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, 'a, E> de::EnumAccess<'de> for StringDeserializer<E>
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -432,14 +501,14 @@ where
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer holding a `Cow<str>`.
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CowStrDeserializer<'a, E> {
|
||||
value: Cow<'a, str>,
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str>
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -454,7 +523,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, 'a, E> de::Deserializer<'de> for CowStrDeserializer<'a, E>
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -492,7 +561,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E>
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -510,6 +579,46 @@ where
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer holding a `&[u8]` with a lifetime tied to another
|
||||
/// deserializer.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BorrowedBytesDeserializer<'de, E> {
|
||||
value: &'de [u8],
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<'de, E> BorrowedBytesDeserializer<'de, E> {
|
||||
/// Create a new borrowed deserializer from the given byte slice.
|
||||
pub fn new(value: &'de [u8]) -> BorrowedBytesDeserializer<'de, E> {
|
||||
BorrowedBytesDeserializer {
|
||||
value: value,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> de::Deserializer<'de> for BorrowedBytesDeserializer<'de, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_borrowed_bytes(self.value)
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct identifier ignored_any enum
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer that iterates over a sequence.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SeqDeserializer<I, E> {
|
||||
@@ -618,7 +727,7 @@ impl Expected for ExpectedInSeq {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, T, E> IntoDeserializer<'de, E> for Vec<T>
|
||||
where
|
||||
T: IntoDeserializer<'de, E>,
|
||||
@@ -631,7 +740,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, T, E> IntoDeserializer<'de, E> for BTreeSet<T>
|
||||
where
|
||||
T: IntoDeserializer<'de, E> + Eq + Ord,
|
||||
@@ -1036,7 +1145,7 @@ impl Expected for ExpectedInMap {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, K, V, E> IntoDeserializer<'de, E> for BTreeMap<K, V>
|
||||
where
|
||||
K: IntoDeserializer<'de, E> + Eq + Ord,
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ pub use self::string::from_utf8_lossy;
|
||||
mod string {
|
||||
use lib::*;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<str> {
|
||||
String::from_utf8_lossy(bytes)
|
||||
}
|
||||
@@ -31,7 +31,7 @@ mod string {
|
||||
//
|
||||
// so it is okay for the return type to be different from the std case as long
|
||||
// as the above works.
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
|
||||
// Three unicode replacement characters if it fails. They look like a
|
||||
// white-on-black question mark. The user will recognize it as invalid
|
||||
|
||||
+45
-23
@@ -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.5")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.13")]
|
||||
|
||||
// Support using Serde without the standard library!
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
@@ -89,33 +89,55 @@
|
||||
//
|
||||
// https://github.com/serde-rs/serde/issues/812
|
||||
#![cfg_attr(feature = "unstable", feature(nonzero, specialization))]
|
||||
#![cfg_attr(all(feature = "std", feature = "unstable"), feature(into_boxed_c_str))]
|
||||
#![cfg_attr(feature = "alloc", feature(alloc))]
|
||||
#![cfg_attr(feature = "collections", feature(collections))]
|
||||
|
||||
// Whitelisted clippy lints.
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(doc_markdown))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(linkedlist))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(zero_prefixed_literal))]
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||
// Whitelisted clippy lints
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(
|
||||
cast_lossless,
|
||||
doc_markdown,
|
||||
linkedlist,
|
||||
type_complexity,
|
||||
unreadable_literal,
|
||||
zero_prefixed_literal,
|
||||
))]
|
||||
// Whitelisted clippy_pedantic lints
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(
|
||||
// integer and float ser/de requires these sorts of casts
|
||||
cast_possible_truncation,
|
||||
cast_possible_wrap,
|
||||
cast_precision_loss,
|
||||
cast_sign_loss,
|
||||
// simplifies some macros
|
||||
invalid_upcast_comparisons,
|
||||
// things are often more readable this way
|
||||
option_unwrap_used,
|
||||
result_unwrap_used,
|
||||
shadow_reuse,
|
||||
single_match_else,
|
||||
stutter,
|
||||
use_self,
|
||||
// not practical
|
||||
missing_docs_in_private_items,
|
||||
// alternative is not stable
|
||||
empty_enum,
|
||||
use_debug,
|
||||
))]
|
||||
|
||||
// Blacklisted Rust lints.
|
||||
#![deny(missing_docs, unused_imports)]
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "collections")]
|
||||
extern crate collections;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(all(feature = "unstable", feature = "std"))]
|
||||
extern crate core;
|
||||
|
||||
/// A facade around all the types we need from the `std`, `core`, `alloc`, and
|
||||
/// `collections` crates. This avoids elaborate import wrangling having to
|
||||
/// happen in every module.
|
||||
/// A facade around all the types we need from the `std`, `core`, and `alloc`
|
||||
/// crates. This avoids elaborate import wrangling having to happen in every
|
||||
/// module.
|
||||
mod lib {
|
||||
mod core {
|
||||
#[cfg(feature = "std")]
|
||||
@@ -140,18 +162,18 @@ mod lib {
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::borrow::{Cow, ToOwned};
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
pub use collections::borrow::{Cow, ToOwned};
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::borrow::{Cow, ToOwned};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::string::String;
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
pub use collections::string::{String, ToString};
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::string::{String, ToString};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::vec::Vec;
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
pub use collections::vec::Vec;
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::vec::Vec;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::boxed::Box;
|
||||
@@ -170,8 +192,8 @@ mod lib {
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
pub use collections::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::{BinaryHeap, BTreeMap, BTreeSet, LinkedList, VecDeque};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::{error, net};
|
||||
@@ -187,7 +209,7 @@ mod lib {
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::path::{Path, PathBuf};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::time::Duration;
|
||||
pub use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::sync::{Mutex, RwLock};
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@ use lib::*;
|
||||
|
||||
use de::{Deserialize, Deserializer, IntoDeserializer, Error, Visitor};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
use de::Unexpected;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub use self::content::{Content, ContentRefDeserializer, ContentDeserializer,
|
||||
TaggedContentVisitor, TagOrContentField, TagOrContentFieldVisitor,
|
||||
TagContentOtherField, TagContentOtherFieldVisitor,
|
||||
@@ -59,7 +59,7 @@ where
|
||||
Deserialize::deserialize(deserializer)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub fn borrow_cow_str<'de: 'a, 'a, D>(deserializer: D) -> Result<Cow<'a, str>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
@@ -128,7 +128,7 @@ where
|
||||
deserializer.deserialize_str(CowStrVisitor)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub fn borrow_cow_bytes<'de: 'a, 'a, D>(deserializer: D) -> Result<Cow<'a, [u8]>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
@@ -210,7 +210,7 @@ pub mod size_hint {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
mod content {
|
||||
// This module is private and nothing here should be used outside of
|
||||
// generated code.
|
||||
|
||||
+13
-13
@@ -10,7 +10,7 @@ use lib::*;
|
||||
|
||||
use ser::{self, Serialize, Serializer, SerializeMap, SerializeStruct, Impossible};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
use self::content::{SerializeTupleVariantAsMapValue, SerializeStructVariantAsMapValue};
|
||||
|
||||
/// Used to check that serde(getter) attributes return the expected type.
|
||||
@@ -64,7 +64,7 @@ enum Unsupported {
|
||||
Sequence,
|
||||
Tuple,
|
||||
TupleStruct,
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
Enum,
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ impl Display for Unsupported {
|
||||
Unsupported::Sequence => formatter.write_str("a sequence"),
|
||||
Unsupported::Tuple => formatter.write_str("a tuple"),
|
||||
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
Unsupported::Enum => formatter.write_str("an enum"),
|
||||
}
|
||||
}
|
||||
@@ -117,14 +117,14 @@ where
|
||||
type SerializeMap = S::SerializeMap;
|
||||
type SerializeStruct = S::SerializeStruct;
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
type SerializeTupleVariant = Impossible<S::Ok, S::Error>;
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
type SerializeTupleVariant = SerializeTupleVariantAsMapValue<S::SerializeMap>;
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
type SerializeStructVariant = Impossible<S::Ok, S::Error>;
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
type SerializeStructVariant = SerializeStructVariantAsMapValue<S::SerializeMap>;
|
||||
|
||||
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
|
||||
@@ -257,7 +257,7 @@ where
|
||||
Err(self.bad_type(Unsupported::TupleStruct))
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_: &'static str,
|
||||
@@ -270,7 +270,7 @@ where
|
||||
Err(self.bad_type(Unsupported::Enum))
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_: &'static str,
|
||||
@@ -300,7 +300,7 @@ where
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
_: &'static str,
|
||||
@@ -313,7 +313,7 @@ where
|
||||
Err(self.bad_type(Unsupported::Enum))
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
_: &'static str,
|
||||
@@ -327,7 +327,7 @@ where
|
||||
Ok(SerializeStructVariantAsMapValue::new(map, inner_variant, len),)
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn collect_str<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Display,
|
||||
@@ -363,7 +363,7 @@ impl Display for Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
mod content {
|
||||
use lib::*;
|
||||
|
||||
|
||||
+29
-10
@@ -56,7 +56,7 @@ impl Serialize for str {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl Serialize for String {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -177,6 +177,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
macro_rules! seq_impl {
|
||||
($ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident)* >) => {
|
||||
impl<T $(, $typaram)*> Serialize for $ty<T $(, $typaram)*>
|
||||
@@ -195,22 +196,22 @@ macro_rules! seq_impl {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(BinaryHeap<T: Ord>);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(BTreeSet<T: Ord>);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
seq_impl!(HashSet<T: Eq + Hash, H: BuildHasher>);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(LinkedList<T>);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(Vec<T>);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(VecDeque<T>);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -290,6 +291,7 @@ tuple_impls! {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
macro_rules! map_impl {
|
||||
($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)* >) => {
|
||||
impl<K, V $(, $typaram)*> Serialize for $ty<K, V $(, $typaram)*>
|
||||
@@ -309,7 +311,7 @@ macro_rules! map_impl {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
map_impl!(BTreeMap<K: Ord, V>);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@@ -338,12 +340,12 @@ deref_impl!(<'a, T: ?Sized> Serialize for &'a mut T where T: Serialize);
|
||||
deref_impl!(<T: ?Sized> Serialize for Box<T> where T: Serialize);
|
||||
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
deref_impl!(<T> Serialize for Rc<T> where T: Serialize);
|
||||
deref_impl!(<T: ?Sized> Serialize for Rc<T> where T: Serialize);
|
||||
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
deref_impl!(<T> Serialize for Arc<T> where T: Serialize);
|
||||
deref_impl!(<T: ?Sized> Serialize for Arc<T> where T: Serialize);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -455,6 +457,23 @@ impl Serialize for Duration {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Serialize for SystemTime {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
use super::SerializeStruct;
|
||||
let duration_since_epoch = self.duration_since(UNIX_EPOCH).expect("SystemTime must be later than UNIX_EPOCH");
|
||||
let mut state = try!(serializer.serialize_struct("SystemTime", 2));
|
||||
try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs()));
|
||||
try!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos()));
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Serialize a value that implements `Display` as a string, when that string is
|
||||
/// statically known to never have more than a constant `MAX_LEN` bytes.
|
||||
///
|
||||
|
||||
+17
-2
@@ -89,6 +89,7 @@
|
||||
//! - OsString
|
||||
//! - **Miscellaneous standard library types**:
|
||||
//! - Duration
|
||||
//! - SystemTime
|
||||
//! - Path
|
||||
//! - PathBuf
|
||||
//! - Range\<T\>
|
||||
@@ -1321,7 +1322,7 @@ pub trait Serializer: Sized {
|
||||
///
|
||||
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
|
||||
/// [`serialize_str`]: #tymethod.serialize_str
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Display,
|
||||
@@ -1358,7 +1359,7 @@ pub trait Serializer: Sized {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Display;
|
||||
@@ -1726,6 +1727,13 @@ pub trait SerializeStruct {
|
||||
where
|
||||
T: Serialize;
|
||||
|
||||
/// Indicate that a struct field has been skipped.
|
||||
#[inline]
|
||||
fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
|
||||
let _ = key;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Finish serializing a struct.
|
||||
fn end(self) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
@@ -1771,6 +1779,13 @@ pub trait SerializeStructVariant {
|
||||
where
|
||||
T: Serialize;
|
||||
|
||||
/// Indicate that a struct variant field has been skipped.
|
||||
#[inline]
|
||||
fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
|
||||
let _ = key;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Finish serializing a struct variant.
|
||||
fn end(self) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "1.0.5" # remember to update html_root_url
|
||||
version = "1.0.13" # 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)]"
|
||||
@@ -20,5 +20,5 @@ proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "0.3.8"
|
||||
serde_derive_internals = { version = "=0.15.0", default-features = false, path = "../serde_derive_internals" }
|
||||
serde_derive_internals = { version = "=0.16.0", default-features = false, path = "../serde_derive_internals" }
|
||||
syn = { version = "0.11", features = ["visit"] }
|
||||
|
||||
@@ -10,7 +10,7 @@ use std::collections::HashSet;
|
||||
|
||||
use syn::{self, visit};
|
||||
|
||||
use internals::ast::Container;
|
||||
use internals::ast::{Body, Container};
|
||||
use internals::attr;
|
||||
|
||||
macro_rules! path {
|
||||
@@ -88,7 +88,7 @@ pub fn with_bound<F>(
|
||||
bound: &syn::Path,
|
||||
) -> syn::Generics
|
||||
where
|
||||
F: Fn(&attr::Field) -> bool,
|
||||
F: Fn(&attr::Field, Option<&attr::Variant>) -> bool,
|
||||
{
|
||||
struct FindTyParams {
|
||||
// Set of all generic type parameters on the current struct (A, B, C in
|
||||
@@ -124,17 +124,27 @@ where
|
||||
.map(|ty_param| ty_param.ident.clone())
|
||||
.collect();
|
||||
|
||||
let relevant_tys = cont.body
|
||||
.all_fields()
|
||||
.filter(|&field| filter(&field.attrs))
|
||||
.map(|field| &field.ty);
|
||||
|
||||
let mut visitor = FindTyParams {
|
||||
all_ty_params: all_ty_params,
|
||||
relevant_ty_params: HashSet::new(),
|
||||
};
|
||||
for ty in relevant_tys {
|
||||
visit::walk_ty(&mut visitor, ty);
|
||||
match cont.body {
|
||||
Body::Enum(ref variants) => {
|
||||
for variant in variants.iter() {
|
||||
let relevant_fields = variant
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|field| filter(&field.attrs, Some(&variant.attrs)));
|
||||
for field in relevant_fields {
|
||||
visit::walk_ty(&mut visitor, field.ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
Body::Struct(_, ref fields) => {
|
||||
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
|
||||
visit::walk_ty(&mut visitor, field.ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let new_predicates = generics
|
||||
|
||||
+132
-44
@@ -23,15 +23,15 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
|
||||
|
||||
let ident = &cont.ident;
|
||||
let params = Parameters::new(&cont);
|
||||
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms);
|
||||
let dummy_const = Ident::new(format!("_IMPL_DESERIALIZE_FOR_{}", ident));
|
||||
let body = Stmts(deserialize_body(&cont, ¶ms));
|
||||
|
||||
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
||||
let (impl_generics, ty_generics, where_clause) = cont.generics.split_for_impl();
|
||||
let de_lifetime = params.de_lifetime_def();
|
||||
let vis = &input.vis;
|
||||
quote! {
|
||||
impl #impl_generics #ident #ty_generics #where_clause {
|
||||
fn deserialize<#de_lifetime, __D>(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error>
|
||||
impl #de_impl_generics #ident #ty_generics #where_clause {
|
||||
#vis fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<#remote #ty_generics, __D::Error>
|
||||
where __D: _serde::Deserializer<'de>
|
||||
{
|
||||
#body
|
||||
@@ -39,7 +39,6 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms);
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl #de_impl_generics _serde::Deserialize<'de> for #ident #ty_generics #where_clause {
|
||||
@@ -158,14 +157,17 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
||||
// deserialized by us so we do not generate a bound. Fields with a `bound`
|
||||
// attribute specify their own bound so we do not generate one. All other fields
|
||||
// may need a `T: Deserialize` bound where T is the type of the field.
|
||||
fn needs_deserialize_bound(attrs: &attr::Field) -> bool {
|
||||
!attrs.skip_deserializing() && attrs.deserialize_with().is_none() && attrs.de_bound().is_none()
|
||||
fn needs_deserialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
|
||||
!field.skip_deserializing() &&
|
||||
field.deserialize_with().is_none() &&
|
||||
field.de_bound().is_none() &&
|
||||
variant.map_or(true, |variant| variant.deserialize_with().is_none())
|
||||
}
|
||||
|
||||
// Fields with a `default` attribute (not `default=...`), and fields with a
|
||||
// `skip_deserializing` attribute that do not also have `default=...`.
|
||||
fn requires_default(attrs: &attr::Field) -> bool {
|
||||
attrs.default() == &attr::Default::Default
|
||||
fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bool {
|
||||
field.default() == &attr::Default::Default
|
||||
}
|
||||
|
||||
// The union of lifetimes borrowed by each field of the container.
|
||||
@@ -373,7 +375,7 @@ fn deserialize_seq(
|
||||
quote!(try!(_serde::de::SeqAccess::next_element::<#field_ty>(&mut __seq)))
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(
|
||||
params, field.ty, path);
|
||||
quote!({
|
||||
#wrapper
|
||||
@@ -429,7 +431,7 @@ fn deserialize_newtype_struct(type_path: &Tokens, params: &Parameters, field: &F
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||
quote!({
|
||||
#wrapper
|
||||
try!(<#wrapper_ty as _serde::Deserialize>::deserialize(__e)).value
|
||||
@@ -797,9 +799,8 @@ fn deserialize_adjacently_tagged_enum(
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
let deny_unknown_fields = cattrs.deny_unknown_fields();
|
||||
|
||||
/// If unknown fields are allowed, we pick the visitor that can
|
||||
/// step over those. Otherwise we pick the visitor that fails on
|
||||
/// unknown keys.
|
||||
// If unknown fields are allowed, we pick the visitor that can step over
|
||||
// those. Otherwise we pick the visitor that fails on unknown keys.
|
||||
let field_visitor_ty = if deny_unknown_fields {
|
||||
quote! { _serde::private::de::TagOrContentFieldVisitor }
|
||||
} else {
|
||||
@@ -854,13 +855,13 @@ fn deserialize_adjacently_tagged_enum(
|
||||
};
|
||||
}
|
||||
|
||||
/// Advance the map by one key, returning early in case of error.
|
||||
// Advance the map by one key, returning early in case of error.
|
||||
let next_key = quote! {
|
||||
try!(_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content))
|
||||
};
|
||||
|
||||
/// When allowing unknown fields, we want to transparently step through keys we don't care
|
||||
/// about until we find `tag`, `content`, or run out of keys.
|
||||
// When allowing unknown fields, we want to transparently step through keys
|
||||
// we don't care about until we find `tag`, `content`, or run out of keys.
|
||||
let next_relevant_key = if deny_unknown_fields {
|
||||
next_key
|
||||
} else {
|
||||
@@ -889,9 +890,9 @@ fn deserialize_adjacently_tagged_enum(
|
||||
}
|
||||
};
|
||||
|
||||
/// Step through remaining keys, looking for duplicates of previously-seen keys.
|
||||
/// When unknown fields are denied, any key that isn't a duplicate will at this
|
||||
/// point immediately produce an error.
|
||||
// Step through remaining keys, looking for duplicates of previously-seen
|
||||
// keys. When unknown fields are denied, any key that isn't a duplicate will
|
||||
// at this point immediately produce an error.
|
||||
let visit_remaining_keys = quote! {
|
||||
match #next_relevant_key {
|
||||
_serde::export::Some(_serde::private::de::TagOrContentField::Tag) => {
|
||||
@@ -1086,6 +1087,16 @@ fn deserialize_externally_tagged_variant(
|
||||
variant: &Variant,
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.deserialize_with() {
|
||||
let (wrapper, wrapper_ty, unwrap_fn) =
|
||||
wrap_deserialize_variant_with(params, &variant, path);
|
||||
return quote_block! {
|
||||
#wrapper
|
||||
_serde::export::Result::map(
|
||||
_serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn)
|
||||
};
|
||||
}
|
||||
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
match variant.style {
|
||||
@@ -1114,6 +1125,10 @@ fn deserialize_internally_tagged_variant(
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Tokens,
|
||||
) -> Fragment {
|
||||
if variant.attrs.deserialize_with().is_some() {
|
||||
return deserialize_untagged_variant(params, variant, cattrs, deserializer);
|
||||
}
|
||||
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
match variant.style {
|
||||
@@ -1139,6 +1154,16 @@ fn deserialize_untagged_variant(
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Tokens,
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.deserialize_with() {
|
||||
let (wrapper, wrapper_ty, unwrap_fn) =
|
||||
wrap_deserialize_variant_with(params, &variant, path);
|
||||
return quote_block! {
|
||||
#wrapper
|
||||
_serde::export::Result::map(
|
||||
<#wrapper_ty as _serde::Deserialize>::deserialize(#deserializer), #unwrap_fn)
|
||||
};
|
||||
}
|
||||
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
match variant.style {
|
||||
@@ -1200,7 +1225,7 @@ fn deserialize_externally_tagged_newtype_variant(
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||
quote_block! {
|
||||
#wrapper
|
||||
_serde::export::Result::map(
|
||||
@@ -1228,7 +1253,7 @@ fn deserialize_untagged_newtype_variant(
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(params, field.ty, path);
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||
quote_block! {
|
||||
#wrapper
|
||||
_serde::export::Result::map(
|
||||
@@ -1386,26 +1411,27 @@ fn deserialize_identifier(
|
||||
"field identifier"
|
||||
};
|
||||
|
||||
let visit_index = if is_variant {
|
||||
let variant_indices = 0u32..;
|
||||
let fallthrough_msg = format!("variant index 0 <= i < {}", fields.len());
|
||||
let visit_index = quote! {
|
||||
fn visit_u32<__E>(self, __value: u32) -> _serde::export::Result<Self::Value, __E>
|
||||
where __E: _serde::de::Error
|
||||
{
|
||||
match __value {
|
||||
#(
|
||||
#variant_indices => _serde::export::Ok(#constructors),
|
||||
)*
|
||||
_ => _serde::export::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value as u64),
|
||||
&#fallthrough_msg))
|
||||
}
|
||||
}
|
||||
};
|
||||
Some(visit_index)
|
||||
let index_expecting = if is_variant {
|
||||
"variant"
|
||||
} else {
|
||||
None
|
||||
"field"
|
||||
};
|
||||
|
||||
let variant_indices = 0u64..;
|
||||
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
|
||||
let visit_index = quote! {
|
||||
fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
|
||||
where __E: _serde::de::Error
|
||||
{
|
||||
match __value {
|
||||
#(
|
||||
#variant_indices => _serde::export::Ok(#constructors),
|
||||
)*
|
||||
_ => _serde::export::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value as u64),
|
||||
&#fallthrough_msg))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let bytes_to_str = if fallthrough.is_some() {
|
||||
@@ -1530,7 +1556,7 @@ fn deserialize_map(
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_with(
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(
|
||||
params, field.ty, path);
|
||||
quote!({
|
||||
#wrapper
|
||||
@@ -1663,7 +1689,7 @@ fn field_i(i: usize) -> Ident {
|
||||
/// in a trait to prevent it from accessing the internal `Deserialize` state.
|
||||
fn wrap_deserialize_with(
|
||||
params: &Parameters,
|
||||
field_ty: &syn::Ty,
|
||||
value_ty: Tokens,
|
||||
deserialize_with: &syn::Path,
|
||||
) -> (Tokens, Tokens) {
|
||||
let this = ¶ms.this;
|
||||
@@ -1671,7 +1697,7 @@ fn wrap_deserialize_with(
|
||||
|
||||
let wrapper = quote! {
|
||||
struct __DeserializeWith #de_impl_generics #where_clause {
|
||||
value: #field_ty,
|
||||
value: #value_ty,
|
||||
phantom: _serde::export::PhantomData<#this #ty_generics>,
|
||||
lifetime: _serde::export::PhantomData<&'de ()>,
|
||||
}
|
||||
@@ -1694,6 +1720,68 @@ fn wrap_deserialize_with(
|
||||
(wrapper, wrapper_ty)
|
||||
}
|
||||
|
||||
fn wrap_deserialize_field_with(
|
||||
params: &Parameters,
|
||||
field_ty: &syn::Ty,
|
||||
deserialize_with: &syn::Path,
|
||||
) -> (Tokens, Tokens) {
|
||||
wrap_deserialize_with(params, quote!(#field_ty), deserialize_with)
|
||||
}
|
||||
|
||||
fn wrap_deserialize_variant_with(
|
||||
params: &Parameters,
|
||||
variant: &Variant,
|
||||
deserialize_with: &syn::Path,
|
||||
) -> (Tokens, Tokens, Tokens) {
|
||||
let this = ¶ms.this;
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
let field_tys = variant.fields.iter().map(|field| field.ty);
|
||||
let (wrapper, wrapper_ty) =
|
||||
wrap_deserialize_with(params, quote!((#(#field_tys),*)), deserialize_with);
|
||||
|
||||
let field_access = (0..variant.fields.len()).map(|n| Ident::new(format!("{}", n)));
|
||||
let unwrap_fn = match variant.style {
|
||||
Style::Struct => {
|
||||
let field_idents = variant.fields.iter().map(|field| field.ident.as_ref().unwrap());
|
||||
quote! {
|
||||
{
|
||||
|__wrap| {
|
||||
#this::#variant_ident { #(#field_idents: __wrap.value.#field_access),* }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Style::Tuple => {
|
||||
quote! {
|
||||
{
|
||||
|__wrap| {
|
||||
#this::#variant_ident(#(__wrap.value.#field_access),*)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Style::Newtype => {
|
||||
quote! {
|
||||
{
|
||||
|__wrap| {
|
||||
#this::#variant_ident(__wrap.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Style::Unit => {
|
||||
quote! {
|
||||
{
|
||||
|__wrap| { #this::#variant_ident }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(wrapper, wrapper_ty, unwrap_fn)
|
||||
}
|
||||
|
||||
fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
|
||||
match *field.attrs.default() {
|
||||
attr::Default::Default => {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
//!
|
||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.5")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.13")]
|
||||
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
|
||||
|
||||
+162
-53
@@ -29,9 +29,10 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, Strin
|
||||
let body = Stmts(serialize_body(&cont, ¶ms));
|
||||
|
||||
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
||||
let vis = &input.vis;
|
||||
quote! {
|
||||
impl #impl_generics #ident #ty_generics #where_clause {
|
||||
fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||
where __S: _serde::Serializer
|
||||
{
|
||||
#body
|
||||
@@ -142,12 +143,16 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
||||
}
|
||||
}
|
||||
|
||||
// Fields with a `skip_serializing` or `serialize_with` attribute are not
|
||||
// serialized by us so we do not generate a bound. Fields with a `bound`
|
||||
// attribute specify their own bound so we do not generate one. All other fields
|
||||
// may need a `T: Serialize` bound where T is the type of the field.
|
||||
fn needs_serialize_bound(attrs: &attr::Field) -> bool {
|
||||
!attrs.skip_serializing() && attrs.serialize_with().is_none() && attrs.ser_bound().is_none()
|
||||
// Fields with a `skip_serializing` or `serialize_with` attribute, or which
|
||||
// belong to a variant with a `serialize_with` attribute, are not serialized by
|
||||
// us so we do not generate a bound. Fields with a `bound` attribute specify
|
||||
// their own bound so we do not generate one. All other fields may need a `T:
|
||||
// Serialize` bound where T is the type of the field.
|
||||
fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
|
||||
!field.skip_serializing() &&
|
||||
field.serialize_with().is_none() &&
|
||||
field.ser_bound().is_none() &&
|
||||
variant.map_or(true, |variant| variant.serialize_with().is_none())
|
||||
}
|
||||
|
||||
fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
||||
@@ -202,7 +207,7 @@ fn serialize_newtype_struct(
|
||||
|
||||
let mut field_expr = get_field(params, field, 0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -241,6 +246,7 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
|
||||
params,
|
||||
false,
|
||||
quote!(_serde::ser::SerializeStruct::serialize_field),
|
||||
quote!(_serde::ser::SerializeStruct::skip_field),
|
||||
);
|
||||
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
@@ -394,6 +400,19 @@ fn serialize_externally_tagged_variant(
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
let variant_name = variant.attrs.name().serialize_name();
|
||||
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
return quote_expr! {
|
||||
_serde::Serializer::serialize_newtype_variant(
|
||||
__serializer,
|
||||
#type_name,
|
||||
#variant_index,
|
||||
#variant_name,
|
||||
#ser,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
match variant.style {
|
||||
Style::Unit => {
|
||||
quote_expr! {
|
||||
@@ -409,7 +428,7 @@ fn serialize_externally_tagged_variant(
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -459,6 +478,20 @@ fn serialize_internally_tagged_variant(
|
||||
let enum_ident_str = params.type_name();
|
||||
let variant_ident_str = variant.ident.as_ref();
|
||||
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
return quote_expr! {
|
||||
_serde::private::ser::serialize_tagged_newtype(
|
||||
__serializer,
|
||||
#enum_ident_str,
|
||||
#variant_ident_str,
|
||||
#tag,
|
||||
#variant_name,
|
||||
#ser,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
match variant.style {
|
||||
Style::Unit => {
|
||||
quote_block! {
|
||||
@@ -473,7 +506,7 @@ fn serialize_internally_tagged_variant(
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -514,44 +547,57 @@ fn serialize_adjacently_tagged_variant(
|
||||
let variant_name = variant.attrs.name().serialize_name();
|
||||
|
||||
let inner = Stmts(
|
||||
match variant.style {
|
||||
Style::Unit => {
|
||||
return quote_block! {
|
||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
||||
__serializer, #type_name, 1));
|
||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
||||
&mut __struct, #tag, #variant_name));
|
||||
_serde::ser::SerializeStruct::end(__struct)
|
||||
};
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
quote_expr! {
|
||||
_serde::Serialize::serialize(#ser, __serializer)
|
||||
}
|
||||
Style::Newtype => {
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
} else {
|
||||
match variant.style {
|
||||
Style::Unit => {
|
||||
return quote_block! {
|
||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
||||
__serializer, #type_name, 1));
|
||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
||||
&mut __struct, #tag, #variant_name));
|
||||
_serde::ser::SerializeStruct::end(__struct)
|
||||
};
|
||||
}
|
||||
Style::Newtype => {
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
_serde::Serialize::serialize(#field_expr, __serializer)
|
||||
quote_expr! {
|
||||
_serde::Serialize::serialize(#field_expr, __serializer)
|
||||
}
|
||||
}
|
||||
Style::Tuple => {
|
||||
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
|
||||
}
|
||||
Style::Struct => {
|
||||
serialize_struct_variant(
|
||||
StructVariant::Untagged,
|
||||
params,
|
||||
&variant.fields,
|
||||
&variant_name,
|
||||
)
|
||||
}
|
||||
}
|
||||
Style::Tuple => {
|
||||
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
|
||||
}
|
||||
Style::Struct => {
|
||||
serialize_struct_variant(
|
||||
StructVariant::Untagged,
|
||||
params,
|
||||
&variant.fields,
|
||||
&variant_name,
|
||||
)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let fields_ty = variant.fields.iter().map(|f| &f.ty);
|
||||
let ref fields_ident: Vec<_> = match variant.style {
|
||||
Style::Unit => unreachable!(),
|
||||
Style::Unit => {
|
||||
if variant.attrs.serialize_with().is_some() {
|
||||
vec![]
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
Style::Newtype => vec![Ident::new("__field0")],
|
||||
Style::Tuple => {
|
||||
(0..variant.fields.len())
|
||||
@@ -575,7 +621,11 @@ fn serialize_adjacently_tagged_variant(
|
||||
|
||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
|
||||
let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a");
|
||||
let wrapper_generics = if let Style::Unit = variant.style {
|
||||
params.generics.clone()
|
||||
} else {
|
||||
bound::with_lifetime_bound(¶ms.generics, "'__a")
|
||||
};
|
||||
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
||||
|
||||
quote_block! {
|
||||
@@ -611,6 +661,13 @@ fn serialize_untagged_variant(
|
||||
variant: &Variant,
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, &variant);
|
||||
return quote_expr! {
|
||||
_serde::Serialize::serialize(#ser, __serializer)
|
||||
};
|
||||
}
|
||||
|
||||
match variant.style {
|
||||
Style::Unit => {
|
||||
quote_expr! {
|
||||
@@ -621,7 +678,7 @@ fn serialize_untagged_variant(
|
||||
let field = &variant.fields[0];
|
||||
let mut field_expr = quote!(__field0);
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
@@ -706,15 +763,23 @@ fn serialize_struct_variant<'a>(
|
||||
fields: &[Field],
|
||||
name: &str,
|
||||
) -> Fragment {
|
||||
let method = match context {
|
||||
let (method, skip_method) = match context {
|
||||
StructVariant::ExternallyTagged { .. } => {
|
||||
quote!(_serde::ser::SerializeStructVariant::serialize_field)
|
||||
(
|
||||
quote!(_serde::ser::SerializeStructVariant::serialize_field),
|
||||
quote!(_serde::ser::SerializeStructVariant::skip_field),
|
||||
)
|
||||
}
|
||||
StructVariant::InternallyTagged { .. } |
|
||||
StructVariant::Untagged => quote!(_serde::ser::SerializeStruct::serialize_field),
|
||||
StructVariant::Untagged => {
|
||||
(
|
||||
quote!(_serde::ser::SerializeStruct::serialize_field),
|
||||
quote!(_serde::ser::SerializeStruct::skip_field),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let serialize_fields = serialize_struct_visitor(fields, params, true, method);
|
||||
let serialize_fields = serialize_struct_visitor(fields, params, true, method, skip_method);
|
||||
|
||||
let mut serialized_fields = fields
|
||||
.iter()
|
||||
@@ -807,7 +872,7 @@ fn serialize_tuple_struct_visitor(
|
||||
.map(|path| quote!(#path(#field_expr)));
|
||||
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr);
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
let ser = quote! {
|
||||
@@ -828,6 +893,7 @@ fn serialize_struct_visitor(
|
||||
params: &Parameters,
|
||||
is_enum: bool,
|
||||
func: Tokens,
|
||||
skip_func: Tokens,
|
||||
) -> Vec<Tokens> {
|
||||
fields
|
||||
.iter()
|
||||
@@ -849,7 +915,7 @@ fn serialize_struct_visitor(
|
||||
.map(|path| quote!(#path(#field_expr)));
|
||||
|
||||
if let Some(path) = field.attrs.serialize_with() {
|
||||
field_expr = wrap_serialize_with(params, field.ty, path, field_expr)
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
|
||||
}
|
||||
|
||||
let ser = quote! {
|
||||
@@ -858,28 +924,71 @@ fn serialize_struct_visitor(
|
||||
|
||||
match skip {
|
||||
None => ser,
|
||||
Some(skip) => quote!(if !#skip { #ser }),
|
||||
Some(skip) => {
|
||||
quote! {
|
||||
if !#skip {
|
||||
#ser
|
||||
} else {
|
||||
try!(#skip_func(&mut __serde_state, #key_expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn wrap_serialize_with(
|
||||
fn wrap_serialize_field_with(
|
||||
params: &Parameters,
|
||||
field_ty: &syn::Ty,
|
||||
serialize_with: &syn::Path,
|
||||
value: Tokens,
|
||||
field_expr: Tokens,
|
||||
) -> Tokens {
|
||||
wrap_serialize_with(params,
|
||||
serialize_with,
|
||||
&[field_ty],
|
||||
&[quote!(#field_expr)])
|
||||
}
|
||||
|
||||
fn wrap_serialize_variant_with(
|
||||
params: &Parameters,
|
||||
serialize_with: &syn::Path,
|
||||
variant: &Variant,
|
||||
) -> Tokens {
|
||||
let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect();
|
||||
let field_exprs: Vec<_> = variant.fields.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| {
|
||||
let id = field.ident.as_ref().map_or_else(|| Ident::new(format!("__field{}", i)),
|
||||
|id| id.clone());
|
||||
quote!(#id)
|
||||
})
|
||||
.collect();
|
||||
wrap_serialize_with(params, serialize_with, field_tys.as_slice(), field_exprs.as_slice())
|
||||
}
|
||||
|
||||
fn wrap_serialize_with(
|
||||
params: &Parameters,
|
||||
serialize_with: &syn::Path,
|
||||
field_tys: &[&syn::Ty],
|
||||
field_exprs: &[Tokens],
|
||||
) -> Tokens {
|
||||
let this = ¶ms.this;
|
||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
|
||||
let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a");
|
||||
let wrapper_generics = if field_exprs.len() == 0 {
|
||||
params.generics.clone()
|
||||
} else {
|
||||
bound::with_lifetime_bound(¶ms.generics, "'__a")
|
||||
};
|
||||
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
||||
|
||||
let field_access = (0..field_exprs.len()).map(|n| Ident::new(format!("{}", n)));
|
||||
|
||||
quote!({
|
||||
struct __SerializeWith #wrapper_impl_generics #where_clause {
|
||||
value: &'__a #field_ty,
|
||||
values: (#(&'__a #field_tys, )*),
|
||||
phantom: _serde::export::PhantomData<#this #ty_generics>,
|
||||
}
|
||||
|
||||
@@ -887,12 +996,12 @@ fn wrap_serialize_with(
|
||||
fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||
where __S: _serde::Serializer
|
||||
{
|
||||
#serialize_with(self.value, __s)
|
||||
#serialize_with(#(self.values.#field_access, )* __s)
|
||||
}
|
||||
}
|
||||
|
||||
&__SerializeWith {
|
||||
value: #value,
|
||||
values: (#(#field_exprs, )*),
|
||||
phantom: _serde::export::PhantomData::<#this #ty_generics>,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.15.0" # remember to update html_root_url
|
||||
version = "0.16.0" # 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."
|
||||
|
||||
@@ -510,6 +510,8 @@ pub struct Variant {
|
||||
skip_deserializing: bool,
|
||||
skip_serializing: bool,
|
||||
other: bool,
|
||||
serialize_with: Option<syn::Path>,
|
||||
deserialize_with: Option<syn::Path>,
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
@@ -520,6 +522,8 @@ impl Variant {
|
||||
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
||||
let mut rename_all = Attr::none(cx, "rename_all");
|
||||
let mut other = BoolAttr::none(cx, "other");
|
||||
let mut serialize_with = Attr::none(cx, "serialize_with");
|
||||
let mut deserialize_with = Attr::none(cx, "deserialize_with");
|
||||
|
||||
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
for meta_item in meta_items {
|
||||
@@ -569,6 +573,32 @@ impl Variant {
|
||||
other.set_true();
|
||||
}
|
||||
|
||||
// Parse `#[serde(with = "...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
let mut ser_path = path.clone();
|
||||
ser_path.segments.push("serialize".into());
|
||||
serialize_with.set(ser_path);
|
||||
let mut de_path = path;
|
||||
de_path.segments.push("deserialize".into());
|
||||
deserialize_with.set(de_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(serialize_with = "...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
serialize_with.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(deserialize_with = "...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
deserialize_with.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem(ref meta_item) => {
|
||||
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
|
||||
}
|
||||
@@ -595,6 +625,8 @@ impl Variant {
|
||||
skip_deserializing: skip_deserializing.get(),
|
||||
skip_serializing: skip_serializing.get(),
|
||||
other: other.get(),
|
||||
serialize_with: serialize_with.get(),
|
||||
deserialize_with: deserialize_with.get(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,6 +658,14 @@ impl Variant {
|
||||
pub fn other(&self) -> bool {
|
||||
self.other
|
||||
}
|
||||
|
||||
pub fn serialize_with(&self) -> Option<&syn::Path> {
|
||||
self.serialize_with.as_ref()
|
||||
}
|
||||
|
||||
pub fn deserialize_with(&self) -> Option<&syn::Path> {
|
||||
self.deserialize_with.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents field attribute information
|
||||
@@ -719,6 +759,12 @@ impl Field {
|
||||
skip_deserializing.set_true();
|
||||
}
|
||||
|
||||
// Parse `#[serde(skip)]`
|
||||
MetaItem(Word(ref name)) if name == "skip" => {
|
||||
skip_serializing.set_true();
|
||||
skip_deserializing.set_true();
|
||||
},
|
||||
|
||||
// Parse `#[serde(skip_serializing_if = "...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "skip_serializing_if" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
|
||||
@@ -27,6 +27,8 @@ pub enum RenameRule {
|
||||
ScreamingSnakeCase,
|
||||
/// Rename direct children to "kebab-case" style.
|
||||
KebabCase,
|
||||
/// Rename direct children to "SCREAMING-KEBAB-CASE" style.
|
||||
ScreamingKebabCase
|
||||
}
|
||||
|
||||
impl RenameRule {
|
||||
@@ -47,6 +49,7 @@ impl RenameRule {
|
||||
}
|
||||
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
|
||||
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
|
||||
ScreamingKebabCase => ScreamingSnakeCase.apply_to_variant(variant).replace('_', "-")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +77,7 @@ impl RenameRule {
|
||||
}
|
||||
ScreamingSnakeCase => field.to_ascii_uppercase(),
|
||||
KebabCase => field.replace('_', "-"),
|
||||
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,6 +93,7 @@ impl FromStr for RenameRule {
|
||||
"snake_case" => Ok(SnakeCase),
|
||||
"SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
|
||||
"kebab-case" => Ok(KebabCase),
|
||||
"SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
@@ -96,12 +101,12 @@ impl FromStr for RenameRule {
|
||||
|
||||
#[test]
|
||||
fn rename_variants() {
|
||||
for &(original, lower, camel, snake, screaming, kebab) in
|
||||
for &(original, lower, camel, snake, screaming, kebab, screaming_kebab) in
|
||||
&[
|
||||
("Outcome", "outcome", "outcome", "outcome", "OUTCOME", "outcome"),
|
||||
("VeryTasty", "verytasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty"),
|
||||
("A", "a", "a", "a", "A", "a"),
|
||||
("Z42", "z42", "z42", "z42", "Z42", "z42"),
|
||||
("Outcome", "outcome", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"),
|
||||
("VeryTasty", "verytasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"),
|
||||
("A", "a", "a", "a", "A", "a", "A"),
|
||||
("Z42", "z42", "z42", "z42", "Z42", "z42", "Z42"),
|
||||
] {
|
||||
assert_eq!(None.apply_to_variant(original), original);
|
||||
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
||||
@@ -110,17 +115,18 @@ fn rename_variants() {
|
||||
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
||||
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
|
||||
assert_eq!(KebabCase.apply_to_variant(original), kebab);
|
||||
assert_eq!(ScreamingKebabCase.apply_to_variant(original), screaming_kebab);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_fields() {
|
||||
for &(original, pascal, camel, screaming, kebab) in
|
||||
for &(original, pascal, camel, screaming, kebab, screaming_kebab) in
|
||||
&[
|
||||
("outcome", "Outcome", "outcome", "OUTCOME", "outcome"),
|
||||
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty"),
|
||||
("a", "A", "a", "A", "a"),
|
||||
("z42", "Z42", "z42", "Z42", "z42"),
|
||||
("outcome", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME"),
|
||||
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty", "VERY-TASTY"),
|
||||
("a", "A", "a", "A", "a", "A"),
|
||||
("z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
||||
] {
|
||||
assert_eq!(None.apply_to_field(original), original);
|
||||
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
||||
@@ -128,5 +134,6 @@ fn rename_fields() {
|
||||
assert_eq!(SnakeCase.apply_to_field(original), original);
|
||||
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
|
||||
assert_eq!(KebabCase.apply_to_field(original), kebab);
|
||||
assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ use Ctxt;
|
||||
pub fn check(cx: &Ctxt, cont: &Container) {
|
||||
check_getter(cx, cont);
|
||||
check_identifier(cx, cont);
|
||||
check_variant_skip_attrs(cx, cont);
|
||||
}
|
||||
|
||||
/// Getters are only allowed inside structs (not enums) with the `remote`
|
||||
@@ -94,3 +95,58 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Skip-(de)serializing attributes are not allowed on variants marked
|
||||
/// (de)serialize_with.
|
||||
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
||||
let variants = match cont.body {
|
||||
Body::Enum(ref variants) => variants,
|
||||
Body::Struct(_, _) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
for variant in variants.iter() {
|
||||
if variant.attrs.serialize_with().is_some() {
|
||||
if variant.attrs.skip_serializing() {
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||
#[serde(skip_serializing)]", variant.ident));
|
||||
}
|
||||
|
||||
for (i, field) in variant.fields.iter().enumerate() {
|
||||
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i),
|
||||
|ident| format!("`{}`", ident));
|
||||
|
||||
if field.attrs.skip_serializing() {
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||
a field {} marked with #[serde(skip_serializing)]",
|
||||
variant.ident, ident));
|
||||
}
|
||||
|
||||
if field.attrs.skip_serializing_if().is_some() {
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||
a field {} marked with #[serde(skip_serializing_if)]",
|
||||
variant.ident, ident));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if variant.attrs.deserialize_with().is_some() {
|
||||
if variant.attrs.skip_deserializing() {
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] and \
|
||||
#[serde(skip_deserializing)]", variant.ident));
|
||||
}
|
||||
|
||||
for (i, field) in variant.fields.iter().enumerate() {
|
||||
if field.attrs.skip_deserializing() {
|
||||
let ident = field.ident.as_ref().map_or_else(|| format!("{}", i),
|
||||
|ident| format!("`{}`", ident));
|
||||
|
||||
cx.error(format!("variant `{}` cannot have both #[serde(deserialize_with)] \
|
||||
and a field {} marked with #[serde(skip_deserializing)]",
|
||||
variant.ident, ident));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// 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.15.0")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.16.0")]
|
||||
|
||||
extern crate syn;
|
||||
#[macro_use]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_test"
|
||||
version = "1.0.5" # remember to update html_root_url
|
||||
version = "1.0.13" # 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"
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.5")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.13")]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
||||
@@ -10,7 +10,7 @@ unstable = ["serde/unstable", "compiletest_rs"]
|
||||
[dev-dependencies]
|
||||
fnv = "1.0"
|
||||
rustc-serialize = "0.3.16"
|
||||
serde = { path = "../serde" }
|
||||
serde = { path = "../serde", features = ["rc"] }
|
||||
serde_derive = { path = "../serde_derive" }
|
||||
serde_test = { path = "../serde_test" }
|
||||
|
||||
|
||||
@@ -4,5 +4,8 @@ version = "0.0.0"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
libc = { version = "0.2", default-features = false }
|
||||
serde = { path = "../../serde", default-features = false }
|
||||
serde_derive = { path = "../../serde_derive" }
|
||||
|
||||
[workspace]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![feature(lang_items, start, libc, compiler_builtins_lib)]
|
||||
#![feature(lang_items, start, compiler_builtins_lib)]
|
||||
#![no_std]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
@@ -18,7 +18,9 @@ mod remote {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "remote::S")]
|
||||
struct S {
|
||||
b: u8, //~^^^ ERROR: no field `b` on type `&remote::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`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Newtype` cannot have both #[serde(deserialize_with)] and a field 0 marked with #[serde(skip_deserializing)]
|
||||
enum Enum {
|
||||
#[serde(deserialize_with = "deserialize_some_newtype_variant")]
|
||||
Newtype(#[serde(skip_deserializing)] String),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,23 @@
|
||||
// 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)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Struct` cannot have both #[serde(deserialize_with)] and a field `f1` marked with #[serde(skip_deserializing)]
|
||||
enum Enum {
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
Struct {
|
||||
#[serde(skip_deserializing)]
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Tuple` cannot have both #[serde(deserialize_with)] and a field 0 marked with #[serde(skip_deserializing)]
|
||||
enum Enum {
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
Tuple(#[serde(skip_deserializing)] String, u8),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Unit` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]
|
||||
enum Enum {
|
||||
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||
#[serde(skip_deserializing)]
|
||||
Unit,
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Newtype` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||
Newtype(#[serde(skip_serializing)] String),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Newtype` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing_if)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||
Newtype(#[serde(skip_serializing_if = "always")] String),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,23 @@
|
||||
// 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)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
Struct {
|
||||
#[serde(skip_serializing)]
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,23 @@
|
||||
// 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)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing_if)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||
Struct {
|
||||
#[serde(skip_serializing_if = "always")]
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Tuple` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
Tuple(#[serde(skip_serializing)] String, u8),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Tuple` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing_if)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
Tuple(#[serde(skip_serializing_if = "always")] String, u8),
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: variant `Unit` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]
|
||||
enum Enum {
|
||||
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||
#[serde(skip_serializing)]
|
||||
Unit,
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
@@ -13,7 +13,7 @@ extern crate compiletest_rs as compiletest;
|
||||
use std::env;
|
||||
|
||||
fn run_mode(mode: &'static str) {
|
||||
let mut config = compiletest::default_config();
|
||||
let mut config = compiletest::Config::default();
|
||||
|
||||
config.mode = mode.parse().expect("invalid mode");
|
||||
config.target_rustcflags = Some("-L deps/target/debug/deps".to_owned());
|
||||
|
||||
@@ -6,11 +6,14 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
extern crate serde;
|
||||
use self::serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||
use self::serde::de::{self, Unexpected};
|
||||
|
||||
extern crate serde_test;
|
||||
use self::serde_test::{Token, assert_tokens, assert_ser_tokens, assert_de_tokens,
|
||||
@@ -580,6 +583,41 @@ fn test_skip_serializing_struct() {
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
struct SkipStruct<B>
|
||||
{
|
||||
a: i8,
|
||||
#[serde(skip)]
|
||||
b: B,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_skip_struct() {
|
||||
assert_ser_tokens(
|
||||
&SkipStruct { a: 1, b: 2 },
|
||||
&[
|
||||
Token::Struct { name: "SkipStruct", len: 1 },
|
||||
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&SkipStruct { a: 1, b: 0 },
|
||||
&[
|
||||
Token::Struct { name: "SkipStruct", len: 1 },
|
||||
|
||||
Token::Str("a"),
|
||||
Token::I8(1),
|
||||
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize)]
|
||||
enum SkipSerializingEnum<'a, B, C>
|
||||
where
|
||||
@@ -776,6 +814,145 @@ fn test_serialize_with_enum() {
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
enum WithVariant {
|
||||
#[serde(serialize_with="serialize_unit_variant_as_i8")]
|
||||
#[serde(deserialize_with="deserialize_i8_as_unit_variant")]
|
||||
Unit,
|
||||
|
||||
#[serde(serialize_with="SerializeWith::serialize_with")]
|
||||
#[serde(deserialize_with="DeserializeWith::deserialize_with")]
|
||||
Newtype(i32),
|
||||
|
||||
#[serde(serialize_with="serialize_variant_as_string")]
|
||||
#[serde(deserialize_with="deserialize_string_as_variant")]
|
||||
Tuple(String, u8),
|
||||
|
||||
#[serde(serialize_with="serialize_variant_as_string")]
|
||||
#[serde(deserialize_with="deserialize_string_as_variant")]
|
||||
Struct {
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
}
|
||||
|
||||
fn serialize_unit_variant_as_i8<S>(serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
serializer.serialize_i8(0)
|
||||
}
|
||||
|
||||
fn deserialize_i8_as_unit_variant<'de, D>(deserializer: D) -> Result<(), D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
let n = i8::deserialize(deserializer)?;
|
||||
match n {
|
||||
0 => Ok(()),
|
||||
_ => Err(de::Error::invalid_value(Unexpected::Signed(n as i64), &"0")),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_variant_as_string<S>(f1: &str,
|
||||
f2: &u8,
|
||||
serializer: S)
|
||||
-> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(format!("{};{:?}", f1, f2).as_str())
|
||||
}
|
||||
|
||||
fn deserialize_string_as_variant<'de, D>(deserializer: D) -> Result<(String, u8), D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
let mut pieces = s.split(';');
|
||||
let f1 = match pieces.next() {
|
||||
Some(x) => x,
|
||||
None => return Err(de::Error::invalid_length(0, &"2")),
|
||||
};
|
||||
let f2 = match pieces.next() {
|
||||
Some(x) => x,
|
||||
None => return Err(de::Error::invalid_length(1, &"2")),
|
||||
};
|
||||
let f2 = match f2.parse() {
|
||||
Ok(n) => n,
|
||||
Err(_) => {
|
||||
return Err(de::Error::invalid_value(Unexpected::Str(f2), &"an 8-bit signed integer"));
|
||||
}
|
||||
};
|
||||
Ok((f1.into(), f2))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_with_variant() {
|
||||
assert_ser_tokens(
|
||||
&WithVariant::Unit,
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Unit" },
|
||||
Token::I8(0),
|
||||
],
|
||||
);
|
||||
|
||||
assert_ser_tokens(
|
||||
&WithVariant::Newtype(123),
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Newtype" },
|
||||
Token::Bool(true),
|
||||
],
|
||||
);
|
||||
|
||||
assert_ser_tokens(
|
||||
&WithVariant::Tuple("hello".into(), 0),
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Tuple" },
|
||||
Token::Str("hello;0"),
|
||||
],
|
||||
);
|
||||
|
||||
assert_ser_tokens(
|
||||
&WithVariant::Struct { f1: "world".into(), f2: 1 },
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Struct" },
|
||||
Token::Str("world;1"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_with_variant() {
|
||||
assert_de_tokens(
|
||||
&WithVariant::Unit,
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Unit" },
|
||||
Token::I8(0),
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&WithVariant::Newtype(123),
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Newtype" },
|
||||
Token::Bool(true),
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&WithVariant::Tuple("hello".into(), 0),
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Tuple" },
|
||||
Token::Str("hello;0"),
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&WithVariant::Struct { f1: "world".into(), f2: 1 },
|
||||
&[
|
||||
Token::NewtypeVariant { name: "WithVariant", variant: "Struct" },
|
||||
Token::Str("world;1"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
struct DeserializeWithStruct<B>
|
||||
where
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(feature = "unstable", feature(into_boxed_c_str))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::net;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
use std::default::Default;
|
||||
use std::ffi::{CString, OsString};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
use std::ffi::CStr;
|
||||
@@ -521,6 +521,15 @@ declare_tests! {
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::U32(0),
|
||||
Token::I32(1),
|
||||
|
||||
Token::U32(1),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Struct { a: 1, b: 2, c: 0 } => &[
|
||||
Token::Struct { name: "Struct", len: 3 },
|
||||
Token::Str("a"),
|
||||
@@ -682,6 +691,23 @@ declare_tests! {
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_system_time {
|
||||
UNIX_EPOCH + Duration::new(1, 2) => &[
|
||||
Token::Struct { name: "SystemTime", len: 2 },
|
||||
Token::Str("secs_since_epoch"),
|
||||
Token::U64(1),
|
||||
|
||||
Token::Str("nanos_since_epoch"),
|
||||
Token::U32(2),
|
||||
Token::StructEnd,
|
||||
],
|
||||
UNIX_EPOCH + Duration::new(1, 2) => &[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::I64(1),
|
||||
Token::I64(2),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_range {
|
||||
1u32..2u32 => &[
|
||||
Token::Struct { name: "Range", len: 2 },
|
||||
@@ -725,6 +751,40 @@ declare_tests! {
|
||||
Token::Bytes(b"abc"),
|
||||
],
|
||||
}
|
||||
test_rc {
|
||||
Rc::new(true) => &[
|
||||
Token::Bool(true),
|
||||
],
|
||||
}
|
||||
test_arc {
|
||||
Arc::new(true) => &[
|
||||
Token::Bool(true),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
declare_tests! {
|
||||
test_rc_dst {
|
||||
Rc::<str>::from("s") => &[
|
||||
Token::Str("s"),
|
||||
],
|
||||
Rc::<[bool]>::from(&[true][..]) => &[
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::Bool(true),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_arc_dst {
|
||||
Arc::<str>::from("s") => &[
|
||||
Token::Str("s"),
|
||||
],
|
||||
Arc::<[bool]>::from(&[true][..]) => &[
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::Bool(true),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
|
||||
@@ -330,6 +330,167 @@ fn test_gen() {
|
||||
struct EmptyArray {
|
||||
empty: [X; 0],
|
||||
}
|
||||
|
||||
enum Or<A, B> {
|
||||
A(A),
|
||||
B(B),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(untagged, remote = "Or")]
|
||||
enum OrDef<A, B> {
|
||||
#[allow(dead_code)]
|
||||
A(A),
|
||||
#[allow(dead_code)]
|
||||
B(B),
|
||||
}
|
||||
|
||||
struct Str<'a>(&'a str);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "Str")]
|
||||
struct StrDef<'a>(&'a str);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Remote<'a> {
|
||||
#[serde(with = "OrDef")]
|
||||
or: Or<u8, bool>,
|
||||
#[serde(borrow, with = "StrDef")]
|
||||
s: Str<'a>,
|
||||
}
|
||||
|
||||
mod vis {
|
||||
pub struct S;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "S")]
|
||||
pub struct SDef;
|
||||
}
|
||||
|
||||
// This would not work if SDef::serialize / deserialize are private.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct RemoteVisibility {
|
||||
#[serde(with = "vis::SDef")]
|
||||
s: vis::S,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum ExternallyTaggedVariantWith {
|
||||
#[allow(dead_code)]
|
||||
Normal { f1: String },
|
||||
|
||||
#[serde(serialize_with = "ser_x")]
|
||||
#[serde(deserialize_with = "de_x")]
|
||||
#[allow(dead_code)]
|
||||
Newtype(X),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Tuple(String, u8),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Struct {
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
|
||||
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||
#[allow(dead_code)]
|
||||
Unit,
|
||||
}
|
||||
assert_ser::<ExternallyTaggedVariantWith>();
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(tag = "t")]
|
||||
enum InternallyTaggedVariantWith {
|
||||
#[allow(dead_code)]
|
||||
Normal { f1: String },
|
||||
|
||||
#[serde(serialize_with = "ser_x")]
|
||||
#[serde(deserialize_with = "de_x")]
|
||||
#[allow(dead_code)]
|
||||
Newtype(X),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Struct {
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
|
||||
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||
#[allow(dead_code)]
|
||||
Unit,
|
||||
}
|
||||
assert_ser::<InternallyTaggedVariantWith>();
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(tag = "t", content = "c")]
|
||||
enum AdjacentlyTaggedVariantWith {
|
||||
#[allow(dead_code)]
|
||||
Normal { f1: String },
|
||||
|
||||
#[serde(serialize_with = "ser_x")]
|
||||
#[serde(deserialize_with = "de_x")]
|
||||
#[allow(dead_code)]
|
||||
Newtype(X),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Tuple(String, u8),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Struct {
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
|
||||
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||
#[allow(dead_code)]
|
||||
Unit,
|
||||
}
|
||||
assert_ser::<AdjacentlyTaggedVariantWith>();
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum UntaggedVariantWith {
|
||||
#[allow(dead_code)]
|
||||
Normal { f1: String },
|
||||
|
||||
#[serde(serialize_with = "ser_x")]
|
||||
#[serde(deserialize_with = "de_x")]
|
||||
#[allow(dead_code)]
|
||||
Newtype(X),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Tuple(String, u8),
|
||||
|
||||
#[serde(serialize_with = "serialize_some_other_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||
#[allow(dead_code)]
|
||||
Struct {
|
||||
f1: String,
|
||||
f2: u8,
|
||||
},
|
||||
|
||||
#[serde(serialize_with = "serialize_some_unit_variant")]
|
||||
#[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||
#[allow(dead_code)]
|
||||
Unit,
|
||||
}
|
||||
assert_ser::<UntaggedVariantWith>();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -371,3 +532,29 @@ impl DeserializeWith for X {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize_some_unit_variant<S>(_: S) -> StdResult<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn deserialize_some_unit_variant<'de, D>(_: D) -> StdResult<(), D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn serialize_some_other_variant<S>(_: &str, _: &u8, _: S) -> StdResult<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn deserialize_some_other_variant<'de, D>(_: D) -> StdResult<(String, u8), D::Error>
|
||||
where D: Deserializer<'de>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn is_zero(n: &u8) -> bool { *n == 0 }
|
||||
|
||||
@@ -23,7 +23,10 @@ fn test_variant_identifier() {
|
||||
Bbb,
|
||||
}
|
||||
|
||||
assert_de_tokens(&V::Aaa, &[Token::U8(0)]);
|
||||
assert_de_tokens(&V::Aaa, &[Token::U16(0)]);
|
||||
assert_de_tokens(&V::Aaa, &[Token::U32(0)]);
|
||||
assert_de_tokens(&V::Aaa, &[Token::U64(0)]);
|
||||
assert_de_tokens(&V::Aaa, &[Token::Str("Aaa")]);
|
||||
assert_de_tokens(&V::Aaa, &[Token::Bytes(b"Aaa")]);
|
||||
}
|
||||
|
||||
@@ -1149,7 +1149,7 @@ fn test_rename_all() {
|
||||
SerializeMap {
|
||||
serialize: bool,
|
||||
serialize_seq: bool,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
@@ -1159,6 +1159,13 @@ fn test_rename_all() {
|
||||
serialize_seq: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename_all = "SCREAMING-KEBAB-CASE")]
|
||||
struct ScreamingKebab {
|
||||
serialize: bool,
|
||||
serialize_seq: bool,
|
||||
}
|
||||
|
||||
assert_tokens(
|
||||
&E::Serialize {
|
||||
serialize: true,
|
||||
@@ -1218,4 +1225,19 @@ fn test_rename_all() {
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&ScreamingKebab {
|
||||
serialize: true,
|
||||
serialize_seq: true,
|
||||
},
|
||||
&[
|
||||
Token::Struct { name: "ScreamingKebab", len: 2 },
|
||||
Token::Str("SERIALIZE"),
|
||||
Token::Bool(true),
|
||||
Token::Str("SERIALIZE-SEQ"),
|
||||
Token::Bool(true),
|
||||
Token::StructEnd,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::net;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
use std::ffi::CString;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::str;
|
||||
@@ -170,6 +172,17 @@ declare_tests! {
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_btreeset {
|
||||
BTreeSet::<isize>::new() => &[
|
||||
Token::Seq { len: Some(0) },
|
||||
Token::SeqEnd,
|
||||
],
|
||||
btreeset![1] => &[
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::I32(1),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_hashset {
|
||||
HashSet::<isize>::new() => &[
|
||||
Token::Seq { len: Some(0) },
|
||||
@@ -319,6 +332,17 @@ declare_tests! {
|
||||
Token::StructEnd,
|
||||
],
|
||||
}
|
||||
test_system_time {
|
||||
UNIX_EPOCH + Duration::new(1, 200) => &[
|
||||
Token::Struct { name: "SystemTime", len: 2 },
|
||||
Token::Str("secs_since_epoch"),
|
||||
Token::U64(1),
|
||||
|
||||
Token::Str("nanos_since_epoch"),
|
||||
Token::U32(200),
|
||||
Token::StructEnd,
|
||||
],
|
||||
}
|
||||
test_range {
|
||||
1u32..2u32 => &[
|
||||
Token::Struct { name: "Range", len: 2 },
|
||||
@@ -361,6 +385,41 @@ declare_tests! {
|
||||
Token::Bytes(b"abc"),
|
||||
],
|
||||
}
|
||||
test_rc {
|
||||
Rc::new(true) => &[
|
||||
Token::Bool(true),
|
||||
],
|
||||
}
|
||||
test_arc {
|
||||
Arc::new(true) => &[
|
||||
Token::Bool(true),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
// Serde's implementation is not unstable, but the constructors are.
|
||||
#[cfg(feature = "unstable")]
|
||||
declare_tests! {
|
||||
test_rc_dst {
|
||||
Rc::<str>::from("s") => &[
|
||||
Token::Str("s"),
|
||||
],
|
||||
Rc::<[bool]>::from(&[true][..]) => &[
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::Bool(true),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
test_arc_dst {
|
||||
Arc::<str>::from("s") => &[
|
||||
Token::Str("s"),
|
||||
],
|
||||
Arc::<[bool]>::from(&[true][..]) => &[
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::Bool(true),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
|
||||
@@ -41,21 +41,24 @@ if [ -n "${CLIPPY}" ]; then
|
||||
cargo clippy -- -Dclippy
|
||||
else
|
||||
CHANNEL=nightly
|
||||
cd "$DIR"
|
||||
cargo clean
|
||||
cd "$DIR/serde"
|
||||
channel build
|
||||
channel build --no-default-features
|
||||
channel build --no-default-features --features alloc
|
||||
channel build --no-default-features --features collections
|
||||
channel test --features 'rc unstable'
|
||||
cd "$DIR/test_suite/deps"
|
||||
channel build
|
||||
cd "$DIR/test_suite"
|
||||
channel test --features unstable
|
||||
cd "$DIR/test_suite/no_std"
|
||||
channel build
|
||||
if [ -z "${APPVEYOR}" ]; then
|
||||
cd "$DIR/test_suite/no_std"
|
||||
channel build
|
||||
fi
|
||||
|
||||
CHANNEL=beta
|
||||
cd "$DIR"
|
||||
cargo clean
|
||||
cd "$DIR/serde"
|
||||
channel build --features rc
|
||||
@@ -63,6 +66,7 @@ else
|
||||
channel test
|
||||
|
||||
CHANNEL=stable
|
||||
cd "$DIR"
|
||||
cargo clean
|
||||
cd "$DIR/serde"
|
||||
channel build --features rc
|
||||
@@ -72,6 +76,7 @@ else
|
||||
channel test
|
||||
|
||||
CHANNEL=1.13.0
|
||||
cd "$DIR"
|
||||
cargo clean
|
||||
cd "$DIR/serde"
|
||||
channel build --features rc
|
||||
|
||||
Reference in New Issue
Block a user