Compare commits

...

20 Commits

Author SHA1 Message Date
Erick Tryzelaar 41142d41ee Merge pull request #319 from dtolnay/release
Release 0.7.5
2016-05-12 09:30:41 -07:00
Homu fd328c2f2a Auto merge of #320 - dtolnay:syntexv, r=oli-obk
Do not depend on multiple syntex versions

serde_codegen has syntex 0.32 under dependencies, but syntex 0.31 under build-dependencies...
2016-05-12 04:05:47 +09:00
David Tolnay 3ad276944a Do not depend on multiple syntex versions 2016-05-11 09:52:28 -07:00
David Tolnay bb20796e9d Bump version numbers in serde-syntex-example 2016-05-11 09:46:16 -07:00
David Tolnay 709ac64dfc Release 0.7.5 2016-05-11 09:36:30 -07:00
Homu a9a4b2d8e2 Auto merge of #293 - dtolnay:duplicate, r=oli-obk
feat(codegen): Detect repeated struct field when deserializing

Addresses #59. Let me know whether you think we need an escape hatch to opt out of this check.
2016-05-11 19:44:34 +09:00
Oliver Schneider 7374ac499d Merge pull request #311 from dtolnay/deserialize_with
Field with deserialize_with should not implement Deserialize
2016-05-11 11:48:19 +02:00
Oliver Schneider 6596f77e91 Merge pull request #315 from dtolnay/underscore
Prefix type parameters and lifetimes with double underscore
2016-05-11 11:06:25 +02:00
David Tolnay eeb4efc19c feat(codegen): Detect repeated struct field when deserializing 2016-05-10 09:52:51 -07:00
David Tolnay 76b70455ec Field with deserialize_with should not implement Deserialize 2016-05-10 09:50:32 -07:00
David Tolnay f43c8a6267 Prefix type parameters and lifetimes with double underscore 2016-05-10 09:12:38 -07:00
Homu 7aa0b6ce27 Auto merge of #314 - dtolnay:revert, r=erickt
Revert "Enable use in no_std environments"

This commit failed to build even before it was merged. See #313.
2016-05-09 12:47:09 +09:00
David Tolnay efdbf5795f Fix version in serde/Cargo.toml 2016-05-08 20:43:46 -07:00
David Tolnay 55355b6680 Revert "Enable use in no_std environments"
This reverts commit 9c0140968d.
2016-05-08 20:30:21 -07:00
Erick Tryzelaar f8a91e5176 Merge pull request #302 from cmr/no_std
Enable use in no_std environments
2016-05-08 19:24:48 -07:00
Erick Tryzelaar aa0cd9b3dc Merge pull request #308 from dtolnay/inference
Reduce dependence on type inference
2016-05-08 19:21:45 -07:00
Erick Tryzelaar 1f82cd6e3d Merge pull request #310 from dtolnay/withdoc
Clarify serialize_with and deserialize_with documentation
2016-05-08 19:20:12 -07:00
David Tolnay 3caac4e6f3 Clarify serialize_with and deserialize_with documentation 2016-05-08 10:52:23 -07:00
David Tolnay f4414bfc14 Reduce dependence on type inference 2016-05-07 15:25:13 -07:00
Corey Richardson 9c0140968d Enable use in no_std environments
These changes are fairly invasive to imports and uses of non-libcore types,
but allow for some or none of the freestanding crates (core, rustc_unicode,
alloc, collections) to be supported by serde.
2016-05-04 01:26:43 +10:00
15 changed files with 325 additions and 156 deletions
+12 -12
View File
@@ -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
========================
+5 -5
View File
@@ -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
View File
@@ -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"
+6
View File
@@ -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
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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)))
}
}
}
+4 -4
View File
@@ -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 {
+3 -3
View File
@@ -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 -1
View File
@@ -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"
+1
View File
@@ -6,5 +6,6 @@ mod token;
mod test_annotations;
mod test_bytes;
mod test_de;
mod test_gen;
mod test_macros;
mod test_ser;
+14 -3
View File
@@ -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)),
+29 -1
View File
@@ -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"),
}
}
+56
View File
@@ -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!() }
+9
View File
@@ -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 {