mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-14 03:31:02 +00:00
Merge pull request #233 from erickt/remove-format2
Remove support for format-specific renames, replace with ser or de specific renames
This commit is contained in:
@@ -424,15 +424,6 @@ pub trait Deserializer {
|
|||||||
{
|
{
|
||||||
self.deserialize(visitor)
|
self.deserialize(visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify a format string for the deserializer.
|
|
||||||
///
|
|
||||||
/// The deserializer format is used to determine which format
|
|
||||||
/// specific field attributes should be used with the
|
|
||||||
/// deserializer.
|
|
||||||
fn format() -> &'static str {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -327,14 +327,6 @@ pub trait Serializer {
|
|||||||
{
|
{
|
||||||
self.serialize_struct_elt(key, value)
|
self.serialize_struct_elt(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify a format string for the serializer.
|
|
||||||
///
|
|
||||||
/// The serializer format is used to determine which format
|
|
||||||
/// specific field attributes should be used with the serializer.
|
|
||||||
fn format() -> &'static str {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait that is used by a `Serialize` to iterate through a sequence.
|
/// A trait that is used by a `Serialize` to iterate through a sequence.
|
||||||
|
|||||||
+272
-310
@@ -1,90 +1,263 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::ext::base::ExtCtxt;
|
use syntax::ext::base::ExtCtxt;
|
||||||
use syntax::print::pprust::meta_item_to_string;
|
use syntax::print::pprust::meta_item_to_string;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
|
||||||
use aster;
|
use aster::AstBuilder;
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
/// Represents field name information
|
/// Represents container (e.g. struct) attribute information
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FieldNames {
|
pub struct ContainerAttrs {
|
||||||
Global(P<ast::Expr>),
|
ident: ast::Ident,
|
||||||
Format{
|
serialize_name: Option<ast::Lit>,
|
||||||
formats: HashMap<P<ast::Expr>, P<ast::Expr>>,
|
deserialize_name: Option<ast::Lit>,
|
||||||
default: P<ast::Expr>,
|
deny_unknown_fields: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContainerAttrs {
|
||||||
|
/// Extract out the `#[serde(...)]` attributes from an item.
|
||||||
|
pub fn from_item(cx: &ExtCtxt, item: &ast::Item) -> Result<ContainerAttrs, Error> {
|
||||||
|
let mut container_attrs = ContainerAttrs {
|
||||||
|
ident: item.ident,
|
||||||
|
serialize_name: None,
|
||||||
|
deserialize_name: None,
|
||||||
|
deny_unknown_fields: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
for meta_items in item.attrs().iter().filter_map(get_serde_meta_items) {
|
||||||
|
for meta_item in meta_items {
|
||||||
|
match meta_item.node {
|
||||||
|
// Parse `#[serde(rename="foo")]`
|
||||||
|
ast::MetaNameValue(ref name, ref lit) if name == &"rename" => {
|
||||||
|
container_attrs.serialize_name = Some(lit.clone());
|
||||||
|
container_attrs.deserialize_name = Some(lit.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||||
|
ast::MetaList(ref name, ref meta_items) if name == &"rename" => {
|
||||||
|
let (ser_name, de_name) = try!(get_renames(cx, meta_items));
|
||||||
|
container_attrs.serialize_name = ser_name;
|
||||||
|
container_attrs.deserialize_name = de_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(deny_unknown_fields)]`
|
||||||
|
ast::MetaWord(ref name) if name == &"deny_unknown_fields" => {
|
||||||
|
container_attrs.deny_unknown_fields = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
cx.span_err(
|
||||||
|
meta_item.span,
|
||||||
|
&format!("unknown serde container attribute `{}`",
|
||||||
|
meta_item_to_string(meta_item)));
|
||||||
|
|
||||||
|
return Err(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(container_attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the string expression of the field ident.
|
||||||
|
pub fn ident_expr(&self) -> P<ast::Expr> {
|
||||||
|
AstBuilder::new().expr().str(self.ident)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the field name for the field when serializing.
|
||||||
|
pub fn serialize_name_expr(&self) -> P<ast::Expr> {
|
||||||
|
match self.serialize_name {
|
||||||
|
Some(ref name) => AstBuilder::new().expr().build_lit(P(name.clone())),
|
||||||
|
None => self.ident_expr(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the field name for the field when serializing.
|
||||||
|
pub fn deserialize_name_expr(&self) -> P<ast::Expr> {
|
||||||
|
match self.deserialize_name {
|
||||||
|
Some(ref name) => AstBuilder::new().expr().build_lit(P(name.clone())),
|
||||||
|
None => self.ident_expr(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deny_unknown_fields(&self) -> bool {
|
||||||
|
self.deny_unknown_fields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents variant attribute information
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VariantAttrs {
|
||||||
|
ident: ast::Ident,
|
||||||
|
serialize_name: Option<ast::Lit>,
|
||||||
|
deserialize_name: Option<ast::Lit>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VariantAttrs {
|
||||||
|
pub fn from_variant(cx: &ExtCtxt, variant: &ast::Variant) -> Result<Self, Error> {
|
||||||
|
let mut variant_attrs = VariantAttrs {
|
||||||
|
ident: variant.node.name,
|
||||||
|
serialize_name: None,
|
||||||
|
deserialize_name: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
for meta_items in variant.node.attrs.iter().filter_map(get_serde_meta_items) {
|
||||||
|
for meta_item in meta_items {
|
||||||
|
match meta_item.node {
|
||||||
|
// Parse `#[serde(rename="foo")]`
|
||||||
|
ast::MetaNameValue(ref name, ref lit) if name == &"rename" => {
|
||||||
|
variant_attrs.serialize_name = Some(lit.clone());
|
||||||
|
variant_attrs.deserialize_name = Some(lit.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||||
|
ast::MetaList(ref name, ref meta_items) if name == &"rename" => {
|
||||||
|
let (ser_name, de_name) = try!(get_renames(cx, meta_items));
|
||||||
|
variant_attrs.serialize_name = ser_name;
|
||||||
|
variant_attrs.deserialize_name = de_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
cx.span_err(
|
||||||
|
meta_item.span,
|
||||||
|
&format!("unknown serde variant attribute `{}`",
|
||||||
|
meta_item_to_string(meta_item)));
|
||||||
|
|
||||||
|
return Err(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(variant_attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the string expression of the field ident.
|
||||||
|
pub fn ident_expr(&self) -> P<ast::Expr> {
|
||||||
|
AstBuilder::new().expr().str(self.ident)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the field name for the field when serializing.
|
||||||
|
pub fn serialize_name_expr(&self) -> P<ast::Expr> {
|
||||||
|
match self.serialize_name {
|
||||||
|
Some(ref name) => AstBuilder::new().expr().build_lit(P(name.clone())),
|
||||||
|
None => self.ident_expr(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the field name for the field when serializing.
|
||||||
|
pub fn deserialize_name_expr(&self) -> P<ast::Expr> {
|
||||||
|
match self.deserialize_name {
|
||||||
|
Some(ref name) => AstBuilder::new().expr().build_lit(P(name.clone())),
|
||||||
|
None => self.ident_expr(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents field attribute information
|
/// Represents field attribute information
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FieldAttrs {
|
pub struct FieldAttrs {
|
||||||
|
ident: ast::Ident,
|
||||||
|
serialize_name: Option<ast::Lit>,
|
||||||
|
deserialize_name: Option<ast::Lit>,
|
||||||
skip_serializing_field: bool,
|
skip_serializing_field: bool,
|
||||||
skip_serializing_field_if_empty: bool,
|
skip_serializing_field_if_empty: bool,
|
||||||
skip_serializing_field_if_none: bool,
|
skip_serializing_field_if_none: bool,
|
||||||
names: FieldNames,
|
|
||||||
use_default: bool,
|
use_default: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FieldAttrs {
|
impl FieldAttrs {
|
||||||
/// Return a set of formats that the field has attributes for.
|
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||||
pub fn formats(&self) -> HashSet<P<ast::Expr>> {
|
pub fn from_field(cx: &ExtCtxt, field: &ast::StructField) -> Result<Self, Error> {
|
||||||
match self.names {
|
let field_ident = match field.node.ident() {
|
||||||
FieldNames::Format { ref formats, .. } => {
|
Some(ident) => ident,
|
||||||
let mut set = HashSet::new();
|
None => { cx.span_bug(field.span, "struct field has no name?") }
|
||||||
for (fmt, _) in formats.iter() {
|
};
|
||||||
set.insert(fmt.clone());
|
|
||||||
};
|
|
||||||
set
|
|
||||||
},
|
|
||||||
_ => HashSet::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return an expression for the field key name for serialisation.
|
let mut field_attrs = FieldAttrs {
|
||||||
///
|
ident: field_ident,
|
||||||
/// The resulting expression assumes that `S` refers to a type
|
serialize_name: None,
|
||||||
/// that implements `Serializer`.
|
deserialize_name: None,
|
||||||
pub fn serializer_key_expr(&self, cx: &ExtCtxt) -> P<ast::Expr> {
|
skip_serializing_field: false,
|
||||||
match self.names {
|
skip_serializing_field_if_empty: false,
|
||||||
FieldNames::Global(ref name) => name.clone(),
|
skip_serializing_field_if_none: false,
|
||||||
FieldNames::Format { ref formats, ref default } => {
|
use_default: false,
|
||||||
let arms = formats.iter()
|
};
|
||||||
.map(|(fmt, lit)| {
|
|
||||||
quote_arm!(cx, $fmt => { $lit })
|
for meta_items in field.node.attrs.iter().filter_map(get_serde_meta_items) {
|
||||||
})
|
for meta_item in meta_items {
|
||||||
.collect::<Vec<_>>();
|
match meta_item.node {
|
||||||
quote_expr!(cx,
|
// Parse `#[serde(rename="foo")]`
|
||||||
match S::format() {
|
ast::MetaNameValue(ref name, ref lit) if name == &"rename" => {
|
||||||
$arms
|
field_attrs.serialize_name = Some(lit.clone());
|
||||||
_ => { $default }
|
field_attrs.deserialize_name = Some(lit.clone());
|
||||||
}
|
}
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the default field name for the field.
|
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||||
pub fn default_key_expr(&self) -> &P<ast::Expr> {
|
ast::MetaList(ref name, ref meta_items) if name == &"rename" => {
|
||||||
match self.names {
|
let (ser_name, de_name) = try!(get_renames(cx, meta_items));
|
||||||
FieldNames::Global(ref expr) => expr,
|
field_attrs.serialize_name = ser_name;
|
||||||
FieldNames::Format { ref default, .. } => default,
|
field_attrs.deserialize_name = de_name;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the field name for the field in the specified format.
|
// Parse `#[serde(default)]`
|
||||||
pub fn key_expr(&self, format: &P<ast::Expr>) -> &P<ast::Expr> {
|
ast::MetaWord(ref name) if name == &"default" => {
|
||||||
match self.names {
|
field_attrs.use_default = true;
|
||||||
FieldNames::Global(ref expr) => expr,
|
}
|
||||||
FieldNames::Format { ref formats, ref default } => {
|
|
||||||
formats.get(format).unwrap_or(default)
|
// Parse `#[serde(skip_serializing)]`
|
||||||
|
ast::MetaWord(ref name) if name == &"skip_serializing" => {
|
||||||
|
field_attrs.skip_serializing_field = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(skip_serializing_if_none)]`
|
||||||
|
ast::MetaWord(ref name) if name == &"skip_serializing_if_none" => {
|
||||||
|
field_attrs.skip_serializing_field_if_none = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse `#[serde(skip_serializing_if_empty)]`
|
||||||
|
ast::MetaWord(ref name) if name == &"skip_serializing_if_empty" => {
|
||||||
|
field_attrs.skip_serializing_field_if_empty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
cx.span_err(
|
||||||
|
meta_item.span,
|
||||||
|
&format!("unknown serde field attribute `{}`",
|
||||||
|
meta_item_to_string(meta_item)));
|
||||||
|
|
||||||
|
return Err(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(field_attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the string expression of the field ident.
|
||||||
|
pub fn ident_expr(&self) -> P<ast::Expr> {
|
||||||
|
AstBuilder::new().expr().str(self.ident)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the field name for the field when serializing.
|
||||||
|
pub fn serialize_name_expr(&self) -> P<ast::Expr> {
|
||||||
|
match self.serialize_name {
|
||||||
|
Some(ref name) => AstBuilder::new().expr().build_lit(P(name.clone())),
|
||||||
|
None => self.ident_expr(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the field name for the field when deserializing.
|
||||||
|
pub fn deserialize_name_expr(&self) -> P<ast::Expr> {
|
||||||
|
match self.deserialize_name {
|
||||||
|
Some(ref name) => AstBuilder::new().expr().build_lit(P(name.clone())),
|
||||||
|
None => self.ident_expr(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Predicate for using a field's default value
|
/// Predicate for using a field's default value
|
||||||
@@ -106,260 +279,49 @@ impl FieldAttrs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FieldAttrsBuilder<'a> {
|
|
||||||
cx: &'a ExtCtxt<'a>,
|
|
||||||
builder: &'a aster::AstBuilder,
|
|
||||||
skip_serializing_field: bool,
|
|
||||||
skip_serializing_field_if_empty: bool,
|
|
||||||
skip_serializing_field_if_none: bool,
|
|
||||||
name: Option<P<ast::Expr>>,
|
|
||||||
format_rename: HashMap<P<ast::Expr>, P<ast::Expr>>,
|
|
||||||
use_default: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FieldAttrsBuilder<'a> {
|
|
||||||
pub fn new(cx: &'a ExtCtxt<'a>,
|
|
||||||
builder: &'a aster::AstBuilder) -> FieldAttrsBuilder<'a> {
|
|
||||||
FieldAttrsBuilder {
|
|
||||||
cx: cx,
|
|
||||||
builder: builder,
|
|
||||||
skip_serializing_field: false,
|
|
||||||
skip_serializing_field_if_empty: false,
|
|
||||||
skip_serializing_field_if_none: false,
|
|
||||||
name: None,
|
|
||||||
format_rename: HashMap::new(),
|
|
||||||
use_default: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn field(mut self, field: &ast::StructField) -> Result<FieldAttrsBuilder<'a>, Error> {
|
|
||||||
match field.node.kind {
|
|
||||||
ast::NamedField(name, _) => {
|
|
||||||
self.name = Some(self.builder.expr().str(name));
|
|
||||||
}
|
|
||||||
ast::UnnamedField(_) => { }
|
|
||||||
};
|
|
||||||
|
|
||||||
self.attrs(&field.node.attrs)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn attrs(mut self, attrs: &[ast::Attribute]) -> Result<FieldAttrsBuilder<'a>, Error> {
|
|
||||||
for attr in attrs {
|
|
||||||
self = try!(self.attr(attr));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn attr(mut self, attr: &ast::Attribute) -> Result<FieldAttrsBuilder<'a>, Error> {
|
|
||||||
match attr.node.value.node {
|
|
||||||
ast::MetaList(ref name, ref items) if name == &"serde" => {
|
|
||||||
attr::mark_used(&attr);
|
|
||||||
for item in items {
|
|
||||||
self = try!(self.meta_item(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn meta_item(mut self,
|
|
||||||
meta_item: &P<ast::MetaItem>) -> Result<FieldAttrsBuilder<'a>, Error> {
|
|
||||||
match meta_item.node {
|
|
||||||
ast::MetaNameValue(ref name, ref lit) if name == &"rename" => {
|
|
||||||
let expr = self.builder.expr().build_lit(P(lit.clone()));
|
|
||||||
|
|
||||||
Ok(self.name(expr))
|
|
||||||
}
|
|
||||||
ast::MetaList(ref name, ref items) if name == &"rename" => {
|
|
||||||
for item in items {
|
|
||||||
match item.node {
|
|
||||||
ast::MetaNameValue(ref name, ref lit) => {
|
|
||||||
let name = self.builder.expr().str(name);
|
|
||||||
let expr = self.builder.expr().build_lit(P(lit.clone()));
|
|
||||||
|
|
||||||
self = self.format_rename(name, expr);
|
|
||||||
}
|
|
||||||
_ => { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
ast::MetaWord(ref name) if name == &"default" => {
|
|
||||||
Ok(self.default())
|
|
||||||
}
|
|
||||||
ast::MetaWord(ref name) if name == &"skip_serializing" => {
|
|
||||||
Ok(self.skip_serializing_field())
|
|
||||||
}
|
|
||||||
ast::MetaWord(ref name) if name == &"skip_serializing_if_empty" => {
|
|
||||||
Ok(self.skip_serializing_field_if_empty())
|
|
||||||
}
|
|
||||||
ast::MetaWord(ref name) if name == &"skip_serializing_if_none" => {
|
|
||||||
Ok(self.skip_serializing_field_if_none())
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.cx.span_err(
|
|
||||||
meta_item.span,
|
|
||||||
&format!("unknown serde field attribute `{}`",
|
|
||||||
meta_item_to_string(meta_item)));
|
|
||||||
Err(Error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn skip_serializing_field(mut self) -> FieldAttrsBuilder<'a> {
|
|
||||||
self.skip_serializing_field = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn skip_serializing_field_if_empty(mut self) -> FieldAttrsBuilder<'a> {
|
|
||||||
self.skip_serializing_field_if_empty = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn skip_serializing_field_if_none(mut self) -> FieldAttrsBuilder<'a> {
|
|
||||||
self.skip_serializing_field_if_none = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(mut self, name: P<ast::Expr>) -> FieldAttrsBuilder<'a> {
|
|
||||||
self.name = Some(name);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn format_rename(mut self, format: P<ast::Expr>, name: P<ast::Expr>) -> FieldAttrsBuilder<'a> {
|
|
||||||
self.format_rename.insert(format, name);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default(mut self) -> FieldAttrsBuilder<'a> {
|
|
||||||
self.use_default = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(self) -> FieldAttrs {
|
|
||||||
let name = self.name.expect("here");
|
|
||||||
let names = if self.format_rename.is_empty() {
|
|
||||||
FieldNames::Global(name)
|
|
||||||
} else {
|
|
||||||
FieldNames::Format {
|
|
||||||
formats: self.format_rename,
|
|
||||||
default: name,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FieldAttrs {
|
|
||||||
skip_serializing_field: self.skip_serializing_field,
|
|
||||||
skip_serializing_field_if_empty: self.skip_serializing_field_if_empty,
|
|
||||||
skip_serializing_field_if_none: self.skip_serializing_field_if_none,
|
|
||||||
names: names,
|
|
||||||
use_default: self.use_default,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents container (e.g. struct) attribute information
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ContainerAttrs {
|
|
||||||
deny_unknown_fields: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ContainerAttrs {
|
|
||||||
pub fn deny_unknown_fields(&self) -> bool {
|
|
||||||
self.deny_unknown_fields
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ContainerAttrsBuilder<'a> {
|
|
||||||
cx: &'a ExtCtxt<'a>,
|
|
||||||
deny_unknown_fields: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ContainerAttrsBuilder<'a> {
|
|
||||||
pub fn new(cx: &'a ExtCtxt) -> Self {
|
|
||||||
ContainerAttrsBuilder {
|
|
||||||
cx: cx,
|
|
||||||
deny_unknown_fields: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn attrs(mut self, attrs: &[ast::Attribute]) -> Result<Self, Error> {
|
|
||||||
for attr in attrs {
|
|
||||||
self = try!(self.attr(attr));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn attr(mut self, attr: &ast::Attribute) -> Result<Self, Error> {
|
|
||||||
match attr.node.value.node {
|
|
||||||
ast::MetaList(ref name, ref items) if name == &"serde" => {
|
|
||||||
attr::mark_used(&attr);
|
|
||||||
for item in items {
|
|
||||||
self = try!(self.meta_item(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn meta_item(self, meta_item: &P<ast::MetaItem>) -> Result<Self, Error> {
|
|
||||||
match meta_item.node {
|
|
||||||
ast::MetaWord(ref name) if name == &"deny_unknown_fields" => {
|
|
||||||
Ok(self.deny_unknown_fields())
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.cx.span_err(
|
|
||||||
meta_item.span,
|
|
||||||
&format!("unknown serde container attribute `{}`",
|
|
||||||
meta_item_to_string(meta_item)));
|
|
||||||
Err(Error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deny_unknown_fields(mut self) -> Self {
|
|
||||||
self.deny_unknown_fields = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(self) -> ContainerAttrs {
|
|
||||||
ContainerAttrs {
|
|
||||||
deny_unknown_fields: self.deny_unknown_fields,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extract out the `#[serde(...)]` attributes from an item.
|
|
||||||
pub fn get_container_attrs(cx: &ExtCtxt,
|
|
||||||
container: &ast::Item,
|
|
||||||
) -> Result<ContainerAttrs, Error> {
|
|
||||||
let builder = ContainerAttrsBuilder::new(cx);
|
|
||||||
let builder = try!(builder.attrs(container.attrs()));
|
|
||||||
Ok(builder.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||||
pub fn get_struct_field_attrs(cx: &ExtCtxt,
|
pub fn get_struct_field_attrs(cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
fields: &[ast::StructField]) -> Result<Vec<FieldAttrs>, Error> {
|
||||||
fields: &[ast::StructField]
|
fields.iter()
|
||||||
) -> Result<Vec<FieldAttrs>, Error> {
|
.map(|field| FieldAttrs::from_field(cx, field))
|
||||||
let mut attrs = vec![];
|
.collect()
|
||||||
for field in fields {
|
}
|
||||||
let builder = FieldAttrsBuilder::new(cx, builder);
|
|
||||||
let builder = try!(builder.field(field));
|
fn get_renames(cx: &ExtCtxt,
|
||||||
let attr = builder.build();
|
items: &[P<ast::MetaItem>]) -> Result<(Option<ast::Lit>, Option<ast::Lit>), Error> {
|
||||||
attrs.push(attr);
|
let mut ser_name = None;
|
||||||
|
let mut de_name = None;
|
||||||
|
|
||||||
|
for item in items {
|
||||||
|
match item.node {
|
||||||
|
ast::MetaNameValue(ref name, ref lit) if name == &"serialize" => {
|
||||||
|
ser_name = Some(lit.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::MetaNameValue(ref name, ref lit) if name == &"deserialize" => {
|
||||||
|
de_name = Some(lit.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
cx.span_err(
|
||||||
|
item.span,
|
||||||
|
&format!("unknown rename attribute `{}`",
|
||||||
|
meta_item_to_string(item)));
|
||||||
|
|
||||||
|
return Err(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(attrs)
|
Ok((ser_name, de_name))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_serde_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
|
||||||
|
match attr.node.value.node {
|
||||||
|
ast::MetaList(ref name, ref items) if name == &"serde" => {
|
||||||
|
attr::mark_used(&attr);
|
||||||
|
Some(items)
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-107
@@ -1,5 +1,3 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use aster;
|
use aster;
|
||||||
|
|
||||||
use syntax::ast::{
|
use syntax::ast::{
|
||||||
@@ -14,8 +12,7 @@ use syntax::ext::base::{Annotatable, ExtCtxt};
|
|||||||
use syntax::ext::build::AstBuilder;
|
use syntax::ext::build::AstBuilder;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
|
||||||
use attr::{self, ContainerAttrs};
|
use attr;
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
pub fn expand_derive_deserialize(
|
pub fn expand_derive_deserialize(
|
||||||
@@ -88,7 +85,7 @@ fn deserialize_body(
|
|||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let container_attrs = try!(attr::get_container_attrs(cx, item));
|
let container_attrs = try!(attr::ContainerAttrs::from_item(cx, item));
|
||||||
|
|
||||||
match item.node {
|
match item.node {
|
||||||
ast::ItemStruct(ref variant_data, _) => {
|
ast::ItemStruct(ref variant_data, _) => {
|
||||||
@@ -129,14 +126,14 @@ fn deserialize_item_struct(
|
|||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
span: Span,
|
span: Span,
|
||||||
variant_data: &ast::VariantData,
|
variant_data: &ast::VariantData,
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
match *variant_data {
|
match *variant_data {
|
||||||
ast::VariantData::Unit(_) => {
|
ast::VariantData::Unit(_) => {
|
||||||
deserialize_unit_struct(
|
deserialize_unit_struct(
|
||||||
cx,
|
cx,
|
||||||
&builder,
|
|
||||||
item.ident,
|
item.ident,
|
||||||
|
container_attrs,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
||||||
@@ -146,6 +143,7 @@ fn deserialize_item_struct(
|
|||||||
item.ident,
|
item.ident,
|
||||||
impl_generics,
|
impl_generics,
|
||||||
ty,
|
ty,
|
||||||
|
container_attrs,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ast::VariantData::Tuple(ref fields, _) => {
|
ast::VariantData::Tuple(ref fields, _) => {
|
||||||
@@ -160,6 +158,7 @@ fn deserialize_item_struct(
|
|||||||
impl_generics,
|
impl_generics,
|
||||||
ty,
|
ty,
|
||||||
fields.len(),
|
fields.len(),
|
||||||
|
container_attrs,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ast::VariantData::Struct(ref fields, _) => {
|
ast::VariantData::Struct(ref fields, _) => {
|
||||||
@@ -264,10 +263,10 @@ fn deserializer_ty_arg(builder: &aster::AstBuilder) -> P<ast::Ty>{
|
|||||||
|
|
||||||
fn deserialize_unit_struct(
|
fn deserialize_unit_struct(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
|
||||||
type_ident: Ident,
|
type_ident: Ident,
|
||||||
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = container_attrs.deserialize_name_expr();
|
||||||
|
|
||||||
Ok(quote_expr!(cx, {
|
Ok(quote_expr!(cx, {
|
||||||
struct __Visitor;
|
struct __Visitor;
|
||||||
@@ -301,6 +300,7 @@ fn deserialize_newtype_struct(
|
|||||||
type_ident: Ident,
|
type_ident: Ident,
|
||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let where_clause = &impl_generics.where_clause;
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
@@ -318,7 +318,7 @@ fn deserialize_newtype_struct(
|
|||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = container_attrs.deserialize_name_expr();
|
||||||
|
|
||||||
Ok(quote_expr!(cx, {
|
Ok(quote_expr!(cx, {
|
||||||
$visitor_item
|
$visitor_item
|
||||||
@@ -353,6 +353,7 @@ fn deserialize_tuple_struct(
|
|||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
fields: usize,
|
fields: usize,
|
||||||
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let where_clause = &impl_generics.where_clause;
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
@@ -370,7 +371,7 @@ fn deserialize_tuple_struct(
|
|||||||
fields,
|
fields,
|
||||||
);
|
);
|
||||||
|
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = container_attrs.deserialize_name_expr();
|
||||||
|
|
||||||
Ok(quote_expr!(cx, {
|
Ok(quote_expr!(cx, {
|
||||||
$visitor_item
|
$visitor_item
|
||||||
@@ -478,7 +479,7 @@ fn deserialize_struct(
|
|||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let where_clause = &impl_generics.where_clause;
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
@@ -506,7 +507,7 @@ fn deserialize_struct(
|
|||||||
container_attrs
|
container_attrs
|
||||||
));
|
));
|
||||||
|
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = container_attrs.deserialize_name_expr();
|
||||||
|
|
||||||
Ok(quote_expr!(cx, {
|
Ok(quote_expr!(cx, {
|
||||||
$field_visitor
|
$field_visitor
|
||||||
@@ -544,23 +545,23 @@ fn deserialize_item_enum(
|
|||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
enum_def: &EnumDef,
|
enum_def: &EnumDef,
|
||||||
container_attrs: &ContainerAttrs
|
container_attrs: &attr::ContainerAttrs
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let where_clause = &impl_generics.where_clause;
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = container_attrs.deserialize_name_expr();
|
||||||
|
|
||||||
let variant_visitor = deserialize_field_visitor(
|
let variant_visitor = deserialize_field_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
enum_def.variants.iter()
|
try!(
|
||||||
.map(|variant| {
|
enum_def.variants.iter()
|
||||||
let expr = builder.expr().str(variant.node.name);
|
.map(|variant| {
|
||||||
attr::FieldAttrsBuilder::new(cx, builder)
|
let attrs = try!(attr::VariantAttrs::from_variant(cx, variant));
|
||||||
.name(expr)
|
Ok(attrs.deserialize_name_expr())
|
||||||
.build()
|
})
|
||||||
})
|
.collect()
|
||||||
.collect(),
|
),
|
||||||
container_attrs,
|
container_attrs,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -642,7 +643,7 @@ fn deserialize_variant(
|
|||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
variant: &ast::Variant,
|
variant: &ast::Variant,
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let variant_ident = variant.node.name;
|
let variant_ident = variant.node.name;
|
||||||
|
|
||||||
@@ -735,7 +736,7 @@ fn deserialize_struct_variant(
|
|||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let where_clause = &generics.where_clause;
|
let where_clause = &generics.where_clause;
|
||||||
|
|
||||||
@@ -798,11 +799,11 @@ fn deserialize_struct_variant(
|
|||||||
fn deserialize_field_visitor(
|
fn deserialize_field_visitor(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
field_attrs: Vec<attr::FieldAttrs>,
|
field_names: Vec<P<ast::Expr>>,
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Vec<P<ast::Item>> {
|
) -> Vec<P<ast::Item>> {
|
||||||
// Create the field names for the fields.
|
// Create the field names for the fields.
|
||||||
let field_idents: Vec<ast::Ident> = (0 .. field_attrs.len())
|
let field_idents: Vec<ast::Ident> = (0 .. field_names.len())
|
||||||
.map(|i| builder.id(format!("__field{}", i)))
|
.map(|i| builder.id(format!("__field{}", i)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -838,19 +839,11 @@ fn deserialize_field_visitor(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// A set of all the formats that have specialized field attributes
|
|
||||||
let formats = field_attrs.iter()
|
|
||||||
.fold(HashSet::new(), |mut set, field_expr| {
|
|
||||||
set.extend(field_expr.formats());
|
|
||||||
set
|
|
||||||
});
|
|
||||||
|
|
||||||
// Match arms to extract a field from a string
|
// Match arms to extract a field from a string
|
||||||
let default_field_arms: Vec<_> = field_idents.iter()
|
let default_field_arms: Vec<_> = field_idents.iter()
|
||||||
.zip(field_attrs.iter())
|
.zip(field_names.iter())
|
||||||
.map(|(field_ident, field_expr)| {
|
.map(|(field_ident, field_name)| {
|
||||||
let expr = field_expr.default_key_expr();
|
quote_arm!(cx, $field_name => { Ok(__Field::$field_ident) })
|
||||||
quote_arm!(cx, $expr => { Ok(__Field::$field_ident) })
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -860,49 +853,12 @@ fn deserialize_field_visitor(
|
|||||||
quote_expr!(cx, Err(::serde::de::Error::unknown_field(value)))
|
quote_expr!(cx, Err(::serde::de::Error::unknown_field(value)))
|
||||||
};
|
};
|
||||||
|
|
||||||
let str_body = if formats.is_empty() {
|
let str_body = quote_expr!(cx,
|
||||||
// No formats specific attributes, so no match on format required
|
match value {
|
||||||
quote_expr!(cx,
|
$default_field_arms
|
||||||
match value {
|
_ => $fallthrough_arm_expr
|
||||||
$default_field_arms
|
}
|
||||||
_ => { $fallthrough_arm_expr }
|
);
|
||||||
})
|
|
||||||
} else {
|
|
||||||
let field_arms: Vec<_> = formats.iter()
|
|
||||||
.map(|fmt| {
|
|
||||||
field_idents.iter()
|
|
||||||
.zip(field_attrs.iter())
|
|
||||||
.map(|(field_ident, field_expr)| {
|
|
||||||
let expr = field_expr.key_expr(fmt);
|
|
||||||
quote_arm!(cx, $expr => { Ok(__Field::$field_ident) })
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let fmt_matches: Vec<_> = formats.iter()
|
|
||||||
.zip(field_arms.iter())
|
|
||||||
.map(|(ref fmt, ref arms)| {
|
|
||||||
quote_arm!(cx, $fmt => {
|
|
||||||
match value {
|
|
||||||
$arms
|
|
||||||
_ => {
|
|
||||||
$fallthrough_arm_expr
|
|
||||||
}
|
|
||||||
}})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
quote_expr!(cx,
|
|
||||||
match __D::format() {
|
|
||||||
$fmt_matches
|
|
||||||
_ => match value {
|
|
||||||
$default_field_arms
|
|
||||||
_ => $fallthrough_arm_expr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let impl_item = quote_item!(cx,
|
let impl_item = quote_item!(cx,
|
||||||
impl ::serde::de::Deserialize for __Field {
|
impl ::serde::de::Deserialize for __Field {
|
||||||
@@ -963,12 +919,19 @@ fn deserialize_struct_visitor(
|
|||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<(Vec<P<ast::Item>>, P<ast::Stmt>, P<ast::Expr>), Error> {
|
) -> Result<(Vec<P<ast::Item>>, P<ast::Stmt>, P<ast::Expr>), Error> {
|
||||||
let field_visitor = deserialize_field_visitor(
|
let field_visitor = deserialize_field_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
try!(attr::get_struct_field_attrs(cx, builder, fields)),
|
try!(
|
||||||
|
fields.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let attrs = try!(attr::FieldAttrs::from_field(cx, field));
|
||||||
|
Ok(attrs.deserialize_name_expr())
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
),
|
||||||
container_attrs
|
container_attrs
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1006,7 +969,7 @@ fn deserialize_map(
|
|||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
struct_path: ast::Path,
|
struct_path: ast::Path,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
container_attrs: &ContainerAttrs,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> 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 field_names: Vec<ast::Ident> = (0 .. fields.len())
|
||||||
@@ -1040,33 +1003,16 @@ fn deserialize_map(
|
|||||||
.chain(ignored_arm.into_iter())
|
.chain(ignored_arm.into_iter())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let field_attrs = try!(attr::get_struct_field_attrs(cx, builder, fields));
|
let field_attrs = try!(attr::get_struct_field_attrs(cx, fields));
|
||||||
|
|
||||||
let extract_values: Vec<P<ast::Stmt>> = field_names.iter()
|
let extract_values = field_names.iter()
|
||||||
.zip(field_attrs.iter())
|
.zip(field_attrs.iter())
|
||||||
.map(|(field_name, field_attr)| {
|
.map(|(field_name, field_attr)| {
|
||||||
let missing_expr = if field_attr.use_default() {
|
let missing_expr = if field_attr.use_default() {
|
||||||
quote_expr!(cx, ::std::default::Default::default())
|
quote_expr!(cx, ::std::default::Default::default())
|
||||||
} else {
|
} else {
|
||||||
let formats = field_attr.formats();
|
let name = field_attr.ident_expr();
|
||||||
let arms : Vec<_> = formats.iter()
|
quote_expr!(cx, try!(visitor.missing_field($name)))
|
||||||
.map(|format| {
|
|
||||||
let key_expr = field_attr.key_expr(format);
|
|
||||||
quote_arm!(cx, $format => { $key_expr })
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let default = field_attr.default_key_expr();
|
|
||||||
if arms.is_empty() {
|
|
||||||
quote_expr!(cx, try!(visitor.missing_field($default)))
|
|
||||||
} else {
|
|
||||||
quote_expr!(
|
|
||||||
cx,
|
|
||||||
try!(visitor.missing_field(
|
|
||||||
match __D::format() {
|
|
||||||
$arms
|
|
||||||
_ => { $default }
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
quote_stmt!(cx,
|
quote_stmt!(cx,
|
||||||
@@ -1076,7 +1022,7 @@ fn deserialize_map(
|
|||||||
};
|
};
|
||||||
).unwrap()
|
).unwrap()
|
||||||
})
|
})
|
||||||
.collect();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let result = builder.expr().struct_path(struct_path)
|
let result = builder.expr().struct_path(struct_path)
|
||||||
.with_id_exprs(
|
.with_id_exprs(
|
||||||
|
|||||||
+25
-25
@@ -84,20 +84,18 @@ fn serialize_body(
|
|||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
// Note: While we don't have any container attributes, we still want to try to
|
let container_attrs = try!(attr::ContainerAttrs::from_item(cx, item));
|
||||||
// parse them so we can report a proper error if we get passed an unknown attribute.
|
|
||||||
let _ = try!(attr::get_container_attrs(cx, item));
|
|
||||||
|
|
||||||
match item.node {
|
match item.node {
|
||||||
ast::ItemStruct(ref variant_data, _) => {
|
ast::ItemStruct(ref variant_data, _) => {
|
||||||
serialize_item_struct(
|
serialize_item_struct(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
item,
|
|
||||||
impl_generics,
|
impl_generics,
|
||||||
ty,
|
ty,
|
||||||
item.span,
|
item.span,
|
||||||
variant_data,
|
variant_data,
|
||||||
|
&container_attrs,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ast::ItemEnum(ref enum_def, _) => {
|
ast::ItemEnum(ref enum_def, _) => {
|
||||||
@@ -108,6 +106,7 @@ fn serialize_body(
|
|||||||
impl_generics,
|
impl_generics,
|
||||||
ty,
|
ty,
|
||||||
enum_def,
|
enum_def,
|
||||||
|
&container_attrs,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -120,25 +119,23 @@ fn serialize_body(
|
|||||||
fn serialize_item_struct(
|
fn serialize_item_struct(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
item: &Item,
|
|
||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
span: Span,
|
span: Span,
|
||||||
variant_data: &ast::VariantData,
|
variant_data: &ast::VariantData,
|
||||||
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
match *variant_data {
|
match *variant_data {
|
||||||
ast::VariantData::Unit(_) => {
|
ast::VariantData::Unit(_) => {
|
||||||
serialize_unit_struct(
|
serialize_unit_struct(
|
||||||
cx,
|
cx,
|
||||||
&builder,
|
container_attrs,
|
||||||
item.ident,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
ast::VariantData::Tuple(ref fields, _) if fields.len() == 1 => {
|
||||||
serialize_newtype_struct(
|
serialize_newtype_struct(
|
||||||
cx,
|
cx,
|
||||||
&builder,
|
container_attrs,
|
||||||
item.ident,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ast::VariantData::Tuple(ref fields, _) => {
|
ast::VariantData::Tuple(ref fields, _) => {
|
||||||
@@ -149,10 +146,10 @@ fn serialize_item_struct(
|
|||||||
serialize_tuple_struct(
|
serialize_tuple_struct(
|
||||||
cx,
|
cx,
|
||||||
&builder,
|
&builder,
|
||||||
item.ident,
|
|
||||||
impl_generics,
|
impl_generics,
|
||||||
ty,
|
ty,
|
||||||
fields.len(),
|
fields.len(),
|
||||||
|
container_attrs,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ast::VariantData::Struct(ref fields, _) => {
|
ast::VariantData::Struct(ref fields, _) => {
|
||||||
@@ -163,10 +160,10 @@ fn serialize_item_struct(
|
|||||||
serialize_struct(
|
serialize_struct(
|
||||||
cx,
|
cx,
|
||||||
&builder,
|
&builder,
|
||||||
item.ident,
|
|
||||||
impl_generics,
|
impl_generics,
|
||||||
ty,
|
ty,
|
||||||
fields,
|
fields,
|
||||||
|
container_attrs,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,10 +171,9 @@ fn serialize_item_struct(
|
|||||||
|
|
||||||
fn serialize_unit_struct(
|
fn serialize_unit_struct(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
type_ident: Ident
|
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = container_attrs.serialize_name_expr();
|
||||||
|
|
||||||
Ok(quote_expr!(cx,
|
Ok(quote_expr!(cx,
|
||||||
serializer.serialize_unit_struct($type_name)
|
serializer.serialize_unit_struct($type_name)
|
||||||
@@ -186,10 +182,9 @@ fn serialize_unit_struct(
|
|||||||
|
|
||||||
fn serialize_newtype_struct(
|
fn serialize_newtype_struct(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
container_attrs: &attr::ContainerAttrs,
|
||||||
type_ident: Ident
|
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = container_attrs.serialize_name_expr();
|
||||||
|
|
||||||
Ok(quote_expr!(cx,
|
Ok(quote_expr!(cx,
|
||||||
serializer.serialize_newtype_struct($type_name, &self.0)
|
serializer.serialize_newtype_struct($type_name, &self.0)
|
||||||
@@ -199,10 +194,10 @@ fn serialize_newtype_struct(
|
|||||||
fn serialize_tuple_struct(
|
fn serialize_tuple_struct(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
type_ident: Ident,
|
|
||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
fields: usize,
|
fields: usize,
|
||||||
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
|
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
|
||||||
cx,
|
cx,
|
||||||
@@ -216,7 +211,7 @@ fn serialize_tuple_struct(
|
|||||||
impl_generics,
|
impl_generics,
|
||||||
);
|
);
|
||||||
|
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = container_attrs.serialize_name_expr();
|
||||||
|
|
||||||
Ok(quote_expr!(cx, {
|
Ok(quote_expr!(cx, {
|
||||||
$visitor_struct
|
$visitor_struct
|
||||||
@@ -232,10 +227,10 @@ fn serialize_tuple_struct(
|
|||||||
fn serialize_struct(
|
fn serialize_struct(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
type_ident: Ident,
|
|
||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let value_exprs = fields.iter().map(|field| {
|
let value_exprs = fields.iter().map(|field| {
|
||||||
let name = field.node.ident().expect("struct has unnamed field");
|
let name = field.node.ident().expect("struct has unnamed field");
|
||||||
@@ -255,7 +250,7 @@ fn serialize_struct(
|
|||||||
value_exprs,
|
value_exprs,
|
||||||
));
|
));
|
||||||
|
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = container_attrs.serialize_name_expr();
|
||||||
|
|
||||||
Ok(quote_expr!(cx, {
|
Ok(quote_expr!(cx, {
|
||||||
$visitor_struct
|
$visitor_struct
|
||||||
@@ -275,6 +270,7 @@ fn serialize_item_enum(
|
|||||||
impl_generics: &ast::Generics,
|
impl_generics: &ast::Generics,
|
||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
enum_def: &ast::EnumDef,
|
enum_def: &ast::EnumDef,
|
||||||
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<P<ast::Expr>, Error> {
|
) -> Result<P<ast::Expr>, Error> {
|
||||||
let mut arms = vec![];
|
let mut arms = vec![];
|
||||||
|
|
||||||
@@ -287,6 +283,7 @@ fn serialize_item_enum(
|
|||||||
ty.clone(),
|
ty.clone(),
|
||||||
variant,
|
variant,
|
||||||
variant_index,
|
variant_index,
|
||||||
|
container_attrs,
|
||||||
));
|
));
|
||||||
|
|
||||||
arms.push(arm);
|
arms.push(arm);
|
||||||
@@ -307,10 +304,13 @@ fn serialize_variant(
|
|||||||
ty: P<ast::Ty>,
|
ty: P<ast::Ty>,
|
||||||
variant: &ast::Variant,
|
variant: &ast::Variant,
|
||||||
variant_index: usize,
|
variant_index: usize,
|
||||||
|
container_attrs: &attr::ContainerAttrs,
|
||||||
) -> Result<ast::Arm, Error> {
|
) -> Result<ast::Arm, Error> {
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = container_attrs.serialize_name_expr();
|
||||||
|
|
||||||
let variant_ident = variant.node.name;
|
let variant_ident = variant.node.name;
|
||||||
let variant_name = builder.expr().str(variant_ident);
|
let variant_attrs = try!(attr::VariantAttrs::from_variant(cx, variant));
|
||||||
|
let variant_name = variant_attrs.serialize_name_expr();
|
||||||
|
|
||||||
match variant.node.data {
|
match variant.node.data {
|
||||||
ast::VariantData::Unit(_) => {
|
ast::VariantData::Unit(_) => {
|
||||||
@@ -605,14 +605,14 @@ fn serialize_struct_visitor<I>(
|
|||||||
{
|
{
|
||||||
let value_exprs = value_exprs.collect::<Vec<_>>();
|
let value_exprs = value_exprs.collect::<Vec<_>>();
|
||||||
|
|
||||||
let field_attrs = try!(attr::get_struct_field_attrs(cx, builder, fields));
|
let field_attrs = try!(attr::get_struct_field_attrs(cx, fields));
|
||||||
|
|
||||||
let arms: Vec<ast::Arm> = field_attrs.iter()
|
let arms: Vec<ast::Arm> = field_attrs.iter()
|
||||||
.zip(value_exprs.iter())
|
.zip(value_exprs.iter())
|
||||||
.filter(|&(ref field, _)| !field.skip_serializing_field())
|
.filter(|&(ref field, _)| !field.skip_serializing_field())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, (ref field, value_expr))| {
|
.map(|(i, (ref field, value_expr))| {
|
||||||
let key_expr = field.serializer_key_expr(cx);
|
let key_expr = field.serialize_name_expr();
|
||||||
|
|
||||||
let stmt = if field.skip_serializing_field_if_empty() {
|
let stmt = if field.skip_serializing_field_if_empty() {
|
||||||
quote_stmt!(cx, if ($value_expr).is_empty() { continue; })
|
quote_stmt!(cx, if ($value_expr).is_empty() { continue; })
|
||||||
|
|||||||
@@ -23,24 +23,44 @@ struct DisallowUnknown {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
struct Rename {
|
#[serde(rename="Superhero")]
|
||||||
|
struct RenameStruct {
|
||||||
a1: i32,
|
a1: i32,
|
||||||
#[serde(rename="a3")]
|
#[serde(rename="a3")]
|
||||||
a2: i32,
|
a2: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
struct FormatRename {
|
#[serde(rename(serialize="SuperheroSer", deserialize="SuperheroDe"))]
|
||||||
|
struct RenameStructSerializeDeserialize {
|
||||||
a1: i32,
|
a1: i32,
|
||||||
#[serde(rename(xml= "a4", token="a5"))]
|
#[serde(rename(serialize="a4", deserialize="a5"))]
|
||||||
a2: i32,
|
a2: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename="Superhero")]
|
||||||
|
enum RenameEnum {
|
||||||
|
#[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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
enum SerEnum<A> {
|
#[serde(rename(serialize="SuperheroSer", deserialize="SuperheroDe"))]
|
||||||
Map {
|
enum RenameEnumSerializeDeserialize<A> {
|
||||||
|
#[serde(rename(serialize="dick_grayson", deserialize="jason_todd"))]
|
||||||
|
Robin {
|
||||||
a: i8,
|
a: i8,
|
||||||
#[serde(rename(xml= "c", token="d"))]
|
#[serde(rename(serialize="c", deserialize="d"))]
|
||||||
b: A,
|
b: A,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -153,11 +173,11 @@ fn test_ignore_unknown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rename() {
|
fn test_rename_struct() {
|
||||||
assert_tokens(
|
assert_tokens(
|
||||||
&Rename { a1: 1, a2: 2 },
|
&RenameStruct { a1: 1, a2: 2 },
|
||||||
vec![
|
vec![
|
||||||
Token::StructStart("Rename", Some(2)),
|
Token::StructStart("Superhero", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::MapSep,
|
||||||
Token::Str("a1"),
|
Token::Str("a1"),
|
||||||
@@ -173,11 +193,28 @@ fn test_rename() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_format_rename() {
|
fn test_rename_struct_serialize_deserialize() {
|
||||||
assert_tokens(
|
assert_ser_tokens(
|
||||||
&FormatRename { a1: 1, a2: 2 },
|
&RenameStructSerializeDeserialize { a1: 1, a2: 2 },
|
||||||
|
&[
|
||||||
|
Token::StructStart("SuperheroSer", Some(2)),
|
||||||
|
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("a1"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("a4"),
|
||||||
|
Token::I32(2),
|
||||||
|
|
||||||
|
Token::MapEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&RenameStructSerializeDeserialize { a1: 1, a2: 2 },
|
||||||
vec![
|
vec![
|
||||||
Token::StructStart("FormatRename", Some(2)),
|
Token::StructStart("SuperheroDe", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::MapSep,
|
||||||
Token::Str("a1"),
|
Token::Str("a1"),
|
||||||
@@ -193,14 +230,80 @@ fn test_format_rename() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_enum_format_rename() {
|
fn test_rename_enum() {
|
||||||
assert_tokens(
|
assert_tokens(
|
||||||
&SerEnum::Map {
|
&RenameEnum::Batman,
|
||||||
|
vec![
|
||||||
|
Token::EnumUnit("Superhero", "bruce_wayne"),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&RenameEnum::Superman(0),
|
||||||
|
vec![
|
||||||
|
Token::EnumNewtype("Superhero", "clark_kent"),
|
||||||
|
Token::I8(0),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&RenameEnum::WonderWoman(0, 1),
|
||||||
|
vec![
|
||||||
|
Token::EnumSeqStart("Superhero", "diana_prince", Some(2)),
|
||||||
|
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I8(0),
|
||||||
|
|
||||||
|
Token::SeqSep,
|
||||||
|
Token::I8(1),
|
||||||
|
|
||||||
|
Token::SeqEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&RenameEnum::Flash { a: 1 },
|
||||||
|
vec![
|
||||||
|
Token::EnumMapStart("Superhero", "barry_allan", Some(1)),
|
||||||
|
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::I32(1),
|
||||||
|
|
||||||
|
Token::MapEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_enum_serialize_deserialize() {
|
||||||
|
assert_ser_tokens(
|
||||||
|
&RenameEnumSerializeDeserialize::Robin {
|
||||||
|
a: 0,
|
||||||
|
b: String::new(),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::EnumMapStart("SuperheroSer", "dick_grayson", Some(2)),
|
||||||
|
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I8(0),
|
||||||
|
|
||||||
|
Token::MapSep,
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Str(""),
|
||||||
|
|
||||||
|
Token::MapEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&RenameEnumSerializeDeserialize::Robin {
|
||||||
a: 0,
|
a: 0,
|
||||||
b: String::new(),
|
b: String::new(),
|
||||||
},
|
},
|
||||||
vec![
|
vec![
|
||||||
Token::EnumMapStart("SerEnum", "Map", Some(2)),
|
Token::EnumMapStart("SuperheroDe", "jason_todd", Some(2)),
|
||||||
|
|
||||||
Token::MapSep,
|
Token::MapSep,
|
||||||
Token::Str("a"),
|
Token::Str("a"),
|
||||||
|
|||||||
@@ -301,10 +301,6 @@ impl<'a, I> ser::Serializer for Serializer<I>
|
|||||||
try!(key.serialize(self));
|
try!(key.serialize(self));
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format() -> &'static str {
|
|
||||||
"token"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -583,10 +579,6 @@ impl<I> de::Deserializer for Deserializer<I>
|
|||||||
None => Err(Error::EndOfStreamError),
|
None => Err(Error::EndOfStreamError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format() -> &'static str {
|
|
||||||
"token"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
Reference in New Issue
Block a user