Compare commits

...

27 Commits

Author SHA1 Message Date
David Tolnay 51ed9c2a40 Release 0.9.10 2017-02-28 12:45:39 -08:00
David Tolnay fe9ea3b4b4 Fix needless_pass_by_value lint 2017-02-27 19:43:42 -08:00
David Tolnay f944b453c4 Merge pull request #792 from elliottslaughter/fix_serialize_tuple_docs
Fix documentation of serialize_tuple and SerializeTuple
2017-02-27 14:05:15 -08:00
Elliott Slaughter a993630cf9 Fix documentation of serialize_tuple and SerializeTuple. 2017-02-27 14:00:21 -08:00
David Tolnay abc081ce9c Test rename_all attribute 2017-02-25 11:58:34 -08:00
David Tolnay 207940046b Merge pull request #788 from 46bit/issue-140
`rename_all` container attribute to have all children fit a naming convention
2017-02-25 11:38:33 -08:00
David Tolnay 47efbc6d75 Don't need to pass back the input here 2017-02-25 11:32:27 -08:00
David Tolnay 17279e8a4f Simplify case conversion implementation 2017-02-25 11:32:22 -08:00
David Tolnay 06c631db05 Bring in the tests 2017-02-25 11:02:51 -08:00
David Tolnay 7952bad41f Move case conversion to its own file 2017-02-25 11:02:25 -08:00
Michael Mokrysz 3308f81c3a Saving progress on naming convention conversion code to try new Inflector changes. #788 2017-02-25 13:24:49 +00:00
David Tolnay 75e6da02d3 Split up test suite so it compiles in parallel 2017-02-24 15:39:18 -08:00
David Tolnay 59ec931d8f Release 0.9.9 2017-02-24 13:57:52 -08:00
David Tolnay 4b3c5ea99e Fix clippy lint in content serializer 2017-02-24 13:56:44 -08:00
David Tolnay d4ea4a7eef Add test for enums containing enums
Fixes #775.
2017-02-24 13:50:47 -08:00
David Tolnay 5fbdadefb2 Deserializing enums in serde_test 2017-02-24 13:47:04 -08:00
David Tolnay 4da77e4200 Serialize to Content 2017-02-24 12:59:35 -08:00
David Tolnay d797504407 Deserialize enums from &Content 2017-02-24 09:32:14 -08:00
Michael Mokrysz 84915268ee Minor fixes for pull request. Cheers @dtolnay. 2017-02-24 01:55:31 +00:00
Michael Mokrysz 3b59d47e07 Heavily refactored rename_all and switched to SCREAMING_SNAKE_CASE. 2017-02-23 23:22:54 +00:00
Michael Mokrysz fc94c5399a Implementing rename_all container attribute using Inflector trait. #140 2017-02-23 18:58:41 +00:00
David Tolnay 8e5f472e27 Merge pull request #787 from 46bit/issue-775
Fix internally tagged enums by implementing ContentDeserializer::deserialize_enum
2017-02-22 18:23:18 -08:00
David Tolnay 5e7883945b Fix clippy lint in Content::unexpected 2017-02-22 18:16:51 -08:00
David Tolnay a4bd6b9a96 Fix content's SeqDeserializer on no_std 2017-02-22 18:14:56 -08:00
Michael Mokrysz 4c253748c2 Compiles and fixes internally tagged testcases. 2017-02-23 01:05:44 +00:00
Michael Mokrysz 8f6e1fb5b3 Resolved error typing. Needs to adapt to Content::Map with non-String keys.
`EnumDeserializer` is being adapted from:
  `serde_json::Value::Map<Vec<(String, Value)>>`
serde has a Map variant that allows non-String keys:
  `serde::de::Content::Map<Vec<(Content, Content)>>`

