mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-23 05:58:01 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 41142d41ee | |||
| fd328c2f2a | |||
| 3ad276944a | |||
| bb20796e9d | |||
| 709ac64dfc | |||
| a9a4b2d8e2 | |||
| 7374ac499d | |||
| 6596f77e91 | |||
| eeb4efc19c | |||
| 76b70455ec | |||
| f43c8a6267 | |||
| 7aa0b6ce27 | |||
| efdbf5795f | |||
| 55355b6680 | |||
| f8a91e5176 | |||
| aa0cd9b3dc | |||
| 1f82cd6e3d | |||
| 3caac4e6f3 | |||
| f4414bfc14 | |||
| 9c0140968d |
@@ -705,18 +705,18 @@ Variant Annotations:
|
||||
|
||||
Field Annotations:
|
||||
|
||||
| Annotation | Function |
|
||||
| ---------- | -------- |
|
||||
| `#[serde(rename="name")]` | Serialize and deserialize this field with the given name |
|
||||
| `#[serde(rename(serialize="name1"))]` | Serialize this field with the given name |
|
||||
| `#[serde(rename(deserialize="name1"))]` | Deserialize this field with the given name |
|
||||
| `#[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(skip_serializing)]` | Do not serialize this value |
|
||||
| `#[serde(skip_deserializing)]` | Always use `Default::default()` or `#[serde(default="$path")]` instead of deserializing this value |
|
||||
| `#[serde(skip_serializing_if="$path")]` | Do not serialize this value if this function `fn(&T) -> bool` returns `true` |
|
||||
| `#[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 |
|
||||
| Annotation | Function |
|
||||
| ---------- | -------- |
|
||||
| `#[serde(rename="name")]` | Serialize and deserialize this field with the given name |
|
||||
| `#[serde(rename(serialize="name1"))]` | Serialize this field with the given name |
|
||||
| `#[serde(rename(deserialize="name1"))]` | Deserialize this field with the given name |
|
||||
| `#[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(skip_serializing)]` | Do not serialize this value |
|
||||
| `#[serde(skip_deserializing)]` | Always use `Default::default()` or `#[serde(default="$path")]` instead of deserializing this value |
|
||||
| `#[serde(skip_serializing_if="$path")]` | Do not serialize this value if this function `fn(&T) -> bool` returns `true` |
|
||||
| `#[serde(serialize_with="$path")]` | Call a function `fn<S>(&T, &mut S) -> Result<(), S::Error> where S: Serializer` to serialize this value of type `T` |
|
||||
| `#[serde(deserialize_with="$path")]` | Call a function `fn<D>(&mut D) -> Result<T, D::Error> where D: Deserializer` to deserialize this value of type `T` |
|
||||
|
||||
Upgrading from Serde 0.6
|
||||
========================
|
||||
|
||||
@@ -9,10 +9,10 @@ default = ["serde_codegen"]
|
||||
nightly = ["serde_macros"]
|
||||
|
||||
[build-dependencies]
|
||||
serde_codegen = { version = "^0.6.4", optional = true }
|
||||
syntex = "^0.22.0"
|
||||
serde_codegen = { version = "^0.7.5", optional = true }
|
||||
syntex = "^0.32.0"
|
||||
|
||||
[dependencies]
|
||||
serde = "^0.6.1"
|
||||
serde_json = "^0.6.0"
|
||||
serde_macros = { version = "^0.6.1", optional = true }
|
||||
serde = "^0.7.5"
|
||||
serde_json = "^0.7.0"
|
||||
serde_macros = { version = "^0.7.5", optional = true }
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "0.7.4"
|
||||
version = "0.7.5"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
|
||||
@@ -46,6 +46,12 @@ pub trait Error: Sized + error::Error {
|
||||
fn missing_field(field: &'static str) -> Self {
|
||||
Error::custom(format!("Missing field `{}`", field))
|
||||
}
|
||||
|
||||
/// Raised when a `Deserialize` struct type received more than one of the
|
||||
/// same struct field.
|
||||
fn duplicate_field(field: &'static str) -> Self {
|
||||
Error::custom(format!("Duplicate field `{}`", field))
|
||||
}
|
||||
}
|
||||
|
||||
/// `Type` represents all the primitive types that can be deserialized. This is used by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_codegen"
|
||||
version = "0.7.4"
|
||||
version = "0.7.5"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Macros to auto-generate implementations for the serde framework"
|
||||
@@ -17,7 +17,7 @@ with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex"
|
||||
|
||||
[build-dependencies]
|
||||
quasi_codegen = { version = "^0.10.0", optional = true }
|
||||
syntex = { version = "^0.31.0", optional = true }
|
||||
syntex = { version = "^0.32.0", optional = true }
|
||||
|
||||
[dependencies]
|
||||
aster = { version = "^0.16.0", default-features = false }
|
||||
|
||||
+24
-77
@@ -180,7 +180,7 @@ pub struct FieldAttrs {
|
||||
skip_serializing_field_if: Option<P<ast::Expr>>,
|
||||
default_expr_if_missing: Option<P<ast::Expr>>,
|
||||
serialize_with: Option<P<ast::Expr>>,
|
||||
deserialize_with: P<ast::Expr>,
|
||||
deserialize_with: Option<ast::Path>,
|
||||
}
|
||||
|
||||
impl FieldAttrs {
|
||||
@@ -197,8 +197,6 @@ impl FieldAttrs {
|
||||
None => { cx.span_bug(field.span, "struct field has no name?") }
|
||||
};
|
||||
|
||||
let identity = quote_expr!(cx, |x| x);
|
||||
|
||||
let mut field_attrs = FieldAttrs {
|
||||
name: Name::new(field_ident),
|
||||
skip_serializing_field: false,
|
||||
@@ -206,7 +204,7 @@ impl FieldAttrs {
|
||||
skip_serializing_field_if: None,
|
||||
default_expr_if_missing: None,
|
||||
serialize_with: None,
|
||||
deserialize_with: identity,
|
||||
deserialize_with: None,
|
||||
};
|
||||
|
||||
for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
@@ -287,14 +285,8 @@ impl FieldAttrs {
|
||||
|
||||
// Parse `#[serde(deserialize_with="...")]`
|
||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize_with" => {
|
||||
let expr = wrap_deserialize_with(
|
||||
cx,
|
||||
&field.ty,
|
||||
generics,
|
||||
try!(parse_lit_into_path(cx, name, lit)),
|
||||
);
|
||||
|
||||
field_attrs.deserialize_with = expr;
|
||||
let path = try!(parse_lit_into_path(cx, name, lit));
|
||||
field_attrs.deserialize_with = Some(path);
|
||||
}
|
||||
|
||||
_ => {
|
||||
@@ -316,22 +308,6 @@ impl FieldAttrs {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Predicate for using a field's default value
|
||||
pub fn expr_is_missing(&self) -> P<ast::Expr> {
|
||||
match self.default_expr_if_missing {
|
||||
Some(ref expr) => expr.clone(),
|
||||
None => {
|
||||
let name = self.name.deserialize_name_expr();
|
||||
AstBuilder::new().expr()
|
||||
.try()
|
||||
.method_call("missing_field").id("visitor")
|
||||
.with_arg(name)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Predicate for ignoring a field when serializing a value
|
||||
pub fn skip_serializing_field(&self) -> bool {
|
||||
self.skip_serializing_field
|
||||
}
|
||||
@@ -344,12 +320,16 @@ impl FieldAttrs {
|
||||
self.skip_serializing_field_if.as_ref()
|
||||
}
|
||||
|
||||
pub fn default_expr_if_missing(&self) -> Option<&P<ast::Expr>> {
|
||||
self.default_expr_if_missing.as_ref()
|
||||
}
|
||||
|
||||
pub fn serialize_with(&self) -> Option<&P<ast::Expr>> {
|
||||
self.serialize_with.as_ref()
|
||||
}
|
||||
|
||||
pub fn deserialize_with(&self) -> &P<ast::Expr> {
|
||||
&self.deserialize_with
|
||||
pub fn deserialize_with(&self) -> Option<&ast::Path> {
|
||||
self.deserialize_with.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,37 +551,37 @@ fn wrap_serialize_with(cx: &ExtCtxt,
|
||||
|
||||
quote_expr!(cx, {
|
||||
trait __SerdeSerializeWith {
|
||||
fn __serde_serialize_with<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: _serde::ser::Serializer;
|
||||
fn __serde_serialize_with<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||
where __S: _serde::ser::Serializer;
|
||||
}
|
||||
|
||||
impl<'a, T> __SerdeSerializeWith for &'a T
|
||||
where T: 'a + __SerdeSerializeWith,
|
||||
impl<'__a, __T> __SerdeSerializeWith for &'__a __T
|
||||
where __T: '__a + __SerdeSerializeWith,
|
||||
{
|
||||
fn __serde_serialize_with<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: _serde::ser::Serializer
|
||||
fn __serde_serialize_with<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||
where __S: _serde::ser::Serializer
|
||||
{
|
||||
(**self).__serde_serialize_with(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl $generics __SerdeSerializeWith for $container_ty $where_clause {
|
||||
fn __serde_serialize_with<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: _serde::ser::Serializer
|
||||
fn __serde_serialize_with<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||
where __S: _serde::ser::Serializer
|
||||
{
|
||||
$expr
|
||||
}
|
||||
}
|
||||
|
||||
struct __SerdeSerializeWithStruct<'a, T: 'a> {
|
||||
value: &'a T,
|
||||
struct __SerdeSerializeWithStruct<'__a, __T: '__a> {
|
||||
value: &'__a __T,
|
||||
}
|
||||
|
||||
impl<'a, T> _serde::ser::Serialize for __SerdeSerializeWithStruct<'a, T>
|
||||
where T: 'a + __SerdeSerializeWith
|
||||
impl<'__a, __T> _serde::ser::Serialize for __SerdeSerializeWithStruct<'__a, __T>
|
||||
where __T: '__a + __SerdeSerializeWith
|
||||
{
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: _serde::ser::Serializer
|
||||
fn serialize<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
|
||||
where __S: _serde::ser::Serializer
|
||||
{
|
||||
self.value.__serde_serialize_with(serializer)
|
||||
}
|
||||
@@ -612,36 +592,3 @@ fn wrap_serialize_with(cx: &ExtCtxt,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// This function wraps the expression in `#[serde(deserialize_with="...")]` in a trait to prevent
|
||||
/// it from accessing the internal `Deserialize` state.
|
||||
fn wrap_deserialize_with(cx: &ExtCtxt,
|
||||
field_ty: &P<ast::Ty>,
|
||||
generics: &ast::Generics,
|
||||
path: ast::Path) -> P<ast::Expr> {
|
||||
// Quasi-quoting doesn't do a great job of expanding generics into paths, so manually build it.
|
||||
let ty_path = AstBuilder::new().path()
|
||||
.segment("__SerdeDeserializeWithStruct")
|
||||
.with_generics(generics.clone())
|
||||
.build()
|
||||
.build();
|
||||
|
||||
let where_clause = &generics.where_clause;
|
||||
|
||||
quote_expr!(cx, ({
|
||||
struct __SerdeDeserializeWithStruct $generics $where_clause {
|
||||
value: $field_ty,
|
||||
}
|
||||
|
||||
impl $generics _serde::de::Deserialize for $ty_path $where_clause {
|
||||
fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<Self, D::Error>
|
||||
where D: _serde::de::Deserializer
|
||||
{
|
||||
let value = try!($path(deserializer));
|
||||
Ok(__SerdeDeserializeWithStruct { value: value })
|
||||
}
|
||||
}
|
||||
|
||||
|visit: $ty_path| visit.value
|
||||
}))
|
||||
}
|
||||
|
||||
+158
-47
@@ -113,22 +113,7 @@ fn deserialized_by_us(field: &ast::StructField) -> bool {
|
||||
return false
|
||||
}
|
||||
ast::MetaItemKind::NameValue(ref name, _) if name == &"deserialize_with" => {
|
||||
// TODO: For now we require `T: Deserialize` even if the
|
||||
// field has `deserialize_with`. The reason is the signature
|
||||
// of serde::de::MapVisitor::missing_field which looks like:
|
||||
//
|
||||
// fn missing_field<T>(...) -> Result<T, Self::Error> where T: Deserialize
|
||||
//
|
||||
// So in order to use missing_field, the type must have the
|
||||
// `T: Deserialize` bound. Some formats rely on this bound
|
||||
// because they treat missing fields as unit.
|
||||
//
|
||||
// Long-term the fix would be to change the signature of
|
||||
// missing_field so it can, for example, use the
|
||||
// `deserialize_with` function to visit a unit in place of
|
||||
// the missing field.
|
||||
//
|
||||
// See https://github.com/serde-rs/serde/issues/259
|
||||
return false
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -356,15 +341,15 @@ fn deserialize_unit_struct(
|
||||
type Value = $type_ident;
|
||||
|
||||
#[inline]
|
||||
fn visit_unit<E>(&mut self) -> ::std::result::Result<$type_ident, E>
|
||||
where E: _serde::de::Error,
|
||||
fn visit_unit<__E>(&mut self) -> ::std::result::Result<$type_ident, __E>
|
||||
where __E: _serde::de::Error,
|
||||
{
|
||||
Ok($type_ident)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<V>(&mut self, mut visitor: V) -> ::std::result::Result<$type_ident, V::Error>
|
||||
where V: _serde::de::SeqVisitor,
|
||||
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$type_ident, __V::Error>
|
||||
where __V: _serde::de::SeqVisitor,
|
||||
{
|
||||
try!(visitor.end());
|
||||
self.visit_unit()
|
||||
@@ -408,8 +393,8 @@ fn deserialize_newtype_struct(
|
||||
type Value = $ty;
|
||||
|
||||
#[inline]
|
||||
fn visit_newtype_struct<D>(&mut self, deserializer: &mut D) -> ::std::result::Result<Self::Value, D::Error>
|
||||
where D: _serde::de::Deserializer,
|
||||
fn visit_newtype_struct<__E>(&mut self, deserializer: &mut __E) -> ::std::result::Result<Self::Value, __E::Error>
|
||||
where __E: _serde::de::Deserializer,
|
||||
{
|
||||
let value = try!(_serde::de::Deserialize::deserialize(deserializer));
|
||||
Ok($type_ident(value))
|
||||
@@ -509,23 +494,39 @@ fn deserialize_seq(
|
||||
fn deserialize_struct_as_seq(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident,
|
||||
struct_path: ast::Path,
|
||||
impl_generics: &ast::Generics,
|
||||
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
let let_values: Vec<_> = fields.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &(_, ref attrs))| {
|
||||
.map(|(i, &(field, ref attrs))| {
|
||||
let name = builder.id(format!("__field{}", i));
|
||||
if attrs.skip_deserializing_field() {
|
||||
let default = attrs.expr_is_missing();
|
||||
let default = expr_is_missing(cx, attrs);
|
||||
quote_stmt!(cx,
|
||||
let $name = $default;
|
||||
).unwrap()
|
||||
} else {
|
||||
let deserialize_with = attrs.deserialize_with();
|
||||
let visit = match attrs.deserialize_with() {
|
||||
None => {
|
||||
let field_ty = &field.ty;
|
||||
quote_expr!(cx, try!(visitor.visit::<$field_ty>()))
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_impl, wrapper_ty) = wrap_deserialize_with(
|
||||
cx, builder, type_ident, impl_generics, &field.ty, path);
|
||||
quote_expr!(cx, {
|
||||
$wrapper
|
||||
$wrapper_impl
|
||||
try!(visitor.visit::<$wrapper_ty>()).map(|wrap| wrap.value)
|
||||
})
|
||||
}
|
||||
};
|
||||
quote_stmt!(cx,
|
||||
let $name = match try!(visitor.visit()) {
|
||||
Some(value) => { $deserialize_with(value) },
|
||||
let $name = match $visit {
|
||||
Some(value) => { value },
|
||||
None => {
|
||||
return Err(_serde::de::Error::end_of_stream());
|
||||
}
|
||||
@@ -587,14 +588,18 @@ fn deserialize_struct(
|
||||
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
type_path.clone(),
|
||||
impl_generics,
|
||||
&fields_with_attrs,
|
||||
));
|
||||
|
||||
let (field_visitor, fields_stmt, visit_map_expr) = try!(deserialize_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
type_path.clone(),
|
||||
impl_generics,
|
||||
&fields_with_attrs,
|
||||
container_attrs,
|
||||
));
|
||||
@@ -843,14 +848,18 @@ fn deserialize_struct_variant(
|
||||
let visit_seq_expr = try!(deserialize_struct_as_seq(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
type_path.clone(),
|
||||
generics,
|
||||
&fields_with_attrs,
|
||||
));
|
||||
|
||||
let (field_visitor, fields_stmt, field_expr) = try!(deserialize_struct_visitor(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
type_path,
|
||||
generics,
|
||||
&fields_with_attrs,
|
||||
container_attrs,
|
||||
));
|
||||
@@ -1008,13 +1017,11 @@ fn deserialize_field_visitor(
|
||||
let impl_item = quote_item!(cx,
|
||||
impl _serde::de::Deserialize for __Field {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<__Field, D::Error>
|
||||
where D: _serde::de::Deserializer,
|
||||
fn deserialize<__D>(deserializer: &mut __D) -> ::std::result::Result<__Field, __D::Error>
|
||||
where __D: _serde::de::Deserializer,
|
||||
{
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct __FieldVisitor<D> {
|
||||
phantom: PhantomData<D>
|
||||
struct __FieldVisitor<__D> {
|
||||
phantom: ::std::marker::PhantomData<__D>
|
||||
}
|
||||
|
||||
impl<__D> _serde::de::Visitor for __FieldVisitor<__D>
|
||||
@@ -1022,26 +1029,30 @@ fn deserialize_field_visitor(
|
||||
{
|
||||
type Value = __Field;
|
||||
|
||||
fn visit_usize<E>(&mut self, value: usize) -> ::std::result::Result<__Field, E>
|
||||
where E: _serde::de::Error,
|
||||
fn visit_usize<__E>(&mut self, value: usize) -> ::std::result::Result<__Field, __E>
|
||||
where __E: _serde::de::Error,
|
||||
{
|
||||
$index_body
|
||||
}
|
||||
|
||||
fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<__Field, E>
|
||||
where E: _serde::de::Error,
|
||||
fn visit_str<__E>(&mut self, value: &str) -> ::std::result::Result<__Field, __E>
|
||||
where __E: _serde::de::Error,
|
||||
{
|
||||
$str_body
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(&mut self, value: &[u8]) -> ::std::result::Result<__Field, E>
|
||||
where E: _serde::de::Error,
|
||||
fn visit_bytes<__E>(&mut self, value: &[u8]) -> ::std::result::Result<__Field, __E>
|
||||
where __E: _serde::de::Error,
|
||||
{
|
||||
$bytes_body
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_struct_field(__FieldVisitor::<D>{ phantom: PhantomData })
|
||||
deserializer.deserialize_struct_field(
|
||||
__FieldVisitor::<__D>{
|
||||
phantom: ::std::marker::PhantomData
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
).unwrap();
|
||||
@@ -1052,7 +1063,9 @@ fn deserialize_field_visitor(
|
||||
fn deserialize_struct_visitor(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident,
|
||||
struct_path: ast::Path,
|
||||
impl_generics: &ast::Generics,
|
||||
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<(Vec<P<ast::Item>>, ast::Stmt, P<ast::Expr>), Error> {
|
||||
@@ -1071,7 +1084,9 @@ fn deserialize_struct_visitor(
|
||||
let visit_map_expr = try!(deserialize_map(
|
||||
cx,
|
||||
builder,
|
||||
type_ident,
|
||||
struct_path,
|
||||
impl_generics,
|
||||
fields,
|
||||
container_attrs,
|
||||
));
|
||||
@@ -1100,7 +1115,9 @@ fn deserialize_struct_visitor(
|
||||
fn deserialize_map(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident,
|
||||
struct_path: ast::Path,
|
||||
impl_generics: &ast::Generics,
|
||||
fields: &[(&ast::StructField, attr::FieldAttrs)],
|
||||
container_attrs: &attr::ContainerAttrs,
|
||||
) -> Result<P<ast::Expr>, Error> {
|
||||
@@ -1114,17 +1131,40 @@ fn deserialize_map(
|
||||
// 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())
|
||||
.map(|&(field, _, name)| {
|
||||
let field_ty = &field.ty;
|
||||
quote_stmt!(cx, let mut $name: Option<$field_ty> = None;).unwrap()
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Match arms to extract a value for a field.
|
||||
let value_arms = fields_attrs_names.iter()
|
||||
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
|
||||
.map(|&(_, ref attrs, name)| {
|
||||
let deserialize_with = attrs.deserialize_with();
|
||||
.map(|&(field, ref attrs, name)| {
|
||||
let deser_name = attrs.name().deserialize_name();
|
||||
let name_str = builder.expr().lit().str(deser_name);
|
||||
|
||||
let visit = match attrs.deserialize_with() {
|
||||
None => {
|
||||
let field_ty = &field.ty;
|
||||
quote_expr!(cx, try!(visitor.visit_value::<$field_ty>()))
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_impl, wrapper_ty) = wrap_deserialize_with(
|
||||
cx, builder, type_ident, impl_generics, &field.ty, path);
|
||||
quote_expr!(cx, ({
|
||||
$wrapper
|
||||
$wrapper_impl
|
||||
try!(visitor.visit_value::<$wrapper_ty>()).value
|
||||
}))
|
||||
}
|
||||
};
|
||||
quote_arm!(cx,
|
||||
__Field::$name => {
|
||||
$name = Some($deserialize_with(try!(visitor.visit_value())));
|
||||
if $name.is_some() {
|
||||
return Err(<__V::Error as _serde::de::Error>::duplicate_field($name_str));
|
||||
}
|
||||
$name = Some($visit);
|
||||
}
|
||||
)
|
||||
})
|
||||
@@ -1155,7 +1195,7 @@ fn deserialize_map(
|
||||
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();
|
||||
let missing_expr = expr_is_missing(cx, attrs);
|
||||
|
||||
Ok(quote_stmt!(cx,
|
||||
let $name = match $name {
|
||||
@@ -1180,7 +1220,7 @@ fn deserialize_map(
|
||||
}
|
||||
},
|
||||
if attrs.skip_deserializing_field() {
|
||||
attrs.expr_is_missing()
|
||||
expr_is_missing(cx, attrs)
|
||||
} else {
|
||||
builder.expr().id(name)
|
||||
}
|
||||
@@ -1192,7 +1232,7 @@ fn deserialize_map(
|
||||
Ok(quote_expr!(cx, {
|
||||
$let_values
|
||||
|
||||
while let Some(key) = try!(visitor.visit_key()) {
|
||||
while let Some(key) = try!(visitor.visit_key::<__Field>()) {
|
||||
match key {
|
||||
$value_arms
|
||||
$skipped_arms
|
||||
@@ -1222,3 +1262,74 @@ fn fields_with_attrs<'a>(
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// This function wraps the expression in `#[serde(deserialize_with="...")]` in
|
||||
/// a trait to prevent it from accessing the internal `Deserialize` state.
|
||||
fn wrap_deserialize_with(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
type_ident: Ident,
|
||||
impl_generics: &ast::Generics,
|
||||
field_ty: &P<ast::Ty>,
|
||||
deserialize_with: &ast::Path,
|
||||
) -> (ast::Stmt, ast::Stmt, ast::Path) {
|
||||
// Quasi-quoting doesn't do a great job of expanding generics into paths,
|
||||
// so manually build it.
|
||||
let wrapper_ty = builder.path()
|
||||
.segment("__SerdeDeserializeWithStruct")
|
||||
.with_generics(impl_generics.clone())
|
||||
.build()
|
||||
.build();
|
||||
|
||||
let where_clause = &impl_generics.where_clause;
|
||||
|
||||
let phantom_ty = builder.path()
|
||||
.segment(type_ident)
|
||||
.with_generics(builder.from_generics(impl_generics.clone())
|
||||
.strip_ty_params()
|
||||
.build())
|
||||
.build()
|
||||
.build();
|
||||
|
||||
(
|
||||
quote_stmt!(cx,
|
||||
struct __SerdeDeserializeWithStruct $impl_generics $where_clause {
|
||||
value: $field_ty,
|
||||
phantom: ::std::marker::PhantomData<$phantom_ty>,
|
||||
}
|
||||
).unwrap(),
|
||||
quote_stmt!(cx,
|
||||
impl $impl_generics _serde::de::Deserialize for $wrapper_ty $where_clause {
|
||||
fn deserialize<__D>(__d: &mut __D) -> ::std::result::Result<Self, __D::Error>
|
||||
where __D: _serde::de::Deserializer
|
||||
{
|
||||
let value = try!($deserialize_with(__d));
|
||||
Ok(__SerdeDeserializeWithStruct {
|
||||
value: value,
|
||||
phantom: ::std::marker::PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
).unwrap(),
|
||||
wrapper_ty,
|
||||
)
|
||||
}
|
||||
|
||||
fn expr_is_missing(
|
||||
cx: &ExtCtxt,
|
||||
attrs: &attr::FieldAttrs,
|
||||
) -> P<ast::Expr> {
|
||||
if let Some(expr) = attrs.default_expr_if_missing() {
|
||||
return expr.clone();
|
||||
}
|
||||
let name = attrs.name().deserialize_name_expr();
|
||||
match attrs.deserialize_with() {
|
||||
None => {
|
||||
quote_expr!(cx, try!(visitor.missing_field($name)))
|
||||
}
|
||||
Some(_) => {
|
||||
quote_expr!(cx, return Err(
|
||||
<__V::Error as _serde::de::Error>::missing_field($name)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,8 +658,8 @@ fn serialize_tuple_struct_visitor(
|
||||
for Visitor $visitor_generics
|
||||
$where_clause {
|
||||
#[inline]
|
||||
fn visit<S>(&mut self, _serializer: &mut S) -> ::std::result::Result<Option<()>, S::Error>
|
||||
where S: _serde::ser::Serializer
|
||||
fn visit<__S>(&mut self, _serializer: &mut __S) -> ::std::result::Result<Option<()>, __S::Error>
|
||||
where __S: _serde::ser::Serializer
|
||||
{
|
||||
match self.state {
|
||||
$arms
|
||||
@@ -763,8 +763,8 @@ fn serialize_struct_visitor(
|
||||
for Visitor $visitor_generics
|
||||
$where_clause {
|
||||
#[inline]
|
||||
fn visit<S>(&mut self, _serializer: &mut S) -> ::std::result::Result<Option<()>, S::Error>
|
||||
where S: _serde::ser::Serializer,
|
||||
fn visit<__S>(&mut self, _serializer: &mut __S) -> ::std::result::Result<Option<()>, __S::Error>
|
||||
where __S: _serde::ser::Serializer,
|
||||
{
|
||||
loop {
|
||||
match self.state {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_macros"
|
||||
version = "0.7.4"
|
||||
version = "0.7.5"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Macros to auto-generate implementations for the serde framework"
|
||||
@@ -17,12 +17,12 @@ nightly-testing = ["clippy", "serde/nightly-testing", "serde_codegen/nightly-tes
|
||||
|
||||
[dependencies]
|
||||
clippy = { version = "^0.*", optional = true }
|
||||
serde_codegen = { version = "^0.7.4", path = "../serde_codegen", default-features = false, features = ["nightly"] }
|
||||
serde_codegen = { version = "^0.7.5", path = "../serde_codegen", default-features = false, features = ["nightly"] }
|
||||
|
||||
[dev-dependencies]
|
||||
compiletest_rs = "^0.1.1"
|
||||
rustc-serialize = "^0.3.16"
|
||||
serde = { version = "^0.7.4", path = "../serde" }
|
||||
serde = { version = "^0.7.5", path = "../serde" }
|
||||
|
||||
[[test]]
|
||||
name = "test"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_tests"
|
||||
version = "0.7.1"
|
||||
version = "0.7.5"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
|
||||
@@ -6,5 +6,6 @@ mod token;
|
||||
mod test_annotations;
|
||||
mod test_bytes;
|
||||
mod test_de;
|
||||
mod test_gen;
|
||||
mod test_macros;
|
||||
mod test_ser;
|
||||
|
||||
@@ -237,6 +237,14 @@ impl Default for NotDeserializeStruct {
|
||||
}
|
||||
}
|
||||
|
||||
impl DeserializeWith for NotDeserializeStruct {
|
||||
fn deserialize_with<D>(_: &mut D) -> Result<Self, D::Error>
|
||||
where D: Deserializer
|
||||
{
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
// Does not implement Deserialize.
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum NotDeserializeEnum { Trouble }
|
||||
@@ -248,13 +256,15 @@ impl MyDefault for NotDeserializeEnum {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
struct ContainsNotDeserialize<A, B, C: MyDefault> {
|
||||
struct ContainsNotDeserialize<A, B, C: DeserializeWith, E: MyDefault> {
|
||||
#[serde(skip_deserializing)]
|
||||
a: A,
|
||||
#[serde(skip_deserializing, default)]
|
||||
b: B,
|
||||
#[serde(skip_deserializing, default="MyDefault::my_default")]
|
||||
#[serde(deserialize_with="DeserializeWith::deserialize_with", default)]
|
||||
c: C,
|
||||
#[serde(skip_deserializing, default="MyDefault::my_default")]
|
||||
e: E,
|
||||
}
|
||||
|
||||
// Tests that a struct field does not need to implement Deserialize if it is
|
||||
@@ -266,7 +276,8 @@ fn test_elt_not_deserialize() {
|
||||
&ContainsNotDeserialize {
|
||||
a: NotDeserializeStruct(123),
|
||||
b: NotDeserializeStruct(123),
|
||||
c: NotDeserializeEnum::Trouble,
|
||||
c: NotDeserializeStruct(123),
|
||||
e: NotDeserializeEnum::Trouble,
|
||||
},
|
||||
vec![
|
||||
Token::StructStart("ContainsNotDeserialize", Some(3)),
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::net;
|
||||
use std::path::PathBuf;
|
||||
|
||||
extern crate serde;
|
||||
use self::serde::de::{Deserializer, Visitor};
|
||||
use self::serde::de::Deserializer;
|
||||
|
||||
use token::{
|
||||
Error,
|
||||
@@ -725,4 +725,32 @@ declare_error_tests! {
|
||||
],
|
||||
Error::UnexpectedToken(Token::SeqSep),
|
||||
}
|
||||
test_duplicate_field_struct<Struct> {
|
||||
vec![
|
||||
Token::MapStart(Some(3)),
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(1),
|
||||
|
||||
Token::MapSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(3),
|
||||
Token::MapEnd,
|
||||
],
|
||||
Error::DuplicateFieldError("a"),
|
||||
}
|
||||
test_duplicate_field_enum<Enum> {
|
||||
vec![
|
||||
Token::EnumMapStart("Enum", "Map", Some(3)),
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(1),
|
||||
|
||||
Token::EnumMapSep,
|
||||
Token::Str("a"),
|
||||
Token::I32(3),
|
||||
Token::EnumMapEnd,
|
||||
],
|
||||
Error::DuplicateFieldError("a"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// These just test that serde_codegen is able to produce code that compiles
|
||||
// successfully when there are a variety of generics involved.
|
||||
|
||||
extern crate serde;
|
||||
use self::serde::ser::{Serialize, Serializer};
|
||||
use self::serde::de::{Deserialize, Deserializer};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct With<T> {
|
||||
t: T,
|
||||
#[serde(serialize_with="ser_i32", deserialize_with="de_i32")]
|
||||
i: i32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct WithRef<'a, T: 'a> {
|
||||
#[serde(skip_deserializing)]
|
||||
t: Option<&'a T>,
|
||||
#[serde(serialize_with="ser_i32", deserialize_with="de_i32")]
|
||||
i: i32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Bounds<T: Serialize + Deserialize> {
|
||||
t: T,
|
||||
option: Option<T>,
|
||||
boxed: Box<T>,
|
||||
option_boxed: Option<Box<T>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct NoBounds<T> {
|
||||
t: T,
|
||||
option: Option<T>,
|
||||
boxed: Box<T>,
|
||||
option_boxed: Option<Box<T>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum EnumWith<T> {
|
||||
A(
|
||||
#[serde(serialize_with="ser_i32", deserialize_with="de_i32")]
|
||||
i32),
|
||||
B {
|
||||
t: T,
|
||||
#[serde(serialize_with="ser_i32", deserialize_with="de_i32")]
|
||||
i: i32 },
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn ser_i32<S: Serializer>(_: &i32, _: &mut S) -> Result<(), S::Error> { panic!() }
|
||||
|
||||
fn de_i32<D: Deserializer>(_: &mut D) -> Result<i32, D::Error> { panic!() }
|
||||
@@ -410,6 +410,7 @@ pub enum Error {
|
||||
UnknownFieldError(String),
|
||||
UnknownVariantError(String),
|
||||
MissingFieldError(&'static str),
|
||||
DuplicateFieldError(&'static str),
|
||||
InvalidName(&'static str),
|
||||
InvalidValue(String),
|
||||
UnexpectedToken(Token<'static>),
|
||||
@@ -429,6 +430,10 @@ impl de::Error for Error {
|
||||
|
||||
fn end_of_stream() -> Error { Error::EndOfStreamError }
|
||||
|
||||
fn invalid_value(msg: &str) -> Error {
|
||||
Error::InvalidValue(msg.to_owned())
|
||||
}
|
||||
|
||||
fn unknown_field(field: &str) -> Error {
|
||||
Error::UnknownFieldError(field.to_owned())
|
||||
}
|
||||
@@ -440,6 +445,10 @@ impl de::Error for Error {
|
||||
fn missing_field(field: &'static str) -> Error {
|
||||
Error::MissingFieldError(field)
|
||||
}
|
||||
|
||||
fn duplicate_field(field: &'static str) -> Error {
|
||||
Error::DuplicateFieldError(field)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
|
||||
Reference in New Issue
Block a user