2017-04-13 19:34:42 -05:00
|
|
|
// 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.
|
|
|
|
|
2017-09-09 13:08:19 -05:00
|
|
|
#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
|
|
|
|
|
2017-02-24 17:32:13 -06:00
|
|
|
#[macro_use]
|
|
|
|
extern crate serde_derive;
|
|
|
|
|
2016-04-24 12:59:57 -05:00
|
|
|
extern crate serde;
|
2018-03-14 12:46:47 -05:00
|
|
|
use std::collections::HashMap;
|
2017-12-23 22:13:08 -06:00
|
|
|
use self::serde::{Deserialize, Deserializer, Serialize, Serializer};
|
2017-08-14 16:39:29 -05:00
|
|
|
use self::serde::de::{self, Unexpected};
|
2016-02-15 19:39:46 -06:00
|
|
|
|
2016-06-28 23:47:54 -05:00
|
|
|
extern crate serde_test;
|
2017-12-23 22:13:08 -06:00
|
|
|
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_tokens,
|
|
|
|
Token};
|
2015-04-02 00:14:28 -05:00
|
|
|
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
trait MyDefault: Sized {
|
2016-02-12 23:53:35 -06:00
|
|
|
fn my_default() -> Self;
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
}
|
2016-02-13 00:05:02 -06:00
|
|
|
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
trait ShouldSkip: Sized {
|
2016-02-13 00:05:02 -06:00
|
|
|
fn should_skip(&self) -> bool;
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
}
|
2016-02-15 19:39:46 -06:00
|
|
|
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
trait SerializeWith: Sized {
|
2017-01-14 18:07:43 -06:00
|
|
|
fn serialize_with<S>(&self, ser: S) -> Result<S::Ok, S::Error>
|
2017-04-13 14:28:23 -05:00
|
|
|
where
|
|
|
|
S: Serializer;
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
}
|
2016-02-15 22:43:11 -06:00
|
|
|
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
trait DeserializeWith: Sized {
|
2017-03-27 00:56:58 -05:00
|
|
|
fn deserialize_with<'de, D>(de: D) -> Result<Self, D::Error>
|
2017-04-13 14:28:23 -05:00
|
|
|
where
|
|
|
|
D: Deserializer<'de>;
|
2016-02-12 23:53:35 -06:00
|
|
|
}
|
|
|
|
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
impl MyDefault for i32 {
|
2017-04-13 14:28:23 -05:00
|
|
|
fn my_default() -> Self {
|
|
|
|
123
|
|
|
|
}
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
}
|
2016-02-13 00:05:02 -06:00
|
|
|
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
impl ShouldSkip for i32 {
|
2017-04-13 14:28:23 -05:00
|
|
|
fn should_skip(&self) -> bool {
|
|
|
|
*self == 123
|
|
|
|
}
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
}
|
2016-02-15 19:39:46 -06:00
|
|
|
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
impl SerializeWith for i32 {
|
2017-01-14 18:07:43 -06:00
|
|
|
fn serialize_with<S>(&self, ser: S) -> Result<S::Ok, S::Error>
|
2017-04-13 14:28:23 -05:00
|
|
|
where
|
|
|
|
S: Serializer,
|
2016-02-15 19:39:46 -06:00
|
|
|
{
|
|
|
|
if *self == 123 {
|
|
|
|
true.serialize(ser)
|
|
|
|
} else {
|
|
|
|
false.serialize(ser)
|
|
|
|
}
|
|
|
|
}
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
}
|
2016-02-15 22:43:11 -06:00
|
|
|
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
impl DeserializeWith for i32 {
|
2017-03-27 00:56:58 -05:00
|
|
|
fn deserialize_with<'de, D>(de: D) -> Result<Self, D::Error>
|
2017-04-13 14:28:23 -05:00
|
|
|
where
|
|
|
|
D: Deserializer<'de>,
|
2016-02-15 22:43:11 -06:00
|
|
|
{
|
|
|
|
if try!(Deserialize::deserialize(de)) {
|
|
|
|
Ok(123)
|
|
|
|
} else {
|
|
|
|
Ok(2)
|
|
|
|
}
|
|
|
|
}
|
2016-02-12 23:53:35 -06:00
|
|
|
}
|
|
|
|
|
2015-04-02 00:14:28 -05:00
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
2016-04-13 02:34:29 -05:00
|
|
|
struct DefaultStruct<A, B, C, D, E>
|
2017-04-13 14:28:23 -05:00
|
|
|
where
|
|
|
|
C: MyDefault,
|
|
|
|
E: MyDefault,
|
2016-04-13 01:42:24 -05:00
|
|
|
{
|
2016-02-12 23:53:35 -06:00
|
|
|
a1: A,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(default)]
|
|
|
|
a2: B,
|
|
|
|
#[serde(default = "MyDefault::my_default")]
|
|
|
|
a3: C,
|
|
|
|
#[serde(skip_deserializing)]
|
|
|
|
a4: D,
|
|
|
|
#[serde(skip_deserializing, default = "MyDefault::my_default")]
|
|
|
|
a5: E,
|
2016-02-12 23:53:35 -06:00
|
|
|
}
|
|
|
|
|
2018-03-14 12:46:47 -05:00
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
struct CollectOther {
|
|
|
|
a: u32,
|
|
|
|
b: u32,
|
2018-03-15 19:26:57 -05:00
|
|
|
#[serde(flatten)]
|
2018-03-14 12:46:47 -05:00
|
|
|
extra: HashMap<String, u32>,
|
|
|
|
}
|
|
|
|
|
2018-03-16 16:40:08 -05:00
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
2018-03-16 16:58:16 -05:00
|
|
|
struct FlattenStructEnumWrapper {
|
2018-03-16 16:40:08 -05:00
|
|
|
#[serde(flatten)]
|
2018-03-16 16:58:16 -05:00
|
|
|
data: FlattenStructEnum,
|
2018-03-16 16:40:08 -05:00
|
|
|
#[serde(flatten)]
|
|
|
|
extra: HashMap<String, String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
#[serde(rename_all = "snake_case")]
|
2018-03-16 16:58:16 -05:00
|
|
|
enum FlattenStructEnum {
|
|
|
|
InsertInteger {
|
|
|
|
index: u32,
|
2018-03-16 16:40:08 -05:00
|
|
|
value: u32
|
|
|
|
},
|
2018-03-16 16:58:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
struct FlattenStructTagContentEnumWrapper {
|
|
|
|
outer: u32,
|
|
|
|
#[serde(flatten)]
|
2018-03-18 07:02:00 -05:00
|
|
|
data: FlattenStructTagContentEnumNewtype,
|
2018-03-16 16:58:16 -05:00
|
|
|
}
|
|
|
|
|
2018-03-18 07:02:00 -05:00
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
struct FlattenStructTagContentEnumNewtype(pub FlattenStructTagContentEnum);
|
|
|
|
|
2018-03-16 16:58:16 -05:00
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
#[serde(rename_all = "snake_case", tag = "type", content = "value")]
|
|
|
|
enum FlattenStructTagContentEnum {
|
2018-03-16 16:40:08 -05:00
|
|
|
InsertInteger {
|
|
|
|
index: u32,
|
|
|
|
value: u32
|
|
|
|
},
|
2018-03-18 07:10:54 -05:00
|
|
|
NewtypeVariant(FlattenStructTagContentEnumNewtypeVariant),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
struct FlattenStructTagContentEnumNewtypeVariant {
|
|
|
|
value: u32,
|
2018-03-16 16:40:08 -05:00
|
|
|
}
|
|
|
|
|
2016-02-12 23:53:35 -06:00
|
|
|
#[test]
|
|
|
|
fn test_default_struct() {
|
|
|
|
assert_de_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&DefaultStruct {
|
2017-12-23 22:13:08 -06:00
|
|
|
a1: 1,
|
|
|
|
a2: 2,
|
|
|
|
a3: 3,
|
|
|
|
a4: 0,
|
|
|
|
a5: 123,
|
|
|
|
},
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "DefaultStruct",
|
|
|
|
len: 3,
|
|
|
|
},
|
2016-02-12 23:53:35 -06:00
|
|
|
Token::Str("a1"),
|
|
|
|
Token::I32(1),
|
|
|
|
Token::Str("a2"),
|
|
|
|
Token::I32(2),
|
|
|
|
Token::Str("a3"),
|
|
|
|
Token::I32(3),
|
2016-04-13 01:42:24 -05:00
|
|
|
Token::Str("a4"),
|
|
|
|
Token::I32(4),
|
|
|
|
Token::Str("a5"),
|
|
|
|
Token::I32(5),
|
2016-02-13 00:05:02 -06:00
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-12 23:53:35 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&DefaultStruct {
|
2017-12-23 22:13:08 -06:00
|
|
|
a1: 1,
|
|
|
|
a2: 0,
|
|
|
|
a3: 123,
|
|
|
|
a4: 0,
|
|
|
|
a5: 123,
|
|
|
|
},
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "DefaultStruct",
|
|
|
|
len: 3,
|
|
|
|
},
|
2016-02-12 23:53:35 -06:00
|
|
|
Token::Str("a1"),
|
|
|
|
Token::I32(1),
|
2016-02-13 00:05:02 -06:00
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-12 23:53:35 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
2016-04-13 02:34:29 -05:00
|
|
|
enum DefaultEnum<A, B, C, D, E>
|
2017-04-13 14:28:23 -05:00
|
|
|
where
|
|
|
|
C: MyDefault,
|
|
|
|
E: MyDefault,
|
2016-04-13 01:42:24 -05:00
|
|
|
{
|
2016-02-12 23:53:35 -06:00
|
|
|
Struct {
|
|
|
|
a1: A,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(default)]
|
|
|
|
a2: B,
|
|
|
|
#[serde(default = "MyDefault::my_default")]
|
|
|
|
a3: C,
|
|
|
|
#[serde(skip_deserializing)]
|
|
|
|
a4: D,
|
|
|
|
#[serde(skip_deserializing, default = "MyDefault::my_default")]
|
|
|
|
a5: E,
|
2017-04-13 14:28:23 -05:00
|
|
|
},
|
2015-04-02 00:14:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2016-02-12 23:53:35 -06:00
|
|
|
fn test_default_enum() {
|
2015-08-27 22:01:09 -05:00
|
|
|
assert_de_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&DefaultEnum::Struct {
|
2017-12-23 22:13:08 -06:00
|
|
|
a1: 1,
|
|
|
|
a2: 2,
|
|
|
|
a3: 3,
|
|
|
|
a4: 0,
|
|
|
|
a5: 123,
|
|
|
|
},
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "DefaultEnum",
|
|
|
|
variant: "Struct",
|
|
|
|
len: 3,
|
|
|
|
},
|
2015-08-27 22:01:09 -05:00
|
|
|
Token::Str("a1"),
|
|
|
|
Token::I32(1),
|
|
|
|
Token::Str("a2"),
|
|
|
|
Token::I32(2),
|
2016-02-12 23:53:35 -06:00
|
|
|
Token::Str("a3"),
|
|
|
|
Token::I32(3),
|
2016-04-13 01:42:24 -05:00
|
|
|
Token::Str("a4"),
|
|
|
|
Token::I32(4),
|
|
|
|
Token::Str("a5"),
|
|
|
|
Token::I32(5),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2015-08-27 22:01:09 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&DefaultEnum::Struct {
|
2017-12-23 22:13:08 -06:00
|
|
|
a1: 1,
|
|
|
|
a2: 0,
|
|
|
|
a3: 123,
|
|
|
|
a4: 0,
|
|
|
|
a5: 123,
|
|
|
|
},
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "DefaultEnum",
|
|
|
|
variant: "Struct",
|
|
|
|
len: 3,
|
|
|
|
},
|
2015-08-27 22:01:09 -05:00
|
|
|
Token::Str("a1"),
|
|
|
|
Token::I32(1),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2015-08-27 22:01:09 -05:00
|
|
|
);
|
2015-04-02 00:14:28 -05:00
|
|
|
}
|
|
|
|
|
2016-04-13 02:34:29 -05:00
|
|
|
// Does not implement std::default::Default.
|
|
|
|
#[derive(Debug, PartialEq, Deserialize)]
|
|
|
|
struct NoStdDefault(i8);
|
|
|
|
|
|
|
|
impl MyDefault for NoStdDefault {
|
|
|
|
fn my_default() -> Self {
|
|
|
|
NoStdDefault(123)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Deserialize)]
|
|
|
|
struct ContainsNoStdDefault<A: MyDefault> {
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(default = "MyDefault::my_default")]
|
|
|
|
a: A,
|
2016-04-13 02:34:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that a struct field does not need to implement std::default::Default if
|
|
|
|
// it is annotated with `default=...`.
|
|
|
|
#[test]
|
|
|
|
fn test_no_std_default() {
|
|
|
|
assert_de_tokens(
|
2017-12-23 22:13:08 -06:00
|
|
|
&ContainsNoStdDefault {
|
|
|
|
a: NoStdDefault(123),
|
|
|
|
},
|
|
|
|
&[
|
|
|
|
Token::Struct {
|
|
|
|
name: "ContainsNoStdDefault",
|
|
|
|
len: 1,
|
|
|
|
},
|
|
|
|
Token::StructEnd,
|
|
|
|
],
|
2016-04-13 02:34:29 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens(
|
|
|
|
&ContainsNoStdDefault { a: NoStdDefault(8) },
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "ContainsNoStdDefault",
|
|
|
|
len: 1,
|
|
|
|
},
|
2016-04-13 02:34:29 -05:00
|
|
|
Token::Str("a"),
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::NewtypeStruct {
|
|
|
|
name: "NoStdDefault",
|
|
|
|
},
|
2016-04-13 02:34:29 -05:00
|
|
|
Token::I8(8),
|
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-04-13 02:34:29 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Does not implement Deserialize.
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
struct NotDeserializeStruct(i8);
|
|
|
|
|
|
|
|
impl Default for NotDeserializeStruct {
|
|
|
|
fn default() -> Self {
|
|
|
|
NotDeserializeStruct(123)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-07 21:57:44 -05:00
|
|
|
impl DeserializeWith for NotDeserializeStruct {
|
2017-03-27 00:56:58 -05:00
|
|
|
fn deserialize_with<'de, D>(_: D) -> Result<Self, D::Error>
|
2017-04-13 14:28:23 -05:00
|
|
|
where
|
|
|
|
D: Deserializer<'de>,
|
2016-05-07 21:57:44 -05:00
|
|
|
{
|
|
|
|
panic!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-13 02:34:29 -05:00
|
|
|
// Does not implement Deserialize.
|
|
|
|
#[derive(Debug, PartialEq)]
|
2017-04-13 14:28:23 -05:00
|
|
|
enum NotDeserializeEnum {
|
|
|
|
Trouble,
|
|
|
|
}
|
2016-04-13 02:34:29 -05:00
|
|
|
|
|
|
|
impl MyDefault for NotDeserializeEnum {
|
|
|
|
fn my_default() -> Self {
|
|
|
|
NotDeserializeEnum::Trouble
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Deserialize)]
|
2016-05-07 21:57:44 -05:00
|
|
|
struct ContainsNotDeserialize<A, B, C: DeserializeWith, E: MyDefault> {
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(skip_deserializing)]
|
|
|
|
a: A,
|
|
|
|
#[serde(skip_deserializing, default)]
|
|
|
|
b: B,
|
|
|
|
#[serde(deserialize_with = "DeserializeWith::deserialize_with", default)]
|
|
|
|
c: C,
|
|
|
|
#[serde(skip_deserializing, default = "MyDefault::my_default")]
|
|
|
|
e: E,
|
2016-04-13 02:34:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that a struct field does not need to implement Deserialize if it is
|
|
|
|
// annotated with skip_deserializing, whether using the std Default or a
|
|
|
|
// custom default.
|
|
|
|
#[test]
|
|
|
|
fn test_elt_not_deserialize() {
|
|
|
|
assert_de_tokens(
|
|
|
|
&ContainsNotDeserialize {
|
2017-12-23 22:13:08 -06:00
|
|
|
a: NotDeserializeStruct(123),
|
|
|
|
b: NotDeserializeStruct(123),
|
|
|
|
c: NotDeserializeStruct(123),
|
|
|
|
e: NotDeserializeEnum::Trouble,
|
|
|
|
},
|
|
|
|
&[
|
|
|
|
Token::Struct {
|
|
|
|
name: "ContainsNotDeserialize",
|
|
|
|
len: 1,
|
|
|
|
},
|
|
|
|
Token::StructEnd,
|
|
|
|
],
|
2016-04-13 02:34:29 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-02-15 18:02:09 -06:00
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
#[serde(deny_unknown_fields)]
|
|
|
|
struct DenyUnknown {
|
|
|
|
a1: i32,
|
|
|
|
}
|
|
|
|
|
2016-01-10 21:34:48 -06:00
|
|
|
#[test]
|
|
|
|
fn test_ignore_unknown() {
|
|
|
|
// 'Default' allows unknown. Basic smoke test of ignore...
|
|
|
|
assert_de_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&DefaultStruct {
|
2017-12-23 22:13:08 -06:00
|
|
|
a1: 1,
|
|
|
|
a2: 2,
|
|
|
|
a3: 3,
|
|
|
|
a4: 0,
|
|
|
|
a5: 123,
|
|
|
|
},
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "DefaultStruct",
|
|
|
|
len: 3,
|
|
|
|
},
|
2016-01-10 21:34:48 -06:00
|
|
|
Token::Str("whoops1"),
|
|
|
|
Token::I32(2),
|
|
|
|
Token::Str("a1"),
|
|
|
|
Token::I32(1),
|
|
|
|
Token::Str("whoops2"),
|
2017-04-19 15:06:31 -05:00
|
|
|
Token::Seq { len: Some(1) },
|
2016-01-10 21:34:48 -06:00
|
|
|
Token::I32(2),
|
|
|
|
Token::SeqEnd,
|
|
|
|
Token::Str("a2"),
|
|
|
|
Token::I32(2),
|
|
|
|
Token::Str("whoops3"),
|
|
|
|
Token::I32(2),
|
2016-02-12 23:53:35 -06:00
|
|
|
Token::Str("a3"),
|
|
|
|
Token::I32(3),
|
2016-02-13 00:05:02 -06:00
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-01-10 21:34:48 -06:00
|
|
|
);
|
|
|
|
|
2016-02-15 18:02:09 -06:00
|
|
|
assert_de_tokens_error::<DenyUnknown>(
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "DenyUnknown",
|
|
|
|
len: 1,
|
|
|
|
},
|
2016-01-10 21:34:48 -06:00
|
|
|
Token::Str("a1"),
|
|
|
|
Token::I32(1),
|
|
|
|
Token::Str("whoops"),
|
|
|
|
],
|
2017-04-19 13:38:57 -05:00
|
|
|
"unknown field `whoops`, expected `a1`",
|
2016-01-10 21:34:48 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-02-15 18:02:09 -06:00
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(rename = "Superhero")]
|
2016-02-15 18:02:09 -06:00
|
|
|
struct RenameStruct {
|
|
|
|
a1: i32,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(rename = "a3")]
|
|
|
|
a2: i32,
|
2016-02-15 18:02:09 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(rename(serialize = "SuperheroSer", deserialize = "SuperheroDe"))]
|
2016-02-15 18:02:09 -06:00
|
|
|
struct RenameStructSerializeDeserialize {
|
|
|
|
a1: i32,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(rename(serialize = "a4", deserialize = "a5"))]
|
|
|
|
a2: i32,
|
2016-02-15 18:02:09 -06:00
|
|
|
}
|
|
|
|
|
2015-04-02 00:14:28 -05:00
|
|
|
#[test]
|
2016-02-08 10:00:38 -06:00
|
|
|
fn test_rename_struct() {
|
2015-08-27 22:01:09 -05:00
|
|
|
assert_tokens(
|
2016-02-08 10:00:38 -06:00
|
|
|
&RenameStruct { a1: 1, a2: 2 },
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "Superhero",
|
|
|
|
len: 2,
|
|
|
|
},
|
2015-08-27 22:01:09 -05:00
|
|
|
Token::Str("a1"),
|
|
|
|
Token::I32(1),
|
|
|
|
Token::Str("a3"),
|
|
|
|
Token::I32(2),
|
2016-02-13 00:05:02 -06:00
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2015-08-27 22:01:09 -05:00
|
|
|
);
|
2015-04-21 09:57:36 -05:00
|
|
|
|
2016-02-08 12:35:42 -06:00
|
|
|
assert_ser_tokens(
|
2016-02-08 10:00:38 -06:00
|
|
|
&RenameStructSerializeDeserialize { a1: 1, a2: 2 },
|
2016-02-08 12:35:42 -06:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "SuperheroSer",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-08 12:35:42 -06:00
|
|
|
Token::Str("a1"),
|
|
|
|
Token::I32(1),
|
|
|
|
Token::Str("a4"),
|
|
|
|
Token::I32(2),
|
2016-02-13 00:05:02 -06:00
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-08 12:35:42 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens(
|
2016-02-08 10:00:38 -06:00
|
|
|
&RenameStructSerializeDeserialize { a1: 1, a2: 2 },
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "SuperheroDe",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-08 12:35:42 -06:00
|
|
|
Token::Str("a1"),
|
|
|
|
Token::I32(1),
|
|
|
|
Token::Str("a5"),
|
|
|
|
Token::I32(2),
|
2016-02-13 00:05:02 -06:00
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-08 12:35:42 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-02-15 18:02:09 -06:00
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(rename = "Superhero")]
|
2016-02-15 18:02:09 -06:00
|
|
|
enum RenameEnum {
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(rename = "bruce_wayne")]
|
|
|
|
Batman,
|
|
|
|
#[serde(rename = "clark_kent")]
|
|
|
|
Superman(i8),
|
|
|
|
#[serde(rename = "diana_prince")]
|
|
|
|
WonderWoman(i8, i8),
|
|
|
|
#[serde(rename = "barry_allan")]
|
|
|
|
Flash {
|
|
|
|
#[serde(rename = "b")]
|
|
|
|
a: i32,
|
|
|
|
},
|
2016-02-15 18:02:09 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(rename(serialize = "SuperheroSer", deserialize = "SuperheroDe"))]
|
2016-02-15 18:02:09 -06:00
|
|
|
enum RenameEnumSerializeDeserialize<A> {
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(rename(serialize = "dick_grayson", deserialize = "jason_todd"))]
|
2016-02-15 18:02:09 -06:00
|
|
|
Robin {
|
|
|
|
a: i8,
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(rename(serialize = "c"))]
|
|
|
|
#[serde(rename(deserialize = "d"))]
|
2016-02-15 18:02:09 -06:00
|
|
|
b: A,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2016-02-08 12:35:42 -06:00
|
|
|
#[test]
|
2016-02-08 10:00:38 -06:00
|
|
|
fn test_rename_enum() {
|
|
|
|
assert_tokens(
|
|
|
|
&RenameEnum::Batman,
|
2017-12-23 22:13:08 -06:00
|
|
|
&[
|
|
|
|
Token::UnitVariant {
|
|
|
|
name: "Superhero",
|
|
|
|
variant: "bruce_wayne",
|
|
|
|
},
|
|
|
|
],
|
2016-02-08 12:35:42 -06:00
|
|
|
);
|
|
|
|
|
2016-02-08 10:00:38 -06:00
|
|
|
assert_tokens(
|
|
|
|
&RenameEnum::Superman(0),
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::NewtypeVariant {
|
|
|
|
name: "Superhero",
|
|
|
|
variant: "clark_kent",
|
|
|
|
},
|
2016-02-08 10:00:38 -06:00
|
|
|
Token::I8(0),
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-08 10:00:38 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_tokens(
|
|
|
|
&RenameEnum::WonderWoman(0, 1),
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::TupleVariant {
|
|
|
|
name: "Superhero",
|
|
|
|
variant: "diana_prince",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-08 10:00:38 -06:00
|
|
|
Token::I8(0),
|
|
|
|
Token::I8(1),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::TupleVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-08 10:00:38 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_tokens(
|
|
|
|
&RenameEnum::Flash { a: 1 },
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "Superhero",
|
|
|
|
variant: "barry_allan",
|
|
|
|
len: 1,
|
|
|
|
},
|
2016-02-08 10:00:38 -06:00
|
|
|
Token::Str("b"),
|
|
|
|
Token::I32(1),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-08 12:35:42 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_ser_tokens(
|
2016-02-08 10:00:38 -06:00
|
|
|
&RenameEnumSerializeDeserialize::Robin {
|
2017-12-23 22:13:08 -06:00
|
|
|
a: 0,
|
|
|
|
b: String::new(),
|
|
|
|
},
|
2016-02-08 12:35:42 -06:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "SuperheroSer",
|
|
|
|
variant: "dick_grayson",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-08 12:35:42 -06:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(0),
|
|
|
|
Token::Str("c"),
|
|
|
|
Token::Str(""),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-08 12:35:42 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens(
|
2016-02-08 10:00:38 -06:00
|
|
|
&RenameEnumSerializeDeserialize::Robin {
|
2017-12-23 22:13:08 -06:00
|
|
|
a: 0,
|
|
|
|
b: String::new(),
|
|
|
|
},
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "SuperheroDe",
|
|
|
|
variant: "jason_todd",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-08 12:35:42 -06:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(0),
|
|
|
|
Token::Str("d"),
|
|
|
|
Token::Str(""),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-08 10:03:46 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-02-15 18:02:09 -06:00
|
|
|
#[derive(Debug, PartialEq, Serialize)]
|
2017-04-13 14:28:23 -05:00
|
|
|
struct SkipSerializingStruct<'a, B, C>
|
|
|
|
where
|
|
|
|
C: ShouldSkip,
|
|
|
|
{
|
2016-02-15 18:02:09 -06:00
|
|
|
a: &'a i8,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(skip_serializing)]
|
|
|
|
b: B,
|
|
|
|
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
|
|
|
|
c: C,
|
2015-07-23 10:07:49 -05:00
|
|
|
}
|
2015-09-07 18:44:56 -05:00
|
|
|
|
|
|
|
#[test]
|
2016-02-15 18:02:09 -06:00
|
|
|
fn test_skip_serializing_struct() {
|
|
|
|
let a = 1;
|
2015-09-07 18:44:56 -05:00
|
|
|
assert_ser_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&SkipSerializingStruct { a: &a, b: 2, c: 3 },
|
2015-09-07 18:44:56 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "SkipSerializingStruct",
|
|
|
|
len: 2,
|
|
|
|
},
|
2015-09-07 18:44:56 -05:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
2016-02-13 00:05:02 -06:00
|
|
|
Token::Str("c"),
|
|
|
|
Token::I32(3),
|
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2015-09-07 18:44:56 -05:00
|
|
|
);
|
|
|
|
|
2016-02-15 18:02:09 -06:00
|
|
|
assert_ser_tokens(
|
|
|
|
&SkipSerializingStruct {
|
2017-12-23 22:13:08 -06:00
|
|
|
a: &a,
|
|
|
|
b: 2,
|
|
|
|
c: 123,
|
|
|
|
},
|
2016-02-15 18:02:09 -06:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "SkipSerializingStruct",
|
|
|
|
len: 1,
|
|
|
|
},
|
2015-09-07 18:44:56 -05:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
2016-02-13 00:05:02 -06:00
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2015-09-07 18:44:56 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-05-16 04:33:26 -05:00
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
2017-12-23 22:13:08 -06:00
|
|
|
struct SkipStruct<B> {
|
2017-05-16 04:33:26 -05:00
|
|
|
a: i8,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(skip)]
|
|
|
|
b: B,
|
2017-05-16 04:33:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_skip_struct() {
|
|
|
|
assert_ser_tokens(
|
|
|
|
&SkipStruct { a: 1, b: 2 },
|
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "SkipStruct",
|
|
|
|
len: 1,
|
|
|
|
},
|
2017-05-16 04:33:26 -05:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
|
|
|
Token::StructEnd,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens(
|
|
|
|
&SkipStruct { a: 1, b: 0 },
|
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "SkipStruct",
|
|
|
|
len: 1,
|
|
|
|
},
|
2017-05-16 04:33:26 -05:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
|
|
|
Token::StructEnd,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-02-15 18:02:09 -06:00
|
|
|
#[derive(Debug, PartialEq, Serialize)]
|
2017-04-13 14:28:23 -05:00
|
|
|
enum SkipSerializingEnum<'a, B, C>
|
|
|
|
where
|
|
|
|
C: ShouldSkip,
|
|
|
|
{
|
2016-02-15 18:02:09 -06:00
|
|
|
Struct {
|
|
|
|
a: &'a i8,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(skip_serializing)]
|
|
|
|
_b: B,
|
|
|
|
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
|
|
|
|
c: C,
|
2017-04-13 14:28:23 -05:00
|
|
|
},
|
2016-02-15 18:02:09 -06:00
|
|
|
}
|
|
|
|
|
2015-09-07 18:44:56 -05:00
|
|
|
#[test]
|
2016-02-15 18:02:09 -06:00
|
|
|
fn test_skip_serializing_enum() {
|
|
|
|
let a = 1;
|
2015-09-07 18:44:56 -05:00
|
|
|
assert_ser_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&SkipSerializingEnum::Struct { a: &a, _b: 2, c: 3 },
|
2015-09-07 18:44:56 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "SkipSerializingEnum",
|
|
|
|
variant: "Struct",
|
|
|
|
len: 2,
|
|
|
|
},
|
2015-09-07 18:44:56 -05:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
2016-02-13 00:05:02 -06:00
|
|
|
Token::Str("c"),
|
|
|
|
Token::I32(3),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2015-09-07 18:44:56 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_ser_tokens(
|
2016-02-15 18:02:09 -06:00
|
|
|
&SkipSerializingEnum::Struct {
|
2017-12-23 22:13:08 -06:00
|
|
|
a: &a,
|
|
|
|
_b: 2,
|
|
|
|
c: 123,
|
|
|
|
},
|
2015-09-07 18:44:56 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "SkipSerializingEnum",
|
|
|
|
variant: "Struct",
|
|
|
|
len: 1,
|
|
|
|
},
|
2015-09-07 18:44:56 -05:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2015-09-07 18:44:56 -05:00
|
|
|
);
|
|
|
|
}
|
2016-02-15 19:39:46 -06:00
|
|
|
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
struct NotSerializeStruct(i8);
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
2017-04-13 14:28:23 -05:00
|
|
|
enum NotSerializeEnum {
|
|
|
|
Trouble,
|
|
|
|
}
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
|
|
|
|
impl SerializeWith for NotSerializeEnum {
|
2017-01-14 18:07:43 -06:00
|
|
|
fn serialize_with<S>(&self, ser: S) -> Result<S::Ok, S::Error>
|
2017-04-13 14:28:23 -05:00
|
|
|
where
|
|
|
|
S: Serializer,
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
{
|
|
|
|
"trouble".serialize(ser)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Serialize)]
|
2017-04-13 14:28:23 -05:00
|
|
|
struct ContainsNotSerialize<'a, B, C, D>
|
|
|
|
where
|
|
|
|
B: 'a,
|
|
|
|
D: SerializeWith,
|
|
|
|
{
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
a: &'a Option<i8>,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(skip_serializing)]
|
|
|
|
b: &'a B,
|
|
|
|
#[serde(skip_serializing)]
|
|
|
|
c: Option<C>,
|
|
|
|
#[serde(serialize_with = "SerializeWith::serialize_with")]
|
|
|
|
d: D,
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_elt_not_serialize() {
|
|
|
|
let a = 1;
|
|
|
|
assert_ser_tokens(
|
|
|
|
&ContainsNotSerialize {
|
2017-12-23 22:13:08 -06:00
|
|
|
a: &Some(a),
|
|
|
|
b: &NotSerializeStruct(2),
|
|
|
|
c: Some(NotSerializeEnum::Trouble),
|
|
|
|
d: NotSerializeEnum::Trouble,
|
|
|
|
},
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "ContainsNotSerialize",
|
|
|
|
len: 2,
|
|
|
|
},
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
Token::Str("a"),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::Some,
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
Token::I8(1),
|
|
|
|
Token::Str("d"),
|
|
|
|
Token::Str("trouble"),
|
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
feat(codegen): Inhibit generic bounds if skip_serializing
The generated code for a struct like:
struct Test<A, B, C> {
a: X<A>
#[serde(skip_serializing)]
b: B
#[serde(serialize_with="...")]
c: C
}
Used to be:
impl<A, B, C> Serialize for Test<A, B, C>
where A: Serialize,
B: Serialize,
C: Serialize,
{ ... }
Now it is:
impl<A, B, C> Serialize for Test<A, B, C>
where X<A>: Serialize,
{ ... }
Both `skip_serializing` and `serialize_with` mean the type does not need to
implement `Serialize`.
2016-02-28 14:17:29 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-02-15 19:39:46 -06:00
|
|
|
#[derive(Debug, PartialEq, Serialize)]
|
2017-04-13 14:28:23 -05:00
|
|
|
struct SerializeWithStruct<'a, B>
|
|
|
|
where
|
|
|
|
B: SerializeWith,
|
|
|
|
{
|
2016-02-15 19:39:46 -06:00
|
|
|
a: &'a i8,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(serialize_with = "SerializeWith::serialize_with")]
|
|
|
|
b: B,
|
2016-02-15 19:39:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_serialize_with_struct() {
|
|
|
|
let a = 1;
|
|
|
|
assert_ser_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&SerializeWithStruct { a: &a, b: 2 },
|
2016-02-15 19:39:46 -06:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "SerializeWithStruct",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-15 19:39:46 -06:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
|
|
|
Token::Str("b"),
|
|
|
|
Token::Bool(false),
|
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-15 19:39:46 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_ser_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&SerializeWithStruct { a: &a, b: 123 },
|
2016-02-15 19:39:46 -06:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "SerializeWithStruct",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-15 19:39:46 -06:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
|
|
|
Token::Str("b"),
|
|
|
|
Token::Bool(true),
|
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-15 19:39:46 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Serialize)]
|
2017-04-13 14:28:23 -05:00
|
|
|
enum SerializeWithEnum<'a, B>
|
|
|
|
where
|
|
|
|
B: SerializeWith,
|
|
|
|
{
|
2016-02-15 19:39:46 -06:00
|
|
|
Struct {
|
|
|
|
a: &'a i8,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(serialize_with = "SerializeWith::serialize_with")]
|
|
|
|
b: B,
|
2017-04-13 14:28:23 -05:00
|
|
|
},
|
2016-02-15 19:39:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_serialize_with_enum() {
|
|
|
|
let a = 1;
|
|
|
|
assert_ser_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&SerializeWithEnum::Struct { a: &a, b: 2 },
|
2016-02-15 19:39:46 -06:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "SerializeWithEnum",
|
|
|
|
variant: "Struct",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-15 19:39:46 -06:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
|
|
|
Token::Str("b"),
|
|
|
|
Token::Bool(false),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-15 19:39:46 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_ser_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&SerializeWithEnum::Struct { a: &a, b: 123 },
|
2016-02-15 19:39:46 -06:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "SerializeWithEnum",
|
|
|
|
variant: "Struct",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-15 19:39:46 -06:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
|
|
|
Token::Str("b"),
|
|
|
|
Token::Bool(true),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-15 19:39:46 -06:00
|
|
|
);
|
|
|
|
}
|
2016-02-15 22:43:11 -06:00
|
|
|
|
2017-08-14 16:39:29 -05:00
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
enum WithVariant {
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(serialize_with = "serialize_unit_variant_as_i8")]
|
|
|
|
#[serde(deserialize_with = "deserialize_i8_as_unit_variant")]
|
2017-08-07 19:22:26 -05:00
|
|
|
Unit,
|
|
|
|
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(serialize_with = "SerializeWith::serialize_with")]
|
|
|
|
#[serde(deserialize_with = "DeserializeWith::deserialize_with")]
|
2017-08-07 19:22:26 -05:00
|
|
|
Newtype(i32),
|
|
|
|
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(serialize_with = "serialize_variant_as_string")]
|
|
|
|
#[serde(deserialize_with = "deserialize_string_as_variant")]
|
2017-08-07 19:22:26 -05:00
|
|
|
Tuple(String, u8),
|
|
|
|
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(serialize_with = "serialize_variant_as_string")]
|
|
|
|
#[serde(deserialize_with = "deserialize_string_as_variant")]
|
|
|
|
Struct { f1: String, f2: u8 },
|
2017-08-07 19:22:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn serialize_unit_variant_as_i8<S>(serializer: S) -> Result<S::Ok, S::Error>
|
2017-12-23 22:13:08 -06:00
|
|
|
where
|
|
|
|
S: Serializer,
|
2017-08-07 19:22:26 -05:00
|
|
|
{
|
|
|
|
serializer.serialize_i8(0)
|
|
|
|
}
|
|
|
|
|
2017-08-14 16:39:29 -05:00
|
|
|
fn deserialize_i8_as_unit_variant<'de, D>(deserializer: D) -> Result<(), D::Error>
|
2017-12-23 22:13:08 -06:00
|
|
|
where
|
|
|
|
D: Deserializer<'de>,
|
2017-08-14 16:39:29 -05:00
|
|
|
{
|
|
|
|
let n = i8::deserialize(deserializer)?;
|
|
|
|
match n {
|
|
|
|
0 => Ok(()),
|
|
|
|
_ => Err(de::Error::invalid_value(Unexpected::Signed(n as i64), &"0")),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-23 22:13:08 -06:00
|
|
|
fn serialize_variant_as_string<S>(f1: &str, f2: &u8, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
2017-08-07 19:22:26 -05:00
|
|
|
{
|
|
|
|
serializer.serialize_str(format!("{};{:?}", f1, f2).as_str())
|
|
|
|
}
|
|
|
|
|
2017-08-14 16:39:29 -05:00
|
|
|
fn deserialize_string_as_variant<'de, D>(deserializer: D) -> Result<(String, u8), D::Error>
|
2017-12-23 22:13:08 -06:00
|
|
|
where
|
|
|
|
D: Deserializer<'de>,
|
2017-08-14 16:39:29 -05:00
|
|
|
{
|
|
|
|
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(_) => {
|
2017-12-23 22:13:08 -06:00
|
|
|
return Err(de::Error::invalid_value(
|
|
|
|
Unexpected::Str(f2),
|
|
|
|
&"an 8-bit signed integer",
|
|
|
|
));
|
2017-08-14 16:39:29 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
Ok((f1.into(), f2))
|
|
|
|
}
|
|
|
|
|
2017-08-07 19:22:26 -05:00
|
|
|
#[test]
|
|
|
|
fn test_serialize_with_variant() {
|
|
|
|
assert_ser_tokens(
|
2017-08-14 16:39:29 -05:00
|
|
|
&WithVariant::Unit,
|
2017-08-07 19:22:26 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::NewtypeVariant {
|
|
|
|
name: "WithVariant",
|
|
|
|
variant: "Unit",
|
|
|
|
},
|
2017-08-07 19:22:26 -05:00
|
|
|
Token::I8(0),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_ser_tokens(
|
2017-08-14 16:39:29 -05:00
|
|
|
&WithVariant::Newtype(123),
|
2017-08-07 19:22:26 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::NewtypeVariant {
|
|
|
|
name: "WithVariant",
|
|
|
|
variant: "Newtype",
|
|
|
|
},
|
2017-08-07 19:22:26 -05:00
|
|
|
Token::Bool(true),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_ser_tokens(
|
2017-08-14 16:39:29 -05:00
|
|
|
&WithVariant::Tuple("hello".into(), 0),
|
2017-08-07 19:22:26 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::NewtypeVariant {
|
|
|
|
name: "WithVariant",
|
|
|
|
variant: "Tuple",
|
|
|
|
},
|
2017-08-07 19:22:26 -05:00
|
|
|
Token::Str("hello;0"),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_ser_tokens(
|
2017-12-23 22:13:08 -06:00
|
|
|
&WithVariant::Struct {
|
|
|
|
f1: "world".into(),
|
|
|
|
f2: 1,
|
|
|
|
},
|
2017-08-14 16:39:29 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::NewtypeVariant {
|
|
|
|
name: "WithVariant",
|
|
|
|
variant: "Struct",
|
|
|
|
},
|
2017-08-14 16:39:29 -05:00
|
|
|
Token::Str("world;1"),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deserialize_with_variant() {
|
|
|
|
assert_de_tokens(
|
|
|
|
&WithVariant::Unit,
|
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::NewtypeVariant {
|
|
|
|
name: "WithVariant",
|
|
|
|
variant: "Unit",
|
|
|
|
},
|
2017-08-14 16:39:29 -05:00
|
|
|
Token::I8(0),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens(
|
|
|
|
&WithVariant::Newtype(123),
|
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::NewtypeVariant {
|
|
|
|
name: "WithVariant",
|
|
|
|
variant: "Newtype",
|
|
|
|
},
|
2017-08-14 16:39:29 -05:00
|
|
|
Token::Bool(true),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens(
|
|
|
|
&WithVariant::Tuple("hello".into(), 0),
|
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::NewtypeVariant {
|
|
|
|
name: "WithVariant",
|
|
|
|
variant: "Tuple",
|
|
|
|
},
|
2017-08-14 16:39:29 -05:00
|
|
|
Token::Str("hello;0"),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens(
|
2017-12-23 22:13:08 -06:00
|
|
|
&WithVariant::Struct {
|
|
|
|
f1: "world".into(),
|
|
|
|
f2: 1,
|
|
|
|
},
|
2017-08-07 19:22:26 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::NewtypeVariant {
|
|
|
|
name: "WithVariant",
|
|
|
|
variant: "Struct",
|
|
|
|
},
|
2017-08-07 19:22:26 -05:00
|
|
|
Token::Str("world;1"),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-02-15 22:43:11 -06:00
|
|
|
#[derive(Debug, PartialEq, Deserialize)]
|
2017-04-13 14:28:23 -05:00
|
|
|
struct DeserializeWithStruct<B>
|
|
|
|
where
|
|
|
|
B: DeserializeWith,
|
|
|
|
{
|
2016-02-15 22:43:11 -06:00
|
|
|
a: i8,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(deserialize_with = "DeserializeWith::deserialize_with")]
|
|
|
|
b: B,
|
2016-02-15 22:43:11 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deserialize_with_struct() {
|
|
|
|
assert_de_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&DeserializeWithStruct { a: 1, b: 2 },
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "DeserializeWithStruct",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-15 22:43:11 -06:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
|
|
|
Token::Str("b"),
|
|
|
|
Token::Bool(false),
|
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-15 22:43:11 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&DeserializeWithStruct { a: 1, b: 123 },
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "DeserializeWithStruct",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-15 22:43:11 -06:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
|
|
|
Token::Str("b"),
|
|
|
|
Token::Bool(true),
|
|
|
|
Token::StructEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-15 22:43:11 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Deserialize)]
|
2017-04-13 14:28:23 -05:00
|
|
|
enum DeserializeWithEnum<B>
|
|
|
|
where
|
|
|
|
B: DeserializeWith,
|
|
|
|
{
|
2016-02-15 22:43:11 -06:00
|
|
|
Struct {
|
|
|
|
a: i8,
|
2017-12-23 22:24:57 -06:00
|
|
|
#[serde(deserialize_with = "DeserializeWith::deserialize_with")]
|
|
|
|
b: B,
|
2017-04-13 14:28:23 -05:00
|
|
|
},
|
2016-02-15 22:43:11 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deserialize_with_enum() {
|
|
|
|
assert_de_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&DeserializeWithEnum::Struct { a: 1, b: 2 },
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "DeserializeWithEnum",
|
|
|
|
variant: "Struct",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-15 22:43:11 -06:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
|
|
|
Token::Str("b"),
|
|
|
|
Token::Bool(false),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-15 22:43:11 -06:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens(
|
2017-04-13 14:28:23 -05:00
|
|
|
&DeserializeWithEnum::Struct { a: 1, b: 123 },
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "DeserializeWithEnum",
|
|
|
|
variant: "Struct",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-02-15 22:43:11 -06:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(1),
|
|
|
|
Token::Str("b"),
|
|
|
|
Token::Bool(true),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2017-04-13 14:28:23 -05:00
|
|
|
],
|
2016-02-15 22:43:11 -06:00
|
|
|
);
|
|
|
|
}
|
2016-04-12 05:42:07 -05:00
|
|
|
|
|
|
|
#[test]
|
2016-04-12 10:26:56 -05:00
|
|
|
fn test_missing_renamed_field_struct() {
|
2016-04-12 05:42:07 -05:00
|
|
|
assert_de_tokens_error::<RenameStruct>(
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "Superhero",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-04-12 05:42:07 -05:00
|
|
|
Token::Str("a1"),
|
|
|
|
Token::I32(1),
|
|
|
|
Token::StructEnd,
|
|
|
|
],
|
2017-04-19 13:38:57 -05:00
|
|
|
"missing field `a3`",
|
2016-04-12 10:26:56 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens_error::<RenameStructSerializeDeserialize>(
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::Struct {
|
|
|
|
name: "SuperheroDe",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-04-12 10:26:56 -05:00
|
|
|
Token::Str("a1"),
|
|
|
|
Token::I32(1),
|
|
|
|
Token::StructEnd,
|
|
|
|
],
|
2017-04-19 13:38:57 -05:00
|
|
|
"missing field `a5`",
|
2016-04-12 10:26:56 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_missing_renamed_field_enum() {
|
|
|
|
assert_de_tokens_error::<RenameEnum>(
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "Superhero",
|
|
|
|
variant: "barry_allan",
|
|
|
|
len: 1,
|
|
|
|
},
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2016-04-12 10:26:56 -05:00
|
|
|
],
|
2017-04-19 13:38:57 -05:00
|
|
|
"missing field `b`",
|
2016-04-12 10:26:56 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_de_tokens_error::<RenameEnumSerializeDeserialize<i8>>(
|
2016-06-29 01:50:19 -05:00
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::StructVariant {
|
|
|
|
name: "SuperheroDe",
|
|
|
|
variant: "jason_todd",
|
|
|
|
len: 2,
|
|
|
|
},
|
2016-04-12 10:26:56 -05:00
|
|
|
Token::Str("a"),
|
|
|
|
Token::I8(0),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::StructVariantEnd,
|
2016-04-12 10:26:56 -05:00
|
|
|
],
|
2017-04-19 13:38:57 -05:00
|
|
|
"missing field `d`",
|
2016-04-12 10:26:56 -05:00
|
|
|
);
|
2016-04-12 05:42:07 -05:00
|
|
|
}
|
2016-07-05 02:52:19 -05:00
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Deserialize)]
|
|
|
|
enum InvalidLengthEnum {
|
|
|
|
A(i32, i32, i32),
|
2017-12-23 22:24:57 -06:00
|
|
|
B(
|
|
|
|
#[serde(skip_deserializing)]
|
|
|
|
i32,
|
|
|
|
i32,
|
|
|
|
i32,
|
|
|
|
),
|
2016-07-05 02:52:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_invalid_length_enum() {
|
|
|
|
assert_de_tokens_error::<InvalidLengthEnum>(
|
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::TupleVariant {
|
|
|
|
name: "InvalidLengthEnum",
|
|
|
|
variant: "A",
|
|
|
|
len: 3,
|
|
|
|
},
|
2017-04-05 11:42:24 -05:00
|
|
|
Token::I32(1),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::TupleVariantEnd,
|
2016-07-05 02:52:19 -05:00
|
|
|
],
|
2017-04-19 13:38:57 -05:00
|
|
|
"invalid length 1, expected tuple of 3 elements",
|
2016-07-05 02:52:19 -05:00
|
|
|
);
|
|
|
|
assert_de_tokens_error::<InvalidLengthEnum>(
|
|
|
|
&[
|
2017-12-23 22:13:08 -06:00
|
|
|
Token::TupleVariant {
|
|
|
|
name: "InvalidLengthEnum",
|
|
|
|
variant: "B",
|
|
|
|
len: 3,
|
|
|
|
},
|
2017-04-05 11:42:24 -05:00
|
|
|
Token::I32(1),
|
2017-04-05 12:40:14 -05:00
|
|
|
Token::TupleVariantEnd,
|
2016-07-05 02:52:19 -05:00
|
|
|
],
|
2017-04-19 13:38:57 -05:00
|
|
|
"invalid length 1, expected tuple of 2 elements",
|
2016-07-05 02:52:19 -05:00
|
|
|
);
|
|
|
|
}
|
2017-03-18 11:22:27 -05:00
|
|
|
|
|
|
|
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(into = "EnumToU32", from = "EnumToU32")]
|
2017-03-18 11:22:27 -05:00
|
|
|
struct StructFromEnum(Option<u32>);
|
|
|
|
|
|
|
|
impl Into<EnumToU32> for StructFromEnum {
|
|
|
|
fn into(self) -> EnumToU32 {
|
|
|
|
match self {
|
2017-04-13 14:28:23 -05:00
|
|
|
StructFromEnum(v) => v.into(),
|
2017-03-18 11:22:27 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<EnumToU32> for StructFromEnum {
|
|
|
|
fn from(v: EnumToU32) -> Self {
|
|
|
|
StructFromEnum(v.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
|
2017-12-23 22:13:08 -06:00
|
|
|
#[serde(into = "Option<u32>", from = "Option<u32>")]
|
2017-03-18 11:22:27 -05:00
|
|
|
enum EnumToU32 {
|
|
|
|
One,
|
|
|
|
Two,
|
|
|
|
Three,
|
|
|
|
Four,
|
2017-04-13 14:28:23 -05:00
|
|
|
Nothing,
|
2017-03-18 11:22:27 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Into<Option<u32>> for EnumToU32 {
|
|
|
|
fn into(self) -> Option<u32> {
|
|
|
|
match self {
|
|
|
|
EnumToU32::One => Some(1),
|
|
|
|
EnumToU32::Two => Some(2),
|
|
|
|
EnumToU32::Three => Some(3),
|
|
|
|
EnumToU32::Four => Some(4),
|
2017-04-13 14:28:23 -05:00
|
|
|
EnumToU32::Nothing => None,
|
2017-03-18 11:22:27 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Option<u32>> for EnumToU32 {
|
|
|
|
fn from(v: Option<u32>) -> Self {
|
|
|
|
match v {
|
|
|
|
Some(1) => EnumToU32::One,
|
|
|
|
Some(2) => EnumToU32::Two,
|
|
|
|
Some(3) => EnumToU32::Three,
|
|
|
|
Some(4) => EnumToU32::Four,
|
2017-04-13 14:28:23 -05:00
|
|
|
_ => EnumToU32::Nothing,
|
2017-03-18 11:22:27 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from_into_traits() {
|
2017-04-13 14:28:23 -05:00
|
|
|
assert_ser_tokens::<EnumToU32>(&EnumToU32::One, &[Token::Some, Token::U32(1)]);
|
|
|
|
assert_ser_tokens::<EnumToU32>(&EnumToU32::Nothing, &[Token::None]);
|
|
|
|
assert_de_tokens::<EnumToU32>(&EnumToU32::Two, &[Token::Some, Token::U32(2)]);
|
|
|
|
assert_ser_tokens::<StructFromEnum>(&StructFromEnum(Some(5)), &[Token::None]);
|
|
|
|
assert_ser_tokens::<StructFromEnum>(&StructFromEnum(None), &[Token::None]);
|
|
|
|
assert_de_tokens::<StructFromEnum>(&StructFromEnum(Some(2)), &[Token::Some, Token::U32(2)]);
|
2017-03-18 11:22:27 -05:00
|
|
|
}
|
2018-03-14 12:46:47 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_collect_other() {
|
|
|
|
let mut extra = HashMap::new();
|
|
|
|
extra.insert("c".into(), 3);
|
|
|
|
assert_de_tokens(
|
|
|
|
&CollectOther { a: 1, b: 2, extra: extra.clone() },
|
|
|
|
&[
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("a"),
|
|
|
|
Token::U32(1),
|
|
|
|
Token::Str("b"),
|
|
|
|
Token::U32(2),
|
|
|
|
Token::Str("c"),
|
|
|
|
Token::U32(3),
|
|
|
|
Token::MapEnd,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
assert_ser_tokens(
|
2018-03-14 15:17:02 -05:00
|
|
|
&CollectOther { a: 1, b: 2, extra },
|
2018-03-14 12:46:47 -05:00
|
|
|
&[
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("a"),
|
|
|
|
Token::U32(1),
|
|
|
|
Token::Str("b"),
|
|
|
|
Token::U32(2),
|
|
|
|
Token::Str("c"),
|
|
|
|
Token::U32(3),
|
|
|
|
Token::MapEnd,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
2018-03-16 16:40:08 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_flatten_struct_enum() {
|
|
|
|
let mut extra = HashMap::new();
|
|
|
|
extra.insert("extra_key".into(), "extra value".into());
|
2018-03-16 16:58:16 -05:00
|
|
|
let change_request = FlattenStructEnumWrapper {
|
|
|
|
data: FlattenStructEnum::InsertInteger {
|
2018-03-16 16:40:08 -05:00
|
|
|
index: 0,
|
|
|
|
value: 42
|
|
|
|
},
|
2018-03-16 18:49:00 -05:00
|
|
|
extra,
|
2018-03-16 16:40:08 -05:00
|
|
|
};
|
|
|
|
assert_de_tokens(
|
|
|
|
&change_request,
|
|
|
|
&[
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("insert_integer"),
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("index"),
|
|
|
|
Token::U32(0),
|
|
|
|
Token::Str("value"),
|
|
|
|
Token::U32(42),
|
|
|
|
Token::MapEnd,
|
|
|
|
Token::Str("extra_key"),
|
2018-03-16 18:49:00 -05:00
|
|
|
Token::Str("extra value"),
|
2018-03-16 16:40:08 -05:00
|
|
|
Token::MapEnd
|
|
|
|
],
|
|
|
|
);
|
|
|
|
assert_ser_tokens(
|
|
|
|
&change_request,
|
|
|
|
&[
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("insert_integer"),
|
|
|
|
Token::Struct { len: 2, name: "insert_integer" },
|
|
|
|
Token::Str("index"),
|
|
|
|
Token::U32(0),
|
|
|
|
Token::Str("value"),
|
|
|
|
Token::U32(42),
|
|
|
|
Token::StructEnd,
|
|
|
|
Token::Str("extra_key"),
|
2018-03-16 18:49:00 -05:00
|
|
|
Token::Str("extra value"),
|
2018-03-16 16:40:08 -05:00
|
|
|
Token::MapEnd
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
2018-03-16 16:58:16 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_flatten_struct_tag_content_enum() {
|
|
|
|
let change_request = FlattenStructTagContentEnumWrapper {
|
|
|
|
outer: 42,
|
2018-03-18 07:02:00 -05:00
|
|
|
data: FlattenStructTagContentEnumNewtype(
|
|
|
|
FlattenStructTagContentEnum::InsertInteger {
|
|
|
|
index: 0,
|
|
|
|
value: 42
|
|
|
|
}
|
|
|
|
),
|
2018-03-16 16:58:16 -05:00
|
|
|
};
|
|
|
|
assert_de_tokens(
|
|
|
|
&change_request,
|
|
|
|
&[
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("outer"),
|
|
|
|
Token::U32(42),
|
|
|
|
Token::Str("type"),
|
|
|
|
Token::Str("insert_integer"),
|
|
|
|
Token::Str("value"),
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("index"),
|
|
|
|
Token::U32(0),
|
|
|
|
Token::Str("value"),
|
|
|
|
Token::U32(42),
|
|
|
|
Token::MapEnd,
|
|
|
|
Token::MapEnd,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
assert_ser_tokens(
|
|
|
|
&change_request,
|
|
|
|
&[
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("outer"),
|
|
|
|
Token::U32(42),
|
|
|
|
Token::Str("type"),
|
|
|
|
Token::Str("insert_integer"),
|
|
|
|
Token::Str("value"),
|
|
|
|
Token::Struct { len: 2, name: "insert_integer" },
|
|
|
|
Token::Str("index"),
|
|
|
|
Token::U32(0),
|
|
|
|
Token::Str("value"),
|
|
|
|
Token::U32(42),
|
|
|
|
Token::StructEnd,
|
|
|
|
Token::MapEnd,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
2018-03-18 07:10:54 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_flatten_struct_tag_content_enum_newtype() {
|
|
|
|
let change_request = FlattenStructTagContentEnumWrapper {
|
|
|
|
outer: 42,
|
|
|
|
data: FlattenStructTagContentEnumNewtype(
|
|
|
|
FlattenStructTagContentEnum::NewtypeVariant(
|
|
|
|
FlattenStructTagContentEnumNewtypeVariant {
|
|
|
|
value: 23
|
|
|
|
}
|
|
|
|
)
|
|
|
|
),
|
|
|
|
};
|
|
|
|
assert_de_tokens(
|
|
|
|
&change_request,
|
|
|
|
&[
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("outer"),
|
|
|
|
Token::U32(42),
|
|
|
|
Token::Str("type"),
|
|
|
|
Token::Str("newtype_variant"),
|
|
|
|
Token::Str("value"),
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("value"),
|
|
|
|
Token::U32(23),
|
|
|
|
Token::MapEnd,
|
|
|
|
Token::MapEnd,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
assert_ser_tokens(
|
|
|
|
&change_request,
|
|
|
|
&[
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("outer"),
|
|
|
|
Token::U32(42),
|
|
|
|
Token::Str("type"),
|
|
|
|
Token::Str("newtype_variant"),
|
|
|
|
Token::Str("value"),
|
|
|
|
Token::Struct { len: 1, name: "FlattenStructTagContentEnumNewtypeVariant" },
|
|
|
|
Token::Str("value"),
|
|
|
|
Token::U32(23),
|
|
|
|
Token::StructEnd,
|
|
|
|
Token::MapEnd,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
2018-03-18 12:22:06 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_unknown_field_in_flatten() {
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
2018-03-18 12:30:46 -05:00
|
|
|
#[serde(deny_unknown_fields)]
|
2018-03-18 12:22:06 -05:00
|
|
|
struct Outer {
|
|
|
|
dummy: String,
|
|
|
|
#[serde(flatten)]
|
|
|
|
inner: Inner,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
struct Inner {
|
|
|
|
foo: HashMap<String, u32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_de_tokens_error::<Outer>(
|
|
|
|
&[
|
|
|
|
Token::Struct {
|
|
|
|
name: "Outer",
|
|
|
|
len: 1,
|
|
|
|
},
|
|
|
|
Token::Str("dummy"),
|
|
|
|
Token::Str("23"),
|
|
|
|
Token::Str("foo"),
|
|
|
|
Token::Map { len: None },
|
|
|
|
Token::Str("a"),
|
|
|
|
Token::U32(1),
|
|
|
|
Token::Str("b"),
|
|
|
|
Token::U32(2),
|
|
|
|
Token::MapEnd,
|
|
|
|
Token::Str("bar"),
|
|
|
|
Token::U32(23),
|
|
|
|
Token::StructEnd,
|
|
|
|
],
|
|
|
|
"unknown field `bar`",
|
|
|
|
);
|
|
|
|
}
|