There's a lot of assumptions in `EnumDeserializer` about `String` keys and I'm not sure what the adaptation should be.
2017-02-22 23:59:47 +00:00
Michael Mokrysz 4e665a71bd Attempt to port serde_json::Value::deserialize_enum for ContentDeserializer is being derailed by what error types should be used. 2017-02-22 22:55:18 +00:00
22 changed files with 1770 additions and 69 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "0.9.8" version = "0.9.10"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
+486 -6
View File
@@ -29,7 +29,6 @@ use de::{self, Deserialize, DeserializeSeed, Deserializer, Visitor, SeqVisitor,
/// Not public API. Use serde-value instead. /// Not public API. Use serde-value instead.
#[derive(Debug)] #[derive(Debug)]
pub enum Content { pub enum Content {
// Don't mind the PhantomData, just need to use E somewhere.
Bool(bool), Bool(bool),
U8(u8), U8(u8),
@@ -58,6 +57,32 @@ pub enum Content {
Map(Vec<(Content, Content)>), Map(Vec<(Content, Content)>),
} }
impl Content {
fn unexpected(&self) -> Unexpected {
match *self {
Content::Bool(b) => Unexpected::Bool(b),
Content::U8(n) => Unexpected::Unsigned(n as u64),
Content::U16(n) => Unexpected::Unsigned(n as u64),
Content::U32(n) => Unexpected::Unsigned(n as u64),
Content::U64(n) => Unexpected::Unsigned(n),
Content::I8(n) => Unexpected::Signed(n as i64),
Content::I16(n) => Unexpected::Signed(n as i64),
Content::I32(n) => Unexpected::Signed(n as i64),
Content::I64(n) => Unexpected::Signed(n),
Content::F32(f) => Unexpected::Float(f as f64),
Content::F64(f) => Unexpected::Float(f),
Content::Char(c) => Unexpected::Char(c),
Content::String(ref s) => Unexpected::Str(s),
Content::Bytes(ref b) => Unexpected::Bytes(b),
Content::None | Content::Some(_) => Unexpected::Option,
Content::Unit => Unexpected::Unit,
Content::Newtype(_) => Unexpected::NewtypeStruct,
Content::Seq(_) => Unexpected::Seq,
Content::Map(_) => Unexpected::Map,
}
}
}
impl Deserialize for Content { impl Deserialize for Content {
fn deserialize<D: Deserializer>(deserializer: D) -> Result<Self, D::Error> { fn deserialize<D: Deserializer>(deserializer: D) -> Result<Self, D::Error> {
// Untagged and internally tagged enums are only supported in // Untagged and internally tagged enums are only supported in
@@ -607,10 +632,41 @@ impl<E> Deserializer for ContentDeserializer<E>
visitor.visit_newtype_struct(self) visitor.visit_newtype_struct(self)
} }
fn deserialize_enum<V>(self, _name: &str, _variants: &'static [&'static str], visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor,
{
let (variant, value) = match self.content {
Content::Map(value) => {
let mut iter = value.into_iter();
let (variant, value) = match iter.next() {
Some(v) => v,
None => {
return Err(de::Error::invalid_value(de::Unexpected::Map, &"map with a single key"));
}
};
// enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() {
return Err(de::Error::invalid_value(de::Unexpected::Map, &"map with a single key"));
}
(variant, Some(value))
}
Content::String(variant) => (Content::String(variant), None),
other => {
return Err(de::Error::invalid_type(other.unexpected(), &"string or map"));
}
};
visitor.visit_enum(EnumDeserializer {
variant: variant,
value: value,
err: PhantomData,
})
}
forward_to_deserialize! { forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
seq_fixed_size bytes byte_buf map unit_struct tuple_struct struct seq_fixed_size bytes byte_buf map unit_struct tuple_struct struct
struct_field tuple enum ignored_any struct_field tuple ignored_any
} }
} }
@@ -624,6 +680,203 @@ impl<E> ContentDeserializer<E> {
} }
} }
struct EnumDeserializer<E> where E: de::Error {
variant: Content,
value: Option<Content>,
err: PhantomData<E>,
}
impl<E> de::EnumVisitor for EnumDeserializer<E> where E: de::Error {
type Error = E;
type Variant = VariantDeserializer<Self::Error>;
fn visit_variant_seed<V>(self, seed: V) -> Result<(V::Value, VariantDeserializer<E>), Self::Error>
where V: de::DeserializeSeed,
{
let visitor = VariantDeserializer { value: self.value, err: PhantomData, };
seed.deserialize(ContentDeserializer::new(self.variant)).map(|v| (v, visitor))
}
}
struct VariantDeserializer<E> where E: de::Error {
value: Option<Content>,
err: PhantomData<E>,
}
impl<E> de::VariantVisitor for VariantDeserializer<E> where E: de::Error {
type Error = E;
fn visit_unit(self) -> Result<(), E> {
match self.value {
Some(value) => de::Deserialize::deserialize(ContentDeserializer::new(value)),
None => Ok(()),
}
}
fn visit_newtype_seed<T>(self, seed: T) -> Result<T::Value, E>
where T: de::DeserializeSeed
{
match self.value {
Some(value) => seed.deserialize(ContentDeserializer::new(value)),
None => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"newtype variant")),
}
}
fn visit_tuple<V>(
self,
_len: usize,
visitor: V
) -> Result<V::Value, Self::Error>
where V: de::Visitor
{
match self.value {
Some(Content::Seq(v)) => {
de::Deserializer::deserialize(SeqDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"tuple variant")),
None => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"tuple variant"))
}
}
fn visit_struct<V>(
self,
_fields: &'static [&'static str],
visitor: V
) -> Result<V::Value, Self::Error>
where V: de::Visitor
{
match self.value {
Some(Content::Map(v)) => {
de::Deserializer::deserialize(MapDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"struct variant")),
_ => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"struct variant"))
}
}
}
struct SeqDeserializer<E> where E: de::Error {
iter: <Vec<Content> as IntoIterator>::IntoIter,
err: PhantomData<E>,
}
impl<E> SeqDeserializer<E> where E: de::Error {
fn new(vec: Vec<Content>) -> Self {
SeqDeserializer {
iter: vec.into_iter(),
err: PhantomData,
}
}
}
impl<E> de::Deserializer for SeqDeserializer<E> where E: de::Error {
type Error = E;
#[inline]
fn deserialize<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where V: de::Visitor,
{
let len = self.iter.len();
if len == 0 {
visitor.visit_unit()
} else {
let ret = try!(visitor.visit_seq(&mut self));
let remaining = self.iter.len();
if remaining == 0 {
Ok(ret)
} else {
Err(de::Error::invalid_length(len, &"fewer elements in array"))
}
}
}
forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
tuple_struct struct struct_field tuple enum ignored_any
}
}
impl<E> de::SeqVisitor for SeqDeserializer<E> where E: de::Error {
type Error = E;
fn visit_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where T: de::DeserializeSeed,
{
match self.iter.next() {
Some(value) => seed.deserialize(ContentDeserializer::new(value)).map(Some),
None => Ok(None),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
struct MapDeserializer<E> where E: de::Error {
iter: <Vec<(Content, Content)> as IntoIterator>::IntoIter,
value: Option<Content>,
err: PhantomData<E>,
}
impl<E> MapDeserializer<E> where E: de::Error {
fn new(map: Vec<(Content, Content)>) -> Self {
MapDeserializer {
iter: map.into_iter(),
value: None,
err: PhantomData,
}
}
}
impl<E> de::MapVisitor for MapDeserializer<E> where E: de::Error {
type Error = E;
fn visit_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where T: de::DeserializeSeed,
{
match self.iter.next() {
Some((key, value)) => {
self.value = Some(value);
seed.deserialize(ContentDeserializer::new(key)).map(Some)
}
None => Ok(None),
}
}
fn visit_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where T: de::DeserializeSeed,
{
match self.value.take() {
Some(value) => seed.deserialize(ContentDeserializer::new(value)),
None => Err(de::Error::custom("value is missing")),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<E> de::Deserializer for MapDeserializer<E> where E: de::Error {
type Error = E;
#[inline]
fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: de::Visitor,
{
visitor.visit_map(self)
}
forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
tuple_struct struct struct_field tuple enum ignored_any
}
}
/// Not public API. /// Not public API.
pub struct ContentRefDeserializer<'a, E> { pub struct ContentRefDeserializer<'a, E> {
content: &'a Content, content: &'a Content,
@@ -637,7 +890,7 @@ impl<'a, E> Deserializer for ContentRefDeserializer<'a, E>
{ {
type Error = E; type Error = E;
fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize<V>(self, visitor: V) -> Result<V::Value, E>
where V: Visitor where V: Visitor
{ {
match *self.content { match *self.content {
@@ -678,7 +931,7 @@ impl<'a, E> Deserializer for ContentRefDeserializer<'a, E>
} }
} }
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, E>
where V: Visitor where V: Visitor
{ {
match *self.content { match *self.content {
@@ -689,16 +942,47 @@ impl<'a, E> Deserializer for ContentRefDeserializer<'a, E>
} }
} }
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, E>
where V: Visitor where V: Visitor
{ {
visitor.visit_newtype_struct(self) visitor.visit_newtype_struct(self)
} }
fn deserialize_enum<V>(self, _name: &str, _variants: &'static [&'static str], visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor,
{
let (variant, value) = match *self.content {
Content::Map(ref value) => {
let mut iter = value.into_iter();
let &(ref variant, ref value) = match iter.next() {
Some(v) => v,
None => {
return Err(de::Error::invalid_value(de::Unexpected::Map, &"map with a single key"));
}
};
// enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() {
return Err(de::Error::invalid_value(de::Unexpected::Map, &"map with a single key"));
}
(variant, Some(value))
}
ref s @ Content::String(_) => (s, None),
ref other => {
return Err(de::Error::invalid_type(other.unexpected(), &"string or map"));
}
};
visitor.visit_enum(EnumRefDeserializer {
variant: variant,
value: value,
err: PhantomData,
})
}
forward_to_deserialize! { forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
seq_fixed_size bytes byte_buf map unit_struct tuple_struct struct seq_fixed_size bytes byte_buf map unit_struct tuple_struct struct
struct_field tuple enum ignored_any struct_field tuple ignored_any
} }
} }
@@ -712,6 +996,202 @@ impl<'a, E> ContentRefDeserializer<'a, E> {
} }
} }
struct EnumRefDeserializer<'a, E> where E: de::Error {
variant: &'a Content,
value: Option<&'a Content>,
err: PhantomData<E>,
}
impl<'a, E> de::EnumVisitor for EnumRefDeserializer<'a, E> where E: de::Error {
type Error = E;
type Variant = VariantRefDeserializer<'a, Self::Error>;
fn visit_variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where V: de::DeserializeSeed,
{
let visitor = VariantRefDeserializer { value: self.value, err: PhantomData, };
seed.deserialize(ContentRefDeserializer::new(self.variant)).map(|v| (v, visitor))
}
}
struct VariantRefDeserializer<'a, E> where E: de::Error {
value: Option<&'a Content>,
err: PhantomData<E>,
}
impl<'a, E> de::VariantVisitor for VariantRefDeserializer<'a, E> where E: de::Error {
type Error = E;
fn visit_unit(self) -> Result<(), E> {
match self.value {
Some(value) => de::Deserialize::deserialize(ContentRefDeserializer::new(value)),
None => Ok(()),
}
}
fn visit_newtype_seed<T>(self, seed: T) -> Result<T::Value, E>
where T: de::DeserializeSeed
{
match self.value {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"newtype variant")),
}
}
fn visit_tuple<V>(
self,
_len: usize,
visitor: V
) -> Result<V::Value, Self::Error>
where V: de::Visitor
{
match self.value {
Some(&Content::Seq(ref v)) => {
de::Deserializer::deserialize(SeqRefDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"tuple variant")),
None => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"tuple variant"))
}
}
fn visit_struct<V>(
self,
_fields: &'static [&'static str],
visitor: V
) -> Result<V::Value, Self::Error>
where V: de::Visitor
{
match self.value {
Some(&Content::Map(ref v)) => {
de::Deserializer::deserialize(MapRefDeserializer::new(v), visitor)
}
Some(other) => Err(de::Error::invalid_type(other.unexpected(), &"struct variant")),
_ => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"struct variant"))
}
}
}
struct SeqRefDeserializer<'a, E> where E: de::Error {
iter: <&'a [Content] as IntoIterator>::IntoIter,
err: PhantomData<E>,
}
impl<'a, E> SeqRefDeserializer<'a, E> where E: de::Error {
fn new(vec: &'a [Content]) -> Self {
SeqRefDeserializer {
iter: vec.into_iter(),
err: PhantomData,
}
}
}
impl<'a, E> de::Deserializer for SeqRefDeserializer<'a, E> where E: de::Error {
type Error = E;
#[inline]
fn deserialize<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
where V: de::Visitor,
{
let len = self.iter.len();
if len == 0 {
visitor.visit_unit()
} else {
let ret = try!(visitor.visit_seq(&mut self));
let remaining = self.iter.len();
if remaining == 0 {
Ok(ret)
} else {
Err(de::Error::invalid_length(len, &"fewer elements in array"))
}
}
}
forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
tuple_struct struct struct_field tuple enum ignored_any
}
}
impl<'a, E> de::SeqVisitor for SeqRefDeserializer<'a, E> where E: de::Error {
type Error = E;
fn visit_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where T: de::DeserializeSeed,
{
match self.iter.next() {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)).map(Some),
None => Ok(None),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
struct MapRefDeserializer<'a, E> where E: de::Error {
iter: <&'a [(Content, Content)] as IntoIterator>::IntoIter,
value: Option<&'a Content>,
err: PhantomData<E>,
}
impl<'a, E> MapRefDeserializer<'a, E> where E: de::Error {
fn new(map: &'a [(Content, Content)]) -> Self {
MapRefDeserializer {
iter: map.into_iter(),
value: None,
err: PhantomData,
}
}
}
impl<'a, E> de::MapVisitor for MapRefDeserializer<'a, E> where E: de::Error {
type Error = E;
fn visit_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where T: de::DeserializeSeed,
{
match self.iter.next() {
Some(&(ref key, ref value)) => {
self.value = Some(value);
seed.deserialize(ContentRefDeserializer::new(key)).map(Some)
}
None => Ok(None),
}
}
fn visit_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where T: de::DeserializeSeed,
{
match self.value.take() {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => Err(de::Error::custom("value is missing")),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a, E> de::Deserializer for MapRefDeserializer<'a, E> where E: de::Error {
type Error = E;
#[inline]
fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: de::Visitor,
{
visitor.visit_map(self)
}
forward_to_deserialize! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
tuple_struct struct struct_field tuple enum ignored_any
}
}
impl<E> de::value::ValueDeserializer<E> for ContentDeserializer<E> impl<E> de::value::ValueDeserializer<E> for ContentDeserializer<E>
where E: de::Error where E: de::Error
{ {
+635
View File
@@ -0,0 +1,635 @@
use core::marker::PhantomData;
#[cfg(all(not(feature = "std"), feature = "collections"))]
use collections::{String, Vec};
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::boxed::Box;
#[cfg(feature = "collections")]
use collections::borrow::ToOwned;
use ser::{self, Serialize, Serializer};
pub struct SerializeTupleVariantAsMapValue<M> {
map: M,
name: &'static str,
fields: Vec<Content>,
}
impl<M> SerializeTupleVariantAsMapValue<M> {
pub fn new(map: M, name: &'static str, len: usize) -> Self {
SerializeTupleVariantAsMapValue {
map: map,
name: name,
fields: Vec::with_capacity(len),
}
}
}
impl<M> ser::SerializeTupleVariant for SerializeTupleVariantAsMapValue<M>
where M: ser::SerializeMap
{
type Ok = M::Ok;
type Error = M::Error;
fn serialize_field<T: ?Sized + Serialize>(&mut self,
value: &T)
-> Result<(), M::Error>
{
let value = try!(value.serialize(ContentSerializer::<M::Error>::new()));
self.fields.push(value);
Ok(())
}
fn end(mut self) -> Result<M::Ok, M::Error> {
try!(self.map.serialize_value(&Content::TupleStruct(self.name, self.fields)));
self.map.end()
}
}
pub struct SerializeStructVariantAsMapValue<M> {
map: M,
name: &'static str,
fields: Vec<(&'static str, Content)>,
}
impl<M> SerializeStructVariantAsMapValue<M> {
pub fn new(map: M, name: &'static str, len: usize) -> Self {
SerializeStructVariantAsMapValue {
map: map,
name: name,
fields: Vec::with_capacity(len),
}
}
}
impl<M> ser::SerializeStructVariant for SerializeStructVariantAsMapValue<M>
where M: ser::SerializeMap
{
type Ok = M::Ok;
type Error = M::Error;
fn serialize_field<T: ?Sized + Serialize>(&mut self,
key: &'static str,
value: &T)
-> Result<(), M::Error>
{
let value = try!(value.serialize(ContentSerializer::<M::Error>::new()));
self.fields.push((key, value));
Ok(())
}
fn end(mut self) -> Result<M::Ok, M::Error> {
try!(self.map.serialize_value(&Content::Struct(self.name, self.fields)));
self.map.end()
}
}
#[derive(Debug)]
enum Content {
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
F32(f32),
F64(f64),
Char(char),
String(String),
Bytes(Vec<u8>),
None,
Some(Box<Content>),
Unit,
UnitStruct(&'static str),
UnitVariant(&'static str, usize, &'static str),
NewtypeStruct(&'static str, Box<Content>),
NewtypeVariant(&'static str, usize, &'static str, Box<Content>),
Seq(Vec<Content>),
SeqFixedSize(Vec<Content>),
Tuple(Vec<Content>),
TupleStruct(&'static str, Vec<Content>),
TupleVariant(&'static str, usize, &'static str, Vec<Content>),
Map(Vec<(Content, Content)>),
Struct(&'static str, Vec<(&'static str, Content)>),
StructVariant(&'static str, usize, &'static str, Vec<(&'static str, Content)>),
}
impl Serialize for Content {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
match *self {
Content::Bool(b) => serializer.serialize_bool(b),
Content::U8(u) => serializer.serialize_u8(u),
Content::U16(u) => serializer.serialize_u16(u),
Content::U32(u) => serializer.serialize_u32(u),
Content::U64(u) => serializer.serialize_u64(u),
Content::I8(i) => serializer.serialize_i8(i),
Content::I16(i) => serializer.serialize_i16(i),
Content::I32(i) => serializer.serialize_i32(i),
Content::I64(i) => serializer.serialize_i64(i),
Content::F32(f) => serializer.serialize_f32(f),
Content::F64(f) => serializer.serialize_f64(f),
Content::Char(c) => serializer.serialize_char(c),
Content::String(ref s) => serializer.serialize_str(s),
Content::Bytes(ref b) => serializer.serialize_bytes(b),
Content::None => serializer.serialize_none(),
Content::Some(ref c) => serializer.serialize_some(&**c),
Content::Unit => serializer.serialize_unit(),
Content::UnitStruct(n) => serializer.serialize_unit_struct(n),
Content::UnitVariant(n, i, v) => serializer.serialize_unit_variant(n, i, v),
Content::NewtypeStruct(n, ref c) => serializer.serialize_newtype_struct(n, &**c),
Content::NewtypeVariant(n, i, v, ref c) => serializer.serialize_newtype_variant(n, i, v, &**c),
Content::Seq(ref elements) => elements.serialize(serializer),
Content::SeqFixedSize(ref elements) => {
use ser::SerializeSeq;
let mut seq = try!(serializer.serialize_seq_fixed_size(elements.len()));
for e in elements {
try!(seq.serialize_element(e));
}
seq.end()
}
Content::Tuple(ref elements) => {
use ser::SerializeTuple;
let mut tuple = try!(serializer.serialize_tuple(elements.len()));
for e in elements {
try!(tuple.serialize_element(e));
}
tuple.end()
}
Content::TupleStruct(n, ref fields) => {
use ser::SerializeTupleStruct;
let mut ts = try!(serializer.serialize_tuple_struct(n, fields.len()));
for f in fields {
try!(ts.serialize_field(f));
}
ts.end()
}
Content::TupleVariant(n, i, v, ref fields) => {
use ser::SerializeTupleVariant;
let mut tv = try!(serializer.serialize_tuple_variant(n, i, v, fields.len()));
for f in fields {
try!(tv.serialize_field(f));
}
tv.end()
}
Content::Map(ref entries) => {
use ser::SerializeMap;
let mut map = try!(serializer.serialize_map(Some(entries.len())));
for &(ref k, ref v) in entries {
try!(map.serialize_entry(k, v));
}
map.end()
}
Content::Struct(n, ref fields) => {
use ser::SerializeStruct;
let mut s = try!(serializer.serialize_struct(n, fields.len()));
for &(k, ref v) in fields {
try!(s.serialize_field(k, v));
}
s.end()
}
Content::StructVariant(n, i, v, ref fields) => {
use ser::SerializeStructVariant;
let mut sv = try!(serializer.serialize_struct_variant(n, i, v, fields.len()));
for &(k, ref v) in fields {
try!(sv.serialize_field(k, v));
}
sv.end()
}
}
}
}
struct ContentSerializer<E> {
error: PhantomData<E>,
}
impl<E> ContentSerializer<E> {
fn new() -> Self {
ContentSerializer {
error: PhantomData,
}
}
}
impl<E> Serializer for ContentSerializer<E>
where E: ser::Error
{
type Ok = Content;
type Error = E;
type SerializeSeq = SerializeSeq<E>;
type SerializeTuple = SerializeTuple<E>;
type SerializeTupleStruct = SerializeTupleStruct<E>;
type SerializeTupleVariant = SerializeTupleVariant<E>;
type SerializeMap = SerializeMap<E>;
type SerializeStruct = SerializeStruct<E>;
type SerializeStructVariant = SerializeStructVariant<E>;
fn serialize_bool(self, v: bool) -> Result<Content, E> {
Ok(Content::Bool(v))
}
fn serialize_i8(self, v: i8) -> Result<Content, E> {
Ok(Content::I8(v))
}
fn serialize_i16(self, v: i16) -> Result<Content, E> {
Ok(Content::I16(v))
}
fn serialize_i32(self, v: i32) -> Result<Content, E> {
Ok(Content::I32(v))
}
fn serialize_i64(self, v: i64) -> Result<Content, E> {
Ok(Content::I64(v))
}
fn serialize_u8(self, v: u8) -> Result<Content, E> {
Ok(Content::U8(v))
}
fn serialize_u16(self, v: u16) -> Result<Content, E> {
Ok(Content::U16(v))
}
fn serialize_u32(self, v: u32) -> Result<Content, E> {
Ok(Content::U32(v))
}
fn serialize_u64(self, v: u64) -> Result<Content, E> {
Ok(Content::U64(v))
}
fn serialize_f32(self, v: f32) -> Result<Content, E> {
Ok(Content::F32(v))
}
fn serialize_f64(self, v: f64) -> Result<Content, E> {
Ok(Content::F64(v))
}
fn serialize_char(self, v: char) -> Result<Content, E> {
Ok(Content::Char(v))
}
fn serialize_str(self, value: &str) -> Result<Content, E> {
Ok(Content::String(value.to_owned()))
}
fn serialize_bytes(self, value: &[u8]) -> Result<Content, E> {
Ok(Content::Bytes(value.to_owned()))
}
fn serialize_none(self) -> Result<Content, E> {
Ok(Content::None)
}
fn serialize_some<T: ?Sized + Serialize>(self,
value: &T)
-> Result<Content, E> {
Ok(Content::Some(Box::new(try!(value.serialize(self)))))
}
fn serialize_unit(self) -> Result<Content, E> {
Ok(Content::Unit)
}
fn serialize_unit_struct(self,
name: &'static str)
-> Result<Content, E> {
Ok(Content::UnitStruct(name))
}
fn serialize_unit_variant(self,
name: &'static str,
variant_index: usize,
variant: &'static str)
-> Result<Content, E> {
Ok(Content::UnitVariant(name, variant_index, variant))
}
fn serialize_newtype_struct<T: ?Sized + Serialize>(self,
name: &'static str,
value: &T)
-> Result<Content, E> {
Ok(Content::NewtypeStruct(name, Box::new(try!(value.serialize(self)))))
}
fn serialize_newtype_variant<T: ?Sized + Serialize>(self,
name: &'static str,
variant_index: usize,
variant: &'static str,
value: &T)
-> Result<Content, E> {
Ok(Content::NewtypeVariant(name, variant_index, variant, Box::new(try!(value.serialize(self)))))
}
fn serialize_seq(self,
len: Option<usize>)
-> Result<Self::SerializeSeq, E> {
Ok(SerializeSeq {
fixed_size: false,
elements: Vec::with_capacity(len.unwrap_or(0)),
error: PhantomData,
})
}
fn serialize_seq_fixed_size(self,
size: usize)
-> Result<Self::SerializeSeq, E> {
Ok(SerializeSeq {
fixed_size: true,
elements: Vec::with_capacity(size),
error: PhantomData,
})
}
fn serialize_tuple(self,
len: usize)
-> Result<Self::SerializeTuple, E> {
Ok(SerializeTuple {
elements: Vec::with_capacity(len),
error: PhantomData,
})
}
fn serialize_tuple_struct(self,
name: &'static str,
len: usize)
-> Result<Self::SerializeTupleStruct, E> {
Ok(SerializeTupleStruct {
name: name,
fields: Vec::with_capacity(len),
error: PhantomData,
})
}
fn serialize_tuple_variant(self,
name: &'static str,
variant_index: usize,
variant: &'static str,
len: usize)
-> Result<Self::SerializeTupleVariant, E> {
Ok(SerializeTupleVariant {
name: name,
variant_index: variant_index,
variant: variant,
fields: Vec::with_capacity(len),
error: PhantomData,
})
}
fn serialize_map(self,
len: Option<usize>)
-> Result<Self::SerializeMap, E> {
Ok(SerializeMap {
entries: Vec::with_capacity(len.unwrap_or(0)),
key: None,
error: PhantomData,
})
}
fn serialize_struct(self,
name: &'static str,
len: usize)
-> Result<Self::SerializeStruct, E> {
Ok(SerializeStruct {
name: name,
fields: Vec::with_capacity(len),
error: PhantomData,
})
}
fn serialize_struct_variant(self,
name: &'static str,
variant_index: usize,
variant: &'static str,
len: usize)
-> Result<Self::SerializeStructVariant, E> {
Ok(SerializeStructVariant {
name: name,
variant_index: variant_index,
variant: variant,
fields: Vec::with_capacity(len),
error: PhantomData,
})
}
}
struct SerializeSeq<E> {
fixed_size: bool,
elements: Vec<Content>,
error: PhantomData<E>,
}
impl<E> ser::SerializeSeq for SerializeSeq<E>
where E: ser::Error
{
type Ok = Content;
type Error = E;
fn serialize_element<T: ?Sized + Serialize>(&mut self,
value: &T)
-> Result<(), E> {
let value = try!(value.serialize(ContentSerializer::<E>::new()));
self.elements.push(value);
Ok(())
}
fn end(self) -> Result<Content, E> {
Ok(if self.fixed_size {
Content::SeqFixedSize(self.elements)
} else {
Content::Seq(self.elements)
})
}
}
struct SerializeTuple<E> {
elements: Vec<Content>,
error: PhantomData<E>,
}
impl<E> ser::SerializeTuple for SerializeTuple<E>
where E: ser::Error
{
type Ok = Content;
type Error = E;
fn serialize_element<T: ?Sized + Serialize>(&mut self,
value: &T)
-> Result<(), E> {
let value = try!(value.serialize(ContentSerializer::<E>::new()));
self.elements.push(value);
Ok(())
}
fn end(self) -> Result<Content, E> {
Ok(Content::Tuple(self.elements))
}
}
struct SerializeTupleStruct<E> {
name: &'static str,
fields: Vec<Content>,
error: PhantomData<E>,
}
impl<E> ser::SerializeTupleStruct for SerializeTupleStruct<E>
where E: ser::Error
{
type Ok = Content;
type Error = E;
fn serialize_field<T: ?Sized + Serialize>(&mut self,
value: &T)
-> Result<(), E> {
let value = try!(value.serialize(ContentSerializer::<E>::new()));
self.fields.push(value);
Ok(())
}
fn end(self) -> Result<Content, E> {
Ok(Content::TupleStruct(self.name, self.fields))
}
}
struct SerializeTupleVariant<E> {
name: &'static str,
variant_index: usize,
variant: &'static str,
fields: Vec<Content>,
error: PhantomData<E>,
}
impl<E> ser::SerializeTupleVariant for SerializeTupleVariant<E>
where E: ser::Error
{
type Ok = Content;
type Error = E;
fn serialize_field<T: ?Sized + Serialize>(&mut self,
value: &T)
-> Result<(), E> {
let value = try!(value.serialize(ContentSerializer::<E>::new()));
self.fields.push(value);
Ok(())
}
fn end(self) -> Result<Content, E> {
Ok(Content::TupleVariant(self.name, self.variant_index, self.variant, self.fields))
}
}
struct SerializeMap<E> {
entries: Vec<(Content, Content)>,
key: Option<Content>,
error: PhantomData<E>,
}
impl<E> ser::SerializeMap for SerializeMap<E>
where E: ser::Error
{
type Ok = Content;
type Error = E;
fn serialize_key<T: ?Sized + Serialize>(&mut self,
key: &T)
-> Result<(), E> {
let key = try!(key.serialize(ContentSerializer::<E>::new()));
self.key = Some(key);
Ok(())
}
fn serialize_value<T: ?Sized + Serialize>(&mut self,
value: &T)
-> Result<(), E> {
let key = self.key.take().expect("serialize_value called before serialize_key");
let value = try!(value.serialize(ContentSerializer::<E>::new()));
self.entries.push((key, value));
Ok(())
}
fn end(self) -> Result<Content, E> {
Ok(Content::Map(self.entries))
}
fn serialize_entry<K: ?Sized + Serialize, V: ?Sized + Serialize>(&mut self,
key: &K,
value: &V)
-> Result<(), E> {
let key = try!(key.serialize(ContentSerializer::<E>::new()));
let value = try!(value.serialize(ContentSerializer::<E>::new()));
self.entries.push((key, value));
Ok(())
}
}
struct SerializeStruct<E> {
name: &'static str,
fields: Vec<(&'static str, Content)>,
error: PhantomData<E>,
}
impl<E> ser::SerializeStruct for SerializeStruct<E>
where E: ser::Error
{
type Ok = Content;
type Error = E;
fn serialize_field<T: ?Sized + Serialize>(&mut self,
key: &'static str,
value: &T)
-> Result<(), E> {
let value = try!(value.serialize(ContentSerializer::<E>::new()));
self.fields.push((key, value));
Ok(())
}
fn end(self) -> Result<Content, E> {
Ok(Content::Struct(self.name, self.fields))
}
}
struct SerializeStructVariant<E> {
name: &'static str,
variant_index: usize,
variant: &'static str,
fields: Vec<(&'static str, Content)>,
error: PhantomData<E>,
}
impl<E> ser::SerializeStructVariant for SerializeStructVariant<E>
where E: ser::Error
{
type Ok = Content;
type Error = E;
fn serialize_field<T: ?Sized + Serialize>(&mut self,
key: &'static str,
value: &T)
-> Result<(), E> {
let value = try!(value.serialize(ContentSerializer::<E>::new()));
self.fields.push((key, value));
Ok(())
}
fn end(self) -> Result<Content, E> {
Ok(Content::StructVariant(self.name, self.variant_index, self.variant, self.fields))
}
}
+9 -7
View File
@@ -107,6 +107,8 @@ mod impossible;
// Helpers used by generated code. Not public API. // Helpers used by generated code. Not public API.
#[doc(hidden)] #[doc(hidden)]
pub mod private; pub mod private;
#[cfg(any(feature = "std", feature = "collections"))]
mod content;
pub use self::impossible::Impossible; pub use self::impossible::Impossible;
@@ -464,13 +466,13 @@ pub trait Serializer: Sized {
fn serialize_seq_fixed_size(self, size: usize) -> Result<Self::SerializeSeq, Self::Error>; fn serialize_seq_fixed_size(self, size: usize) -> Result<Self::SerializeSeq, Self::Error>;
/// Begin to serialize a tuple. This call must be followed by zero or more /// Begin to serialize a tuple. This call must be followed by zero or more
/// calls to `serialize_field`, then a call to `end`. /// calls to `serialize_element`, then a call to `end`.
/// ///
/// ```rust,ignore /// ```rust,ignore
/// let mut tup = serializer.serialize_tuple(3)?; /// let mut tup = serializer.serialize_tuple(3)?;
/// tup.serialize_field(&self.0)?; /// tup.serialize_element(&self.0)?;
/// tup.serialize_field(&self.1)?; /// tup.serialize_element(&self.1)?;
/// tup.serialize_field(&self.2)?; /// tup.serialize_element(&self.2)?;
/// tup.end() /// tup.end()
/// ``` /// ```
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error>; fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error>;
@@ -644,9 +646,9 @@ pub trait SerializeSeq {
/// ///
/// ```rust,ignore /// ```rust,ignore
/// let mut tup = serializer.serialize_tuple(3)?; /// let mut tup = serializer.serialize_tuple(3)?;
/// tup.serialize_field(&self.0)?; /// tup.serialize_element(&self.0)?;
/// tup.serialize_field(&self.1)?; /// tup.serialize_element(&self.1)?;
/// tup.serialize_field(&self.2)?; /// tup.serialize_element(&self.2)?;
/// tup.end() /// tup.end()
/// ``` /// ```
pub trait SerializeTuple { pub trait SerializeTuple {
+63 -12
View File
@@ -1,6 +1,9 @@
use core::fmt::{self, Display}; use core::fmt::{self, Display};
use ser::{self, Serialize, Serializer, SerializeMap, SerializeStruct}; use ser::{self, Serialize, Serializer, SerializeMap, SerializeStruct, Impossible};
#[cfg(any(feature = "std", feature = "collections"))]
use ser::content::{SerializeTupleVariantAsMapValue, SerializeStructVariantAsMapValue};
/// Not public API. /// Not public API.
pub fn serialize_tagged_newtype<S, T>(serializer: S, pub fn serialize_tagged_newtype<S, T>(serializer: S,
@@ -8,7 +11,7 @@ pub fn serialize_tagged_newtype<S, T>(serializer: S,
variant_ident: &'static str, variant_ident: &'static str,
tag: &'static str, tag: &'static str,
variant_name: &'static str, variant_name: &'static str,
value: T) value: &T)
-> Result<S::Ok, S::Error> -> Result<S::Ok, S::Error>
where S: Serializer, where S: Serializer,
T: Serialize T: Serialize
@@ -43,6 +46,7 @@ enum Unsupported {
Sequence, Sequence,
Tuple, Tuple,
TupleStruct, TupleStruct,
#[cfg(not(any(feature = "std", feature = "collections")))]
Enum, Enum,
} }
@@ -61,6 +65,7 @@ impl Display for Unsupported {
Unsupported::Sequence => formatter.write_str("a sequence"), Unsupported::Sequence => formatter.write_str("a sequence"),
Unsupported::Tuple => formatter.write_str("a tuple"), Unsupported::Tuple => formatter.write_str("a tuple"),
Unsupported::TupleStruct => formatter.write_str("a tuple struct"), Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
#[cfg(not(any(feature = "std", feature = "collections")))]
Unsupported::Enum => formatter.write_str("an enum"), Unsupported::Enum => formatter.write_str("an enum"),
} }
} }
@@ -98,13 +103,21 @@ impl<S> Serializer for TaggedSerializer<S>
type Ok = S::Ok; type Ok = S::Ok;
type Error = S::Error; type Error = S::Error;
type SerializeSeq = S::SerializeSeq; type SerializeSeq = Impossible<S::Ok, S::Error>;
type SerializeTuple = S::SerializeTuple; type SerializeTuple = Impossible<S::Ok, S::Error>;
type SerializeTupleStruct = S::SerializeTupleStruct; type SerializeTupleStruct = Impossible<S::Ok, S::Error>;
type SerializeTupleVariant = S::SerializeTupleVariant;
type SerializeMap = S::SerializeMap; type SerializeMap = S::SerializeMap;
type SerializeStruct = S::SerializeStruct; type SerializeStruct = S::SerializeStruct;
type SerializeStructVariant = S::SerializeStructVariant;
#[cfg(not(any(feature = "std", feature = "collections")))]
type SerializeTupleVariant = Impossible<S::Ok, S::Error>;
#[cfg(any(feature = "std", feature = "collections"))]
type SerializeTupleVariant = SerializeTupleVariantAsMapValue<S::SerializeMap>;
#[cfg(not(any(feature = "std", feature = "collections")))]
type SerializeStructVariant = Impossible<S::Ok, S::Error>;
#[cfg(any(feature = "std", feature = "collections"))]
type SerializeStructVariant = SerializeStructVariantAsMapValue<S::SerializeMap>;
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> { fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Boolean)) Err(self.bad_type(Unsupported::Boolean))
@@ -183,9 +196,12 @@ impl<S> Serializer for TaggedSerializer<S>
fn serialize_unit_variant(self, fn serialize_unit_variant(self,
_: &'static str, _: &'static str,
_: usize, _: usize,
_: &'static str) inner_variant: &'static str)
-> Result<Self::Ok, Self::Error> { -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Enum)) let mut map = try!(self.delegate.serialize_map(Some(2)));
try!(map.serialize_entry(self.tag, self.variant_name));
try!(map.serialize_entry(inner_variant, &()));
map.end()
} }
fn serialize_newtype_struct<T: ?Sized>(self, fn serialize_newtype_struct<T: ?Sized>(self,
@@ -200,12 +216,15 @@ impl<S> Serializer for TaggedSerializer<S>
fn serialize_newtype_variant<T: ?Sized>(self, fn serialize_newtype_variant<T: ?Sized>(self,
_: &'static str, _: &'static str,
_: usize, _: usize,
_: &'static str, inner_variant: &'static str,
_: &T) inner_value: &T)
-> Result<Self::Ok, Self::Error> -> Result<Self::Ok, Self::Error>
where T: Serialize where T: Serialize
{ {
Err(self.bad_type(Unsupported::Enum)) let mut map = try!(self.delegate.serialize_map(Some(2)));
try!(map.serialize_entry(self.tag, self.variant_name));
try!(map.serialize_entry(inner_variant, inner_value));
map.end()
} }
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
@@ -227,15 +246,31 @@ impl<S> Serializer for TaggedSerializer<S>
Err(self.bad_type(Unsupported::TupleStruct)) Err(self.bad_type(Unsupported::TupleStruct))
} }
#[cfg(not(any(feature = "std", feature = "collections")))]
fn serialize_tuple_variant(self, fn serialize_tuple_variant(self,
_: &'static str, _: &'static str,
_: usize, _: usize,
_: &'static str, _: &'static str,
_: usize) _: usize)
-> Result<Self::SerializeTupleVariant, Self::Error> { -> Result<Self::SerializeTupleVariant, Self::Error> {
// Lack of push-based serialization means we need to buffer the content
// of the tuple variant, so it requires std.
Err(self.bad_type(Unsupported::Enum)) Err(self.bad_type(Unsupported::Enum))
} }
#[cfg(any(feature = "std", feature = "collections"))]
fn serialize_tuple_variant(self,
_: &'static str,
_: usize,
inner_variant: &'static str,
len: usize)
-> Result<Self::SerializeTupleVariant, Self::Error> {
let mut map = try!(self.delegate.serialize_map(Some(2)));
try!(map.serialize_entry(self.tag, self.variant_name));
try!(map.serialize_key(inner_variant));
Ok(SerializeTupleVariantAsMapValue::new(map, inner_variant, len))
}
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
let mut map = try!(self.delegate.serialize_map(len.map(|len| len + 1))); let mut map = try!(self.delegate.serialize_map(len.map(|len| len + 1)));
try!(map.serialize_entry(self.tag, self.variant_name)); try!(map.serialize_entry(self.tag, self.variant_name));
@@ -251,12 +286,28 @@ impl<S> Serializer for TaggedSerializer<S>
Ok(state) Ok(state)
} }
#[cfg(not(any(feature = "std", feature = "collections")))]
fn serialize_struct_variant(self, fn serialize_struct_variant(self,
_: &'static str, _: &'static str,
_: usize, _: usize,
_: &'static str, _: &'static str,
_: usize) _: usize)
-> Result<Self::SerializeStructVariant, Self::Error> { -> Result<Self::SerializeStructVariant, Self::Error> {
// Lack of push-based serialization means we need to buffer the content
// of the struct variant, so it requires std.
Err(self.bad_type(Unsupported::Enum)) Err(self.bad_type(Unsupported::Enum))
} }
#[cfg(any(feature = "std", feature = "collections"))]
fn serialize_struct_variant(self,
_: &'static str,
_: usize,
inner_variant: &'static str,
len: usize)
-> Result<Self::SerializeStructVariant, Self::Error> {
let mut map = try!(self.delegate.serialize_map(Some(2)));
try!(map.serialize_entry(self.tag, self.variant_name));
try!(map.serialize_key(inner_variant));
Ok(SerializeStructVariantAsMapValue::new(map, inner_variant, len))
}
} }
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_codegen_internals" name = "serde_codegen_internals"
version = "0.14.0" version = "0.14.1"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "AST representation used by Serde codegen. Unstable." description = "AST representation used by Serde codegen. Unstable."
+17 -1
View File
@@ -38,7 +38,7 @@ impl<'a> Item<'a> {
pub fn from_ast(cx: &Ctxt, item: &'a syn::MacroInput) -> Item<'a> { pub fn from_ast(cx: &Ctxt, item: &'a syn::MacroInput) -> Item<'a> {
let attrs = attr::Item::from_ast(cx, item); let attrs = attr::Item::from_ast(cx, item);
let body = match item.body { let mut body = match item.body {
syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)), syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)),
syn::Body::Struct(ref variant_data) => { syn::Body::Struct(ref variant_data) => {
let (style, fields) = struct_from_ast(cx, variant_data); let (style, fields) = struct_from_ast(cx, variant_data);
@@ -46,6 +46,22 @@ impl<'a> Item<'a> {
} }
}; };
match body {
Body::Enum(ref mut variants) => {
for ref mut variant in variants {
variant.attrs.rename_by_rule(attrs.rename_all());
for ref mut field in &mut variant.fields {
field.attrs.rename_by_rule(variant.attrs.rename_all());
}
}
}
Body::Struct(_, ref mut fields) => {
for field in fields {
field.attrs.rename_by_rule(attrs.rename_all());
}
}
}
Item { Item {
ident: item.ident.clone(), ident: item.ident.clone(),
attrs: attrs, attrs: attrs,
+90 -6
View File
@@ -2,6 +2,7 @@ use Ctxt;
use syn; use syn;
use syn::MetaItem::{List, NameValue, Word}; use syn::MetaItem::{List, NameValue, Word};
use syn::NestedMetaItem::{Literal, MetaItem}; use syn::NestedMetaItem::{Literal, MetaItem};
use std::str::FromStr;
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints // This module handles parsing of `#[serde(...)]` attributes. The entrypoints
// are `attr::Item::from_ast`, `attr::Variant::from_ast`, and // are `attr::Item::from_ast`, `attr::Variant::from_ast`, and
@@ -11,6 +12,8 @@ use syn::NestedMetaItem::{Literal, MetaItem};
// user will see errors simultaneously for all bad attributes in the crate // user will see errors simultaneously for all bad attributes in the crate
// rather than just the first. // rather than just the first.
pub use case::RenameRule;
struct Attr<'c, T> { struct Attr<'c, T> {
cx: &'c Ctxt, cx: &'c Ctxt,
name: &'static str, name: &'static str,
@@ -91,6 +94,7 @@ pub struct Item {
name: Name, name: Name,
deny_unknown_fields: bool, deny_unknown_fields: bool,
default: Default, default: Default,
rename_all: RenameRule,
ser_bound: Option<Vec<syn::WherePredicate>>, ser_bound: Option<Vec<syn::WherePredicate>>,
de_bound: Option<Vec<syn::WherePredicate>>, de_bound: Option<Vec<syn::WherePredicate>>,
tag: EnumTag, tag: EnumTag,
@@ -135,6 +139,7 @@ impl Item {
let mut de_name = Attr::none(cx, "rename"); let mut de_name = Attr::none(cx, "rename");
let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields"); let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields");
let mut default = Attr::none(cx, "default"); let mut default = Attr::none(cx, "default");
let mut rename_all = Attr::none(cx, "rename_all");
let mut ser_bound = Attr::none(cx, "bound"); let mut ser_bound = Attr::none(cx, "bound");
let mut de_bound = Attr::none(cx, "bound"); let mut de_bound = Attr::none(cx, "bound");
let mut untagged = BoolAttr::none(cx, "untagged"); let mut untagged = BoolAttr::none(cx, "untagged");
@@ -160,6 +165,20 @@ impl Item {
} }
} }
// Parse `#[serde(rename_all="foo")]`
MetaItem(NameValue(ref name, ref lit)) if name == "rename_all" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
match RenameRule::from_str(&s) {
Ok(rename_rule) => rename_all.set(rename_rule),
Err(()) => {
cx.error(format!("unknown rename rule for #[serde(rename_all \
= {:?})]",
s))
}
}
}
}
// Parse `#[serde(deny_unknown_fields)]` // Parse `#[serde(deny_unknown_fields)]`
MetaItem(Word(ref name)) if name == "deny_unknown_fields" => { MetaItem(Word(ref name)) if name == "deny_unknown_fields" => {
deny_unknown_fields.set_true(); deny_unknown_fields.set_true();
@@ -244,7 +263,8 @@ impl Item {
content.set(s); content.set(s);
} }
syn::Body::Struct(_) => { syn::Body::Struct(_) => {
cx.error("#[serde(content = \"...\")] can only be used on enums") cx.error("#[serde(content = \"...\")] can only be used on \
enums")
} }
} }
} }
@@ -297,7 +317,10 @@ impl Item {
EnumTag::External EnumTag::External
} }
(false, Some(tag), Some(content)) => { (false, Some(tag), Some(content)) => {
EnumTag::Adjacent { tag: tag, content: content } EnumTag::Adjacent {
tag: tag,
content: content,
}
} }
(true, Some(_), Some(_)) => { (true, Some(_), Some(_)) => {
cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]"); cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]");
@@ -312,6 +335,7 @@ impl Item {
}, },
deny_unknown_fields: deny_unknown_fields.get(), deny_unknown_fields: deny_unknown_fields.get(),
default: default.get().unwrap_or(Default::None), default: default.get().unwrap_or(Default::None),
rename_all: rename_all.get().unwrap_or(RenameRule::None),
ser_bound: ser_bound.get(), ser_bound: ser_bound.get(),
de_bound: de_bound.get(), de_bound: de_bound.get(),
tag: tag, tag: tag,
@@ -322,6 +346,10 @@ impl Item {
&self.name &self.name
} }
pub fn rename_all(&self) -> &RenameRule {
&self.rename_all
}
pub fn deny_unknown_fields(&self) -> bool { pub fn deny_unknown_fields(&self) -> bool {
self.deny_unknown_fields self.deny_unknown_fields
} }
@@ -347,6 +375,9 @@ impl Item {
#[derive(Debug)] #[derive(Debug)]
pub struct Variant { pub struct Variant {
name: Name, name: Name,
ser_renamed: bool,
de_renamed: bool,
rename_all: RenameRule,
skip_deserializing: bool, skip_deserializing: bool,
skip_serializing: bool, skip_serializing: bool,
} }
@@ -357,6 +388,7 @@ impl Variant {
let mut de_name = Attr::none(cx, "rename"); let mut de_name = Attr::none(cx, "rename");
let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing"); let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing");
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing"); let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
let mut rename_all = Attr::none(cx, "rename_all");
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) { for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
for meta_item in meta_items { for meta_item in meta_items {
@@ -376,6 +408,21 @@ impl Variant {
de_name.set_opt(de); de_name.set_opt(de);
} }
} }
// Parse `#[serde(rename_all="foo")]`
MetaItem(NameValue(ref name, ref lit)) if name == "rename_all" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
match RenameRule::from_str(&s) {
Ok(rename_rule) => rename_all.set(rename_rule),
Err(()) => {
cx.error(format!("unknown rename rule for #[serde(rename_all \
= {:?})]",
s))
}
}
}
}
// Parse `#[serde(skip_deserializing)]` // Parse `#[serde(skip_deserializing)]`
MetaItem(Word(ref name)) if name == "skip_deserializing" => { MetaItem(Word(ref name)) if name == "skip_deserializing" => {
skip_deserializing.set_true(); skip_deserializing.set_true();
@@ -396,11 +443,18 @@ impl Variant {
} }
} }
let ser_name = ser_name.get();
let ser_renamed = ser_name.is_some();
let de_name = de_name.get();
let de_renamed = de_name.is_some();
Variant { Variant {
name: Name { name: Name {
serialize: ser_name.get().unwrap_or_else(|| variant.ident.to_string()), serialize: ser_name.unwrap_or_else(|| variant.ident.to_string()),
deserialize: de_name.get().unwrap_or_else(|| variant.ident.to_string()), deserialize: de_name.unwrap_or_else(|| variant.ident.to_string()),
}, },
ser_renamed: ser_renamed,
de_renamed: de_renamed,
rename_all: rename_all.get().unwrap_or(RenameRule::None),
skip_deserializing: skip_deserializing.get(), skip_deserializing: skip_deserializing.get(),
skip_serializing: skip_serializing.get(), skip_serializing: skip_serializing.get(),
} }
@@ -410,6 +464,19 @@ impl Variant {
&self.name &self.name
} }
pub fn rename_by_rule(&mut self, rule: &RenameRule) {
if !self.ser_renamed {
self.name.serialize = rule.apply_to_variant(&self.name.serialize);
}
if !self.de_renamed {
self.name.deserialize = rule.apply_to_variant(&self.name.deserialize);
}
}
pub fn rename_all(&self) -> &RenameRule {
&self.rename_all
}
pub fn skip_deserializing(&self) -> bool { pub fn skip_deserializing(&self) -> bool {
self.skip_deserializing self.skip_deserializing
} }
@@ -423,6 +490,8 @@ impl Variant {
#[derive(Debug)] #[derive(Debug)]
pub struct Field { pub struct Field {
name: Name, name: Name,
ser_renamed: bool,
de_renamed: bool,
skip_serializing: bool, skip_serializing: bool,
skip_deserializing: bool, skip_deserializing: bool,
skip_serializing_if: Option<syn::Path>, skip_serializing_if: Option<syn::Path>,
@@ -571,11 +640,17 @@ impl Field {
default.set_if_none(Default::Default); default.set_if_none(Default::Default);
} }
let ser_name = ser_name.get();
let ser_renamed = ser_name.is_some();
let de_name = de_name.get();
let de_renamed = de_name.is_some();
Field { Field {
name: Name { name: Name {
serialize: ser_name.get().unwrap_or_else(|| ident.clone()), serialize: ser_name.unwrap_or_else(|| ident.clone()),
deserialize: de_name.get().unwrap_or(ident), deserialize: de_name.unwrap_or(ident),
}, },
ser_renamed: ser_renamed,
de_renamed: de_renamed,
skip_serializing: skip_serializing.get(), skip_serializing: skip_serializing.get(),
skip_deserializing: skip_deserializing.get(), skip_deserializing: skip_deserializing.get(),
skip_serializing_if: skip_serializing_if.get(), skip_serializing_if: skip_serializing_if.get(),
@@ -591,6 +666,15 @@ impl Field {
&self.name &self.name
} }
pub fn rename_by_rule(&mut self, rule: &RenameRule) {
if !self.ser_renamed {
self.name.serialize = rule.apply_to_field(&self.name.serialize);
}
if !self.de_renamed {
self.name.deserialize = rule.apply_to_field(&self.name.deserialize);
}
}
pub fn skip_serializing(&self) -> bool { pub fn skip_serializing(&self) -> bool {
self.skip_serializing self.skip_serializing
} }
+115
View File
@@ -0,0 +1,115 @@
use std::ascii::AsciiExt;
use std::str::FromStr;
use self::RenameRule::*;
#[derive(Debug, PartialEq)]
pub enum RenameRule {
/// Don't apply a default rename rule.
None,
/// Rename direct children to "PascalCase" style, as typically used for enum variants.
PascalCase,
/// Rename direct children to "camelCase" style.
CamelCase,
/// Rename direct children to "snake_case" style, as commonly used for fields.
SnakeCase,
/// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly used for constants.
ScreamingSnakeCase,
/// Rename direct children to "kebab-case" style.
KebabCase,
}
impl RenameRule {
pub fn apply_to_variant(&self, variant: &str) -> String {
match *self {
None | PascalCase => variant.to_owned(),
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
SnakeCase => {
let mut snake = String::new();
for (i, ch) in variant.char_indices() {
if i > 0 && ch.is_uppercase() {
snake.push('_');
}
snake.push(ch.to_ascii_lowercase());
}
snake
}
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
}
}
pub fn apply_to_field(&self, field: &str) -> String {
match *self {
None | SnakeCase => field.to_owned(),
PascalCase => {
let mut pascal = String::new();
let mut capitalize = true;
for ch in field.chars() {
if ch == '_' {
capitalize = true;
} else if capitalize {
pascal.push(ch.to_ascii_uppercase());
capitalize = false;
} else {
pascal.push(ch);
}
}
pascal
}
CamelCase => {
let pascal = PascalCase.apply_to_field(field);
pascal[..1].to_ascii_lowercase() + &pascal[1..]
}
ScreamingSnakeCase => field.to_ascii_uppercase(),
KebabCase => field.replace('_', "-"),
}
}
}
impl FromStr for RenameRule {
type Err = ();
fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> {
match rename_all_str {
"PascalCase" => Ok(PascalCase),
"camelCase" => Ok(CamelCase),
"snake_case" => Ok(SnakeCase),
"SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
"kebab-case" => Ok(KebabCase),
_ => Err(()),
}
}
}
#[test]
fn rename_variants() {
for &(original, camel, snake, screaming, kebab) in
&[("Outcome", "outcome", "outcome", "OUTCOME", "outcome"),
("VeryTasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty"),
("A", "a", "a", "A", "a"),
("Z42", "z42", "z42", "Z42", "z42")] {
assert_eq!(None.apply_to_variant(original), original);
assert_eq!(PascalCase.apply_to_variant(original), original);
assert_eq!(CamelCase.apply_to_variant(original), camel);
assert_eq!(SnakeCase.apply_to_variant(original), snake);
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
assert_eq!(KebabCase.apply_to_variant(original), kebab);
}
}
#[test]
fn rename_fields() {
for &(original, pascal, camel, screaming, kebab) in
&[("outcome", "Outcome", "outcome", "OUTCOME", "outcome"),
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty"),
("a", "A", "a", "A", "a"),
("z42", "Z42", "z42", "Z42", "z42")] {
assert_eq!(None.apply_to_field(original), original);
assert_eq!(PascalCase.apply_to_field(original), pascal);
assert_eq!(CamelCase.apply_to_field(original), camel);
assert_eq!(SnakeCase.apply_to_field(original), original);
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
assert_eq!(KebabCase.apply_to_field(original), kebab);
}
}
+2
View File
@@ -5,3 +5,5 @@ pub mod attr;
mod ctxt; mod ctxt;
pub use ctxt::Ctxt; pub use ctxt::Ctxt;
mod case;
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "0.9.8" version = "0.9.10"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
@@ -23,5 +23,5 @@ proc-macro = true
[dependencies] [dependencies]
quote = "0.3.8" quote = "0.3.8"
serde_codegen_internals = { version = "=0.14.0", default-features = false, path = "../serde_codegen_internals" } serde_codegen_internals = { version = "=0.14.1", default-features = false, path = "../serde_codegen_internals" }
syn = { version = "0.11", features = ["visit"] } syn = { version = "0.11", features = ["visit"] }
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_test" name = "serde_test"
version = "0.9.8" version = "0.9.10"
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations" description = "Token De/Serializer for testing De/Serialize implementations"
+77 -1
View File
@@ -2,7 +2,7 @@ use std::iter;
use serde::de::{self, Deserialize, DeserializeSeed, EnumVisitor, MapVisitor, SeqVisitor, use serde::de::{self, Deserialize, DeserializeSeed, EnumVisitor, MapVisitor, SeqVisitor,
VariantVisitor, Visitor}; VariantVisitor, Visitor};
use serde::de::value::ValueDeserializer; use serde::de::value::{ValueDeserializer, MapVisitorDeserializer, SeqVisitorDeserializer};
use error::Error; use error::Error;
use token::Token; use token::Token;
@@ -129,6 +129,13 @@ impl<'a, I> de::Deserializer for &'a mut Deserializer<I>
Some(Token::StructStart(_, len)) => { Some(Token::StructStart(_, len)) => {
self.visit_map(Some(len), Token::StructSep, Token::StructEnd, visitor) self.visit_map(Some(len), Token::StructSep, Token::StructEnd, visitor)
} }
Some(Token::EnumUnit(_, variant)) => visitor.visit_str(variant),
Some(Token::EnumStart(variant)) |
Some(Token::EnumNewType(_, variant)) |
Some(Token::EnumSeqStart(_, variant, _)) |
Some(Token::EnumMapStart(_, variant, _)) => {
visitor.visit_map(EnumMapVisitor::new(self, variant))
}
Some(token) => Err(Error::UnexpectedToken(token)), Some(token) => Err(Error::UnexpectedToken(token)),
None => Err(Error::EndOfTokens), None => Err(Error::EndOfTokens),
} }
@@ -541,3 +548,72 @@ impl<'a, I> VariantVisitor for DeserializerEnumVisitor<'a, I>
} }
} }
} }
//////////////////////////////////////////////////////////////////////////
struct EnumMapVisitor<'a, I: 'a>
where I: Iterator<Item = Token<'static>>
{
de: &'a mut Deserializer<I>,
variant: Option<&'a str>,
}
impl<'a, I: 'a> EnumMapVisitor<'a, I>
where I: Iterator<Item = Token<'static>>
{
fn new(de: &'a mut Deserializer<I>, variant: &'a str) -> Self {
EnumMapVisitor {
de: de,
variant: Some(variant),
}
}
}
impl<'a, I: 'a> MapVisitor for EnumMapVisitor<'a, I>
where I: Iterator<Item = Token<'static>>
{
type Error = Error;
fn visit_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
where K: DeserializeSeed
{
match self.variant.take() {
Some(variant) => seed.deserialize(variant.into_deserializer()).map(Some),
None => Ok(None),
}
}
fn visit_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
where V: DeserializeSeed
{
match self.de.tokens.peek() {
Some(&Token::EnumSeqSep) => {
let value = {
let visitor = DeserializerSeqVisitor {
de: self.de,
len: None,
sep: Token::EnumSeqSep,
end: Token::EnumSeqEnd,
};
try!(seed.deserialize(SeqVisitorDeserializer::new(visitor)))
};
try!(self.de.expect_token(Token::EnumSeqEnd));
Ok(value)
}
Some(&Token::EnumMapSep) => {
let value = {
let visitor = DeserializerMapVisitor {
de: self.de,
len: None,
sep: Token::EnumMapSep,
end: Token::EnumMapEnd,
};
try!(seed.deserialize(MapVisitorDeserializer::new(visitor)))
};
try!(self.de.expect_token(Token::EnumMapEnd));
Ok(value)
}
_ => seed.deserialize(&mut *self.de),
}
}
}
+1 -8
View File
@@ -5,10 +5,7 @@ authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
publish = false publish = false
[features] [features]
unstable-testing = [ unstable-testing = ["compiletest_rs"]
"compiletest_rs",
"serde/unstable-testing",
]
[dev-dependencies] [dev-dependencies]
fnv = "1.0" fnv = "1.0"
@@ -19,7 +16,3 @@ serde_test = { path = "../serde_test" }
[dependencies] [dependencies]
compiletest_rs = { version = "0.2", optional = true } compiletest_rs = { version = "0.2", optional = true }
[[test]]
name = "test"
path = "tests/test.rs"
+2
View File
@@ -1,3 +1,5 @@
#![cfg(feature = "unstable-testing")]
extern crate compiletest_rs as compiletest; extern crate compiletest_rs as compiletest;
use std::env; use std::env;
-23
View File
@@ -1,23 +0,0 @@
#![cfg_attr(feature = "unstable-testing", feature(test, non_ascii_idents))]
#[cfg(feature = "unstable-testing")]
extern crate test;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_test;
#[macro_use]
mod macros;
mod test_annotations;
mod test_bytes;
mod test_de;
mod test_gen;
mod test_macros;
mod test_ser;
#[cfg(feature = "unstable-testing")]
mod compiletest;
+3
View File
@@ -1,3 +1,6 @@
#[macro_use]
extern crate serde_derive;
extern crate serde; extern crate serde;
use self::serde::{Serialize, Serializer, Deserialize, Deserializer}; use self::serde::{Serialize, Serializer, Deserialize, Deserializer};
+3
View File
@@ -1,4 +1,7 @@
extern crate serde;
use serde::bytes::{ByteBuf, Bytes}; use serde::bytes::{ByteBuf, Bytes};
extern crate serde_test;
use serde_test::{assert_tokens, assert_ser_tokens, assert_de_tokens, Token}; use serde_test::{assert_tokens, assert_ser_tokens, assert_de_tokens, Token};
#[test] #[test]
+7
View File
@@ -1,9 +1,13 @@
#[macro_use]
extern crate serde_derive;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::net; use std::net;
use std::path::PathBuf; use std::path::PathBuf;
use std::time::Duration; use std::time::Duration;
use std::default::Default; use std::default::Default;
extern crate serde;
use serde::Deserialize; use serde::Deserialize;
extern crate fnv; extern crate fnv;
@@ -17,6 +21,9 @@ use self::serde_test::{
assert_de_tokens_error, assert_de_tokens_error,
}; };
#[macro_use]
mod macros;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#[derive(Copy, Clone, PartialEq, Debug, Deserialize)] #[derive(Copy, Clone, PartialEq, Debug, Deserialize)]
+5
View File
@@ -2,6 +2,11 @@
// successfully when there are a variety of generics and non-(de)serializable // successfully when there are a variety of generics and non-(de)serializable
// types involved. // types involved.
#![cfg_attr(feature = "unstable-testing", feature(non_ascii_idents))]
#[macro_use]
extern crate serde_derive;
extern crate serde; extern crate serde;
use self::serde::ser::{Serialize, Serializer}; use self::serde::ser::{Serialize, Serializer};
use self::serde::de::{Deserialize, Deserializer}; use self::serde::de::{Deserialize, Deserializer};
+242
View File
@@ -1,3 +1,6 @@
#[macro_use]
extern crate serde_derive;
extern crate serde_test; extern crate serde_test;
use self::serde_test::{ use self::serde_test::{
Error, Error,
@@ -1069,3 +1072,242 @@ fn test_adjacently_tagged_enum() {
] ]
); );
} }
#[test]
fn test_enum_in_internally_tagged_enum() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type")]
enum Outer {
Inner(Inner),
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
enum Inner {
Unit,
Newtype(u8),
Tuple(u8, u8),
Struct { f: u8 },
}
assert_tokens(
&Outer::Inner(Inner::Unit),
&[
Token::MapStart(Some(2)),
Token::MapSep,
Token::Str("type"),
Token::Str("Inner"),
Token::MapSep,
Token::Str("Unit"),
Token::Unit,
Token::MapEnd,
]
);
assert_tokens(
&Outer::Inner(Inner::Newtype(1)),
&[
Token::MapStart(Some(2)),
Token::MapSep,
Token::Str("type"),
Token::Str("Inner"),
Token::MapSep,
Token::Str("Newtype"),
Token::U8(1),
Token::MapEnd,
]
);
assert_tokens(
&Outer::Inner(Inner::Tuple(1, 1)),
&[
Token::MapStart(Some(2)),
Token::MapSep,
Token::Str("type"),
Token::Str("Inner"),
Token::MapSep,
Token::Str("Tuple"),
Token::TupleStructStart("Tuple", 2),
Token::TupleStructSep,
Token::U8(1),
Token::TupleStructSep,
Token::U8(1),
Token::TupleStructEnd,
Token::MapEnd,
]
);
assert_tokens(
&Outer::Inner(Inner::Struct { f: 1 }),
&[
Token::MapStart(Some(2)),
Token::MapSep,
Token::Str("type"),
Token::Str("Inner"),
Token::MapSep,
Token::Str("Struct"),
Token::StructStart("Struct", 1),
Token::StructSep,
Token::Str("f"),
Token::U8(1),
Token::StructEnd,
Token::MapEnd,
]
);
}
#[test]
fn test_enum_in_untagged_enum() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
enum Outer {
Inner(Inner),
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
enum Inner {
Unit,
Newtype(u8),
Tuple(u8, u8),
Struct { f: u8 },
}
assert_tokens(
&Outer::Inner(Inner::Unit),
&[
Token::EnumUnit("Inner", "Unit"),
]
);
assert_tokens(
&Outer::Inner(Inner::Newtype(1)),
&[
Token::EnumNewType("Inner", "Newtype"),
Token::U8(1),
]
);
assert_tokens(
&Outer::Inner(Inner::Tuple(1, 1)),
&[
Token::EnumSeqStart("Inner", "Tuple", 2),
Token::EnumSeqSep,
Token::U8(1),
Token::EnumSeqSep,
Token::U8(1),
Token::EnumSeqEnd,
]
);
assert_tokens(
&Outer::Inner(Inner::Struct { f: 1 }),
&[
Token::EnumMapStart("Inner", "Struct", 1),
Token::EnumMapSep,
Token::Str("f"),
Token::U8(1),
Token::EnumMapEnd,
]
);
}
#[test]
fn test_rename_all() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "snake_case")]
enum E {
#[serde(rename_all = "camelCase")]
Serialize {
serialize: bool,
serialize_seq: bool,
},
#[serde(rename_all = "kebab-case")]
SerializeSeq {
serialize: bool,
serialize_seq: bool,
},
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
SerializeMap {
serialize: bool,
serialize_seq: bool,
},
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "PascalCase")]
struct S {
serialize: bool,
serialize_seq: bool,
}
assert_tokens(
&E::Serialize { serialize: true, serialize_seq: true },
&[
Token::EnumMapStart("E", "serialize", 2),
Token::EnumMapSep,
Token::Str("serialize"),
Token::Bool(true),
Token::EnumMapSep,
Token::Str("serializeSeq"),
Token::Bool(true),
Token::EnumMapEnd,
]
);
assert_tokens(
&E::SerializeSeq { serialize: true, serialize_seq: true },
&[
Token::EnumMapStart("E", "serialize_seq", 2),
Token::EnumMapSep,
Token::Str("serialize"),
Token::Bool(true),
Token::EnumMapSep,
Token::Str("serialize-seq"),
Token::Bool(true),
Token::EnumMapEnd,
]
);
assert_tokens(
&E::SerializeMap { serialize: true, serialize_seq: true },
&[
Token::EnumMapStart("E", "serialize_map", 2),
Token::EnumMapSep,
Token::Str("SERIALIZE"),
Token::Bool(true),
Token::EnumMapSep,
Token::Str("SERIALIZE_SEQ"),
Token::Bool(true),
Token::EnumMapEnd,
]
);
assert_tokens(
&S { serialize: true, serialize_seq: true },
&[
Token::StructStart("S", 2),
Token::StructSep,
Token::Str("Serialize"),
Token::Bool(true),
Token::StructSep,
Token::Str("SerializeSeq"),
Token::Bool(true),
Token::StructEnd,
]
);
}
+8
View File
@@ -1,9 +1,14 @@
#[macro_use]
extern crate serde_derive;
use std::collections::{BTreeMap, HashMap, HashSet}; use std::collections::{BTreeMap, HashMap, HashSet};
use std::net; use std::net;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str; use std::str;
use std::time::Duration; use std::time::Duration;
extern crate serde;
extern crate serde_test; extern crate serde_test;
use self::serde_test::{ use self::serde_test::{
Error, Error,
@@ -18,6 +23,9 @@ use self::fnv::FnvHasher;
#[cfg(feature = "unstable")] #[cfg(feature = "unstable")]
use serde::ser::iterator; use serde::ser::iterator;
#[macro_use]
mod macros;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#[derive(Serialize)] #[derive(Serialize)]