mirror of
https://github.com/serde-rs/serde.git
synced 2025-09-29 22:11:09 +00:00
feat(codegen) skip_deserializing
This commit is contained in:
parent
a84b6aaedd
commit
87393b61bb
@ -714,6 +714,7 @@ Field Annotations:
|
|||||||
| `#[serde(default)]` | If the value is not specified, use the `Default::default()` |
|
| `#[serde(default)]` | If the value is not specified, use the `Default::default()` |
|
||||||
| `#[serde(default="$path")]` | Call the path to a function `fn() -> T` to build the value |
|
| `#[serde(default="$path")]` | Call the path to a function `fn() -> T` to build the value |
|
||||||
| `#[serde(skip_serializing)]` | Do not serialize this value |
|
| `#[serde(skip_serializing)]` | Do not serialize this value |
|
||||||
|
| `#[serde(skip_deserializing)]` | Always use `Default::default()` instead of deserializing this value |
|
||||||
| `#[serde(skip_serializing_if="$path")]` | Do not serialize this value if this function `fn(&T) -> bool` returns `false` |
|
| `#[serde(skip_serializing_if="$path")]` | Do not serialize this value if this function `fn(&T) -> bool` returns `false` |
|
||||||
| `#[serde(serialize_with="$path")]` | Call a function `fn<T, S>(&T, &mut S) -> Result<(), S::Error> where S: Serializer` to serialize this value |
|
| `#[serde(serialize_with="$path")]` | Call a function `fn<T, S>(&T, &mut S) -> Result<(), S::Error> where S: Serializer` to serialize this value |
|
||||||
| `#[serde(deserialize_with="$path")]` | Call a function `fn<T, D>(&mut D) -> Result<T, D::Error> where D: Deserializer` to deserialize this value |
|
| `#[serde(deserialize_with="$path")]` | Call a function `fn<T, D>(&mut D) -> Result<T, D::Error> where D: Deserializer` to deserialize this value |
|
||||||
|
@ -181,6 +181,7 @@ impl VariantAttrs {
|
|||||||
pub struct FieldAttrs {
|
pub struct FieldAttrs {
|
||||||
name: Name,
|
name: Name,
|
||||||
skip_serializing_field: bool,
|
skip_serializing_field: bool,
|
||||||
|
skip_deserializing_field: bool,
|
||||||
skip_serializing_field_if: Option<P<ast::Expr>>,
|
skip_serializing_field_if: Option<P<ast::Expr>>,
|
||||||
default_expr_if_missing: Option<P<ast::Expr>>,
|
default_expr_if_missing: Option<P<ast::Expr>>,
|
||||||
serialize_with: Option<P<ast::Expr>>,
|
serialize_with: Option<P<ast::Expr>>,
|
||||||
@ -204,6 +205,7 @@ impl FieldAttrs {
|
|||||||
let mut field_attrs = FieldAttrs {
|
let mut field_attrs = FieldAttrs {
|
||||||
name: Name::new(field_ident),
|
name: Name::new(field_ident),
|
||||||
skip_serializing_field: false,
|
skip_serializing_field: false,
|
||||||
|
skip_deserializing_field: false,
|
||||||
skip_serializing_field_if: None,
|
skip_serializing_field_if: None,
|
||||||
default_expr_if_missing: None,
|
default_expr_if_missing: None,
|
||||||
serialize_with: None,
|
serialize_with: None,
|
||||||
@ -249,6 +251,11 @@ impl FieldAttrs {
|
|||||||
field_attrs.skip_serializing_field = true;
|
field_attrs.skip_serializing_field = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(skip_deserializing)]`
|
||||||
|
ast::MetaItemKind::Word(ref name) if name == &"skip_deserializing" => {
|
||||||
|
field_attrs.skip_deserializing_field = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip_serializing_if="...")]`
|
// Parse `#[serde(skip_serializing_if="...")]`
|
||||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => {
|
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => {
|
||||||
let expr = wrap_skip_serializing(
|
let expr = wrap_skip_serializing(
|
||||||
@ -325,6 +332,10 @@ impl FieldAttrs {
|
|||||||
self.skip_serializing_field
|
self.skip_serializing_field
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn skip_deserializing_field(&self) -> bool {
|
||||||
|
self.skip_deserializing_field
|
||||||
|
}
|
||||||
|
|
||||||
pub fn skip_serializing_field_if(&self) -> Option<&P<ast::Expr>> {
|
pub fn skip_serializing_field_if(&self) -> Option<&P<ast::Expr>> {
|
||||||
self.skip_serializing_field_if.as_ref()
|
self.skip_serializing_field_if.as_ref()
|
||||||
}
|
}
|
||||||
|
@ -430,19 +430,27 @@ fn deserialize_struct_as_seq(
|
|||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
fields: &[ast::StructField],
|
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let let_values: Vec<_> = (0 .. fields.len())
|
let let_values: Vec<_> = fields.iter()
|
||||||
.map(|i| {
|
.enumerate()
|
||||||
|
.map(|(i, &(_, ref attrs))| {
|
||||||
let name = builder.id(format!("__field{}", i));
|
let name = builder.id(format!("__field{}", i));
|
||||||
quote_stmt!(cx,
|
if attrs.skip_deserializing_field() {
|
||||||
let $name = match try!(visitor.visit()) {
|
let default = builder.expr().default();
|
||||||
Some(value) => { value },
|
quote_stmt!(cx,
|
||||||
None => {
|
let $name = $default;
|
||||||
return Err(::serde::de::Error::end_of_stream());
|
).unwrap()
|
||||||
}
|
} else {
|
||||||
};
|
quote_stmt!(cx,
|
||||||
).unwrap()
|
let $name = match try!(visitor.visit()) {
|
||||||
|
Some(value) => { value },
|
||||||
|
None => {
|
||||||
|
return Err(::serde::de::Error::end_of_stream());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
).unwrap()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@ -450,7 +458,7 @@ fn deserialize_struct_as_seq(
|
|||||||
.with_id_exprs(
|
.with_id_exprs(
|
||||||
fields.iter()
|
fields.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, field)| {
|
.map(|(i, &(field, _))| {
|
||||||
(
|
(
|
||||||
match field.ident {
|
match field.ident {
|
||||||
Some(name) => name.clone(),
|
Some(name) => name.clone(),
|
||||||
@ -493,22 +501,21 @@ fn deserialize_struct(
|
|||||||
|
|
||||||
let type_path = builder.path().id(type_ident).build();
|
let type_path = builder.path().id(type_ident).build();
|
||||||
|
|
||||||
|
let fields_with_attrs = try!(fields_with_attrs(cx, impl_generics, &ty, fields, false));
|
||||||
|
|
||||||
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
type_path.clone(),
|
type_path.clone(),
|
||||||
fields,
|
&fields_with_attrs,
|
||||||
));
|
));
|
||||||
|
|
||||||
let (field_visitor, fields_stmt, visit_map_expr) = try!(deserialize_struct_visitor(
|
let (field_visitor, fields_stmt, visit_map_expr) = try!(deserialize_struct_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
type_path.clone(),
|
type_path.clone(),
|
||||||
&ty,
|
&fields_with_attrs,
|
||||||
impl_generics,
|
|
||||||
fields,
|
|
||||||
container_attrs,
|
container_attrs,
|
||||||
false,
|
|
||||||
));
|
));
|
||||||
|
|
||||||
let type_name = container_attrs.name().deserialize_name_expr();
|
let type_name = container_attrs.name().deserialize_name_expr();
|
||||||
@ -750,22 +757,21 @@ fn deserialize_struct_variant(
|
|||||||
.id(variant_ident)
|
.id(variant_ident)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
let fields_with_attrs = try!(fields_with_attrs(cx, generics, &ty, fields, true));
|
||||||
|
|
||||||
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
type_path.clone(),
|
type_path.clone(),
|
||||||
fields,
|
&fields_with_attrs,
|
||||||
));
|
));
|
||||||
|
|
||||||
let (field_visitor, fields_stmt, field_expr) = try!(deserialize_struct_visitor(
|
let (field_visitor, fields_stmt, field_expr) = try!(deserialize_struct_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
type_path,
|
type_path,
|
||||||
&ty,
|
&fields_with_attrs,
|
||||||
generics,
|
|
||||||
fields,
|
|
||||||
container_attrs,
|
container_attrs,
|
||||||
true,
|
|
||||||
));
|
));
|
||||||
|
|
||||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) = try!(deserialize_visitor(
|
||||||
@ -966,29 +972,17 @@ fn deserialize_struct_visitor(
|
|||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
container_ty: &P<ast::Ty>,
|
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||||
generics: &ast::Generics,
|
|
||||||
fields: &[ast::StructField],
|
|
||||||
container_attrs: &attr::ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
is_enum: bool,
|
|
||||||
) -> Result<(Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>), Error> {
|
) -> Result<(Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>), Error> {
|
||||||
let field_exprs = fields.iter()
|
let field_exprs = fields.iter()
|
||||||
.map(|field| {
|
.map(|&(_, ref attrs)| attrs.name().deserialize_name())
|
||||||
let field_attrs = try!(
|
|
||||||
attr::FieldAttrs::from_field(cx,
|
|
||||||
container_ty,
|
|
||||||
generics,
|
|
||||||
field,
|
|
||||||
is_enum)
|
|
||||||
);
|
|
||||||
Ok(field_attrs.name().deserialize_name())
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let field_visitor = deserialize_field_visitor(
|
let field_visitor = deserialize_field_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
try!(field_exprs),
|
field_exprs,
|
||||||
container_attrs,
|
container_attrs,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@ -997,17 +991,14 @@ fn deserialize_struct_visitor(
|
|||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
struct_path,
|
struct_path,
|
||||||
container_ty,
|
|
||||||
generics,
|
|
||||||
fields,
|
fields,
|
||||||
container_attrs,
|
container_attrs,
|
||||||
is_enum,
|
|
||||||
));
|
));
|
||||||
|
|
||||||
let fields_expr = builder.expr().ref_().slice()
|
let fields_expr = builder.expr().ref_().slice()
|
||||||
.with_exprs(
|
.with_exprs(
|
||||||
fields.iter()
|
fields.iter()
|
||||||
.map(|field| {
|
.map(|&(field, _)| {
|
||||||
match field.ident {
|
match field.ident {
|
||||||
Some(name) => builder.expr().str(name),
|
Some(name) => builder.expr().str(name),
|
||||||
None => {
|
None => {
|
||||||
@ -1029,62 +1020,69 @@ fn deserialize_map(
|
|||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
container_ty: &P<ast::Ty>,
|
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||||
generics: &ast::Generics,
|
|
||||||
fields: &[ast::StructField],
|
|
||||||
container_attrs: &attr::ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
is_enum: bool,
|
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
// Create the field names for the fields.
|
// Create the field names for the fields.
|
||||||
let field_names: Vec<ast::Ident> = (0 .. fields.len())
|
let fields_attrs_names = fields.iter()
|
||||||
.map(|i| builder.id(format!("__field{}", i)))
|
.enumerate()
|
||||||
|
.map(|(i, &(ref field, ref attrs))|
|
||||||
|
(field, attrs, builder.id(format!("__field{}", i))))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Declare each field that will be deserialized.
|
||||||
|
let let_values: Vec<ast::Stmt> = fields_attrs_names.iter()
|
||||||
|
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
|
||||||
|
.map(|&(_, _, name)| quote_stmt!(cx, let mut $name = None;).unwrap())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let field_attrs: Vec<_> = try!(
|
|
||||||
fields.iter()
|
|
||||||
.map(|field| attr::FieldAttrs::from_field(cx, container_ty, generics, field, is_enum))
|
|
||||||
.collect()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Declare each field.
|
|
||||||
let let_values: Vec<ast::Stmt> = field_names.iter()
|
|
||||||
.map(|field_name| quote_stmt!(cx, let mut $field_name = None;).unwrap())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
|
|
||||||
// Visit ignored values to consume them
|
|
||||||
let ignored_arm = if container_attrs.deny_unknown_fields() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(quote_arm!(cx,
|
|
||||||
_ => { try!(visitor.visit_value::<::serde::de::impls::IgnoredAny>()); }
|
|
||||||
))
|
|
||||||
};
|
|
||||||
|
|
||||||
// Match arms to extract a value for a field.
|
// Match arms to extract a value for a field.
|
||||||
let value_arms = field_attrs.iter().zip(field_names.iter())
|
let value_arms = fields_attrs_names.iter()
|
||||||
.map(|(field_attr, field_name)| {
|
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
|
||||||
let expr = match field_attr.deserialize_with() {
|
.map(|&(_, ref attrs, name)| {
|
||||||
|
let expr = match attrs.deserialize_with() {
|
||||||
Some(expr) => expr.clone(),
|
Some(expr) => expr.clone(),
|
||||||
None => quote_expr!(cx, visitor.visit_value()),
|
None => quote_expr!(cx, visitor.visit_value()),
|
||||||
};
|
};
|
||||||
|
|
||||||
quote_arm!(cx,
|
quote_arm!(cx,
|
||||||
__Field::$field_name => {
|
__Field::$name => {
|
||||||
$field_name = Some(try!($expr));
|
$name = Some(try!($expr));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.chain(ignored_arm.into_iter())
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let extract_values = field_attrs.iter().zip(field_names.iter())
|
// Match arms to ignore value for fields that have `skip_deserializing`.
|
||||||
.map(|(field_attr, field_name)| {
|
// Ignored even if `deny_unknown_fields` is set.
|
||||||
let missing_expr = field_attr.expr_is_missing();
|
let skipped_arms = fields_attrs_names.iter()
|
||||||
|
.filter(|&&(_, ref attrs, _)| attrs.skip_deserializing_field())
|
||||||
|
.map(|&(_, _, name)| {
|
||||||
|
quote_arm!(cx,
|
||||||
|
__Field::$name => {
|
||||||
|
try!(visitor.visit_value::<::serde::de::impls::IgnoredAny>());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Visit ignored values to consume them
|
||||||
|
let ignored_arm = if !container_attrs.deny_unknown_fields() {
|
||||||
|
Some(quote_arm!(cx,
|
||||||
|
_ => { try!(visitor.visit_value::<::serde::de::impls::IgnoredAny>()); }
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let extract_values = fields_attrs_names.iter()
|
||||||
|
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
|
||||||
|
.map(|&(_, ref attrs, name)| {
|
||||||
|
let missing_expr = attrs.expr_is_missing();
|
||||||
|
|
||||||
Ok(quote_stmt!(cx,
|
Ok(quote_stmt!(cx,
|
||||||
let $field_name = match $field_name {
|
let $name = match $name {
|
||||||
Some($field_name) => $field_name,
|
Some($name) => $name,
|
||||||
None => $missing_expr
|
None => $missing_expr
|
||||||
};
|
};
|
||||||
).unwrap())
|
).unwrap())
|
||||||
@ -1095,9 +1093,8 @@ fn deserialize_map(
|
|||||||
|
|
||||||
let result = builder.expr().struct_path(struct_path)
|
let result = builder.expr().struct_path(struct_path)
|
||||||
.with_id_exprs(
|
.with_id_exprs(
|
||||||
fields.iter()
|
fields_attrs_names.iter()
|
||||||
.zip(field_names.iter())
|
.map(|&(field, attrs, name)| {
|
||||||
.map(|(field, field_name)| {
|
|
||||||
(
|
(
|
||||||
match field.ident {
|
match field.ident {
|
||||||
Some(name) => name.clone(),
|
Some(name) => name.clone(),
|
||||||
@ -1105,7 +1102,11 @@ fn deserialize_map(
|
|||||||
cx.span_bug(field.span, "struct contains unnamed fields")
|
cx.span_bug(field.span, "struct contains unnamed fields")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
builder.expr().id(field_name),
|
if attrs.skip_deserializing_field() {
|
||||||
|
builder.expr().default()
|
||||||
|
} else {
|
||||||
|
builder.expr().id(name)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -1117,6 +1118,8 @@ fn deserialize_map(
|
|||||||
while let Some(key) = try!(visitor.visit_key()) {
|
while let Some(key) = try!(visitor.visit_key()) {
|
||||||
match key {
|
match key {
|
||||||
$value_arms
|
$value_arms
|
||||||
|
$skipped_arms
|
||||||
|
$ignored_arm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1127,3 +1130,18 @@ fn deserialize_map(
|
|||||||
Ok($result)
|
Ok($result)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fields_with_attrs<'a>(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
generics: &ast::Generics,
|
||||||
|
ty: &P<ast::Ty>,
|
||||||
|
fields: &'a [ast::StructField],
|
||||||
|
is_enum: bool
|
||||||
|
) -> Result<Vec<(&'a ast::StructField, attr::FieldAttrs)>, Error> {
|
||||||
|
fields.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let attrs = try!(attr::FieldAttrs::from_field(cx, &ty, generics, field, is_enum));
|
||||||
|
Ok((field, attrs))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@ struct TupleStruct(i32, i32, i32);
|
|||||||
struct Struct {
|
struct Struct {
|
||||||
a: i32,
|
a: i32,
|
||||||
b: i32,
|
b: i32,
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
c: i32,
|
c: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +61,17 @@ macro_rules! declare_tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! declare_error_tests {
|
||||||
|
($($name:ident<$target:ident> { $tokens:expr, $expected:expr, })+) => {
|
||||||
|
$(
|
||||||
|
#[test]
|
||||||
|
fn $name() {
|
||||||
|
assert_de_tokens_error::<$target>($tokens, $expected);
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
declare_tests! {
|
declare_tests! {
|
||||||
@ -524,7 +536,40 @@ declare_tests! {
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
test_struct {
|
test_struct {
|
||||||
Struct { a: 1, b: 2, c: 3 } => vec![
|
Struct { a: 1, b: 2, c: 0 } => vec![
|
||||||
|
Token::MapStart(Some(3)),
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::I32(2),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
Struct { a: 1, b: 2, c: 0 } => vec![
|
||||||
|
Token::StructStart("Struct", Some(3)),
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::I32(2),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
Struct { a: 1, b: 2, c: 0 } => vec![
|
||||||
|
Token::SeqStart(Some(3)),
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I32(2),
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
test_struct_with_skip {
|
||||||
|
Struct { a: 1, b: 2, c: 0 } => vec![
|
||||||
Token::MapStart(Some(3)),
|
Token::MapStart(Some(3)),
|
||||||
Token::MapSep,
|
Token::MapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
@ -537,9 +582,13 @@ declare_tests! {
|
|||||||
Token::MapSep,
|
Token::MapSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
|
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("d"),
|
||||||
|
Token::I32(4),
|
||||||
Token::MapEnd,
|
Token::MapEnd,
|
||||||
],
|
],
|
||||||
Struct { a: 1, b: 2, c: 3 } => vec![
|
Struct { a: 1, b: 2, c: 0 } => vec![
|
||||||
Token::StructStart("Struct", Some(3)),
|
Token::StructStart("Struct", Some(3)),
|
||||||
Token::StructSep,
|
Token::StructSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
@ -552,6 +601,10 @@ declare_tests! {
|
|||||||
Token::StructSep,
|
Token::StructSep,
|
||||||
Token::Str("c"),
|
Token::Str("c"),
|
||||||
Token::I32(3),
|
Token::I32(3),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("d"),
|
||||||
|
Token::I32(4),
|
||||||
Token::StructEnd,
|
Token::StructEnd,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@ -638,12 +691,22 @@ fn test_net_ipaddr() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
declare_error_tests! {
|
||||||
fn test_enum_error() {
|
test_unknown_variant<Enum> {
|
||||||
assert_de_tokens_error::<Enum>(
|
|
||||||
vec![
|
vec![
|
||||||
Token::EnumUnit("Enum", "Foo"),
|
Token::EnumUnit("Enum", "Foo"),
|
||||||
],
|
],
|
||||||
Error::UnknownVariantError("Foo".to_owned()),
|
Error::UnknownVariantError("Foo".to_owned()),
|
||||||
)
|
}
|
||||||
|
test_struct_seq_too_long<Struct> {
|
||||||
|
vec![
|
||||||
|
Token::SeqStart(Some(4)),
|
||||||
|
Token::SeqSep, Token::I32(1),
|
||||||
|
Token::SeqSep, Token::I32(2),
|
||||||
|
Token::SeqSep, Token::I32(3),
|
||||||
|
Token::SeqSep, Token::I32(4),
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
Error::UnexpectedToken(Token::SeqSep),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user