Round trip testing
diff --git a/Cargo.toml b/Cargo.toml
index 72e29ff..c24d48d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,3 +20,8 @@
clippy = { version = "0.*", optional = true }
quote = { version = "0.2", optional = true }
unicode-xid = { version = "0.0.3", optional = true }
+
+[dev-dependencies]
+syntex_pos = "0.44.0"
+syntex_syntax = "0.44.0"
+walkdir = "0.1.8"
diff --git a/src/attr.rs b/src/attr.rs
index 8a16982..068e0ee 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -1,12 +1,24 @@
use super::*;
+use std::iter;
+
/// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Attribute {
+ pub style: AttrStyle,
pub value: MetaItem,
pub is_sugared_doc: bool,
}
+/// Distinguishes between Attributes that decorate items and Attributes that
+/// are contained as statements within items. These two cases need to be
+/// distinguished for pretty-printing.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum AttrStyle {
+ Outer,
+ Inner,
+}
+
/// A compile-time attribute item.
///
/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
@@ -36,6 +48,31 @@
}
}
+pub trait FilterAttrs<'a> {
+ type Ret: Iterator<Item = &'a Attribute>;
+
+ fn outer(self) -> Self::Ret;
+ fn inner(self) -> Self::Ret;
+}
+
+impl<'a, T> FilterAttrs<'a> for T where T: IntoIterator<Item = &'a Attribute> {
+ type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;
+
+ fn outer(self) -> Self::Ret {
+ fn is_outer(attr: &&Attribute) -> bool {
+ attr.style == AttrStyle::Outer
+ }
+ self.into_iter().filter(is_outer)
+ }
+
+ fn inner(self) -> Self::Ret {
+ fn is_inner(attr: &&Attribute) -> bool {
+ attr.style == AttrStyle::Inner
+ }
+ self.into_iter().filter(is_inner)
+ }
+}
+
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
@@ -43,13 +80,27 @@
use lit::{Lit, StrStyle};
use lit::parsing::lit;
- named!(pub attribute -> Attribute, alt!(
+ named!(pub inner_attr -> Attribute, do_parse!(
+ punct!("#") >>
+ punct!("!") >>
+ punct!("[") >>
+ meta_item: meta_item >>
+ punct!("]") >>
+ (Attribute {
+ style: AttrStyle::Inner,
+ value: meta_item,
+ is_sugared_doc: false,
+ })
+ ));
+
+ named!(pub outer_attr -> Attribute, alt!(
do_parse!(
punct!("#") >>
punct!("[") >>
meta_item: meta_item >>
punct!("]") >>
(Attribute {
+ style: AttrStyle::Outer,
value: meta_item,
is_sugared_doc: false,
})
@@ -60,6 +111,7 @@
not!(peek!(tag!("/"))) >>
content: take_until!("\n") >>
(Attribute {
+ style: AttrStyle::Outer,
value: MetaItem::NameValue(
"doc".into(),
Lit::Str(
@@ -102,6 +154,7 @@
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
Attribute {
+ style: AttrStyle::Outer,
value: MetaItem::NameValue(
ref name,
Lit::Str(ref value, StrStyle::Cooked),
@@ -112,6 +165,9 @@
}
_ => {
tokens.append("#");
+ if let AttrStyle::Inner = self.style {
+ tokens.append("!");
+ }
tokens.append("[");
self.value.to_tokens(tokens);
tokens.append("]");
diff --git a/src/data.rs b/src/data.rs
index 30edc8b..7082363 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -49,7 +49,7 @@
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
- use attr::parsing::attribute;
+ use attr::parsing::outer_attr;
use ident::parsing::ident;
use lit::parsing::int;
use ty::parsing::ty;
@@ -71,7 +71,7 @@
));
named!(variant -> Variant, do_parse!(
- attrs: many0!(attribute) >>
+ attrs: many0!(outer_attr) >>
id: ident >>
data: alt!(
struct_like_body => { VariantData::Struct }
@@ -106,7 +106,7 @@
));
named!(struct_field -> Field, do_parse!(
- attrs: many0!(attribute) >>
+ attrs: many0!(outer_attr) >>
vis: visibility >>
id: ident >>
punct!(":") >>
@@ -120,7 +120,7 @@
));
named!(tuple_field -> Field, do_parse!(
- attrs: many0!(attribute) >>
+ attrs: many0!(outer_attr) >>
vis: visibility >>
ty: ty >>
(Field {
diff --git a/src/item.rs b/src/item.rs
index d8488c8..86c7df9 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -209,7 +209,7 @@
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
- use attr::parsing::attribute;
+ use attr::parsing::outer_attr;
use data::parsing::visibility;
use ident::parsing::ident;
use macro_input::{Body, MacroInput};
@@ -234,7 +234,7 @@
));
named!(item_extern_crate -> Item, do_parse!(
- attrs: many0!(attribute) >>
+ attrs: many0!(outer_attr) >>
vis: visibility >>
keyword!("extern") >>
keyword!("crate") >>
@@ -275,3 +275,73 @@
}
));
}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use attr::FilterAttrs;
+ use data::{VariantData, Visibility};
+ use quote::{Tokens, ToTokens};
+
+ impl ToTokens for Item {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ for attr in self.attrs.outer() {
+ attr.to_tokens(tokens);
+ }
+ match self.node {
+ ItemKind::ExternCrate(ref original) => {
+ tokens.append("extern");
+ tokens.append("crate");
+ if let Some(ref original) = *original {
+ original.to_tokens(tokens);
+ tokens.append("as");
+ }
+ self.ident.to_tokens(tokens);
+ tokens.append(";");
+ }
+ ItemKind::Use(ref _view_path) => unimplemented!(),
+ ItemKind::Static(ref _ty, ref _mutability, ref _expr) => unimplemented!(),
+ ItemKind::Const(ref _ty, ref _expr) => unimplemented!(),
+ ItemKind::Fn(ref _decl, _unsafety, _constness, ref _abi, ref _generics, ref _block) => unimplemented!(),
+ ItemKind::Mod(ref _items) => unimplemented!(),
+ ItemKind::ForeignMod(ref _foreign_mod) => unimplemented!(),
+ ItemKind::Ty(ref _ty, ref _generics) => unimplemented!(),
+ ItemKind::Enum(ref variants, ref generics) => {
+ if let Visibility::Public = self.vis {
+ tokens.append("pub");
+ }
+ tokens.append("enum");
+ self.ident.to_tokens(tokens);
+ generics.to_tokens(tokens);
+ generics.where_clause.to_tokens(tokens);
+ tokens.append("{");
+ for variant in variants {
+ variant.to_tokens(tokens);
+ tokens.append(",");
+ }
+ tokens.append("}");
+ }
+ ItemKind::Struct(ref variant_data, ref generics) => {
+ if let Visibility::Public = self.vis {
+ tokens.append("pub");
+ }
+ tokens.append("struct");
+ self.ident.to_tokens(tokens);
+ generics.to_tokens(tokens);
+ generics.where_clause.to_tokens(tokens);
+ variant_data.to_tokens(tokens);
+ match *variant_data {
+ VariantData::Struct(_) => { /* no semicolon */ }
+ VariantData::Tuple(_) |
+ VariantData::Unit => tokens.append(";"),
+ }
+ }
+ ItemKind::Union(ref _variant_data, ref _generics) => unimplemented!(),
+ ItemKind::Trait(_unsafety, ref _generics, ref _bound, ref _item) => unimplemented!(),
+ ItemKind::DefaultImpl(_unsafety, ref _path) => unimplemented!(),
+ ItemKind::Impl(_unsafety, _polarity, ref _generics, ref _path, ref _ty, ref _item) => unimplemented!(),
+ ItemKind::Mac(ref _mac) => unimplemented!(),
+ }
+ }
+ }
+}
diff --git a/src/krate.rs b/src/krate.rs
new file mode 100644
index 0000000..c5b2126
--- /dev/null
+++ b/src/krate.rs
@@ -0,0 +1,43 @@
+use super::*;
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct Crate {
+ attrs: Vec<Attribute>,
+ items: Vec<Item>,
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+ use attr::parsing::inner_attr;
+ use item::parsing::item;
+ use nom::multispace;
+
+ named!(pub krate -> Crate, do_parse!(
+ attrs: many0!(inner_attr) >>
+ items: many0!(item) >>
+ option!(multispace) >>
+ (Crate {
+ attrs: attrs,
+ items: items,
+ })
+ ));
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use attr::FilterAttrs;
+ use quote::{Tokens, ToTokens};
+
+ impl ToTokens for Crate {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ for attr in self.attrs.inner() {
+ attr.to_tokens(tokens);
+ }
+ for item in &self.items {
+ item.to_tokens(tokens);
+ }
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index df62d75..50a754c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -19,6 +19,7 @@
mod attr;
pub use attr::{
Attribute,
+ AttrStyle,
MetaItem,
};
@@ -65,6 +66,11 @@
WhereRegionPredicate,
};
+#[cfg(feature = "full")]
+mod krate;
+#[cfg(feature = "full")]
+pub use krate::Crate;
+
mod ident;
pub use ident::{
Ident,
@@ -155,13 +161,18 @@
use nom;
#[cfg(feature = "full")]
- use {expr, item};
+ use {expr, item, krate};
pub fn parse_macro_input(input: &str) -> Result<MacroInput, String> {
unwrap("macro input", macro_input::parsing::macro_input, input)
}
#[cfg(feature = "full")]
+ pub fn parse_crate(input: &str) -> Result<Crate, String> {
+ unwrap("crate", krate::parsing::krate, input)
+ }
+
+ #[cfg(feature = "full")]
pub fn parse_item(input: &str) -> Result<Item, String> {
unwrap("item", item::parsing::item, input)
}
diff --git a/src/macro_input.rs b/src/macro_input.rs
index 848e609..c2b5900 100644
--- a/src/macro_input.rs
+++ b/src/macro_input.rs
@@ -18,14 +18,14 @@
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
- use attr::parsing::attribute;
+ use attr::parsing::outer_attr;
use data::parsing::{visibility, struct_body, enum_body};
use generics::parsing::generics;
use ident::parsing::ident;
use nom::multispace;
named!(pub macro_input -> MacroInput, do_parse!(
- attrs: many0!(attribute) >>
+ attrs: many0!(outer_attr) >>
vis: visibility >>
which: alt!(keyword!("struct") | keyword!("enum")) >>
id: ident >>
@@ -55,12 +55,13 @@
#[cfg(feature = "printing")]
mod printing {
use super::*;
+ use attr::FilterAttrs;
use data::{Visibility, VariantData};
use quote::{Tokens, ToTokens};
impl ToTokens for MacroInput {
fn to_tokens(&self, tokens: &mut Tokens) {
- for attr in &self.attrs {
+ for attr in self.attrs.outer() {
attr.to_tokens(tokens);
}
if let Visibility::Public = self.vis {
diff --git a/tests/cases/structs_enums.rs b/tests/cases/structs_enums.rs
new file mode 100644
index 0000000..0236741
--- /dev/null
+++ b/tests/cases/structs_enums.rs
@@ -0,0 +1,529 @@
+#![feature(rustc_macro)]
+
+#[macro_use]
+extern crate serde_derive;
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct DefaultStruct<A, B, C, D, E> where C: MyDefault, E: MyDefault {
+ a1: A,
+ #[serde(default)]
+ a2: B,
+ #[serde(default = "MyDefault::my_default")]
+ a3: C,
+ #[serde(skip_deserializing)]
+ a4: D,
+ #[serde(skip_deserializing, default = "MyDefault::my_default")]
+ a5: E,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+enum DefaultEnum<A, B, C, D, E> where C: MyDefault, E: MyDefault {
+ Struct {
+ a1: A,
+ #[serde(default)]
+ a2: B,
+ #[serde(default = "MyDefault::my_default")]
+ a3: C,
+ #[serde(skip_deserializing)]
+ a4: D,
+ #[serde(skip_deserializing, default = "MyDefault::my_default")]
+ a5: E,
+ },
+}
+
+#[derive(Deserialize)]
+struct NoStdDefault(i8);
+
+#[derive(Deserialize)]
+struct ContainsNoStdDefault<A: MyDefault> {
+ #[serde(default = "MyDefault::my_default")]
+ a: A,
+}
+
+#[derive(Deserialize)]
+struct ContainsNotDeserialize<A, B, C: DeserializeWith, E: MyDefault> {
+ #[serde(skip_deserializing)]
+ a: A,
+ #[serde(skip_deserializing, default)]
+ b: B,
+ #[serde(deserialize_with = "DeserializeWith::deserialize_with", default)]
+ c: C,
+ #[serde(skip_deserializing, default = "MyDefault::my_default")]
+ e: E,
+}
+
+#[derive(Serialize)]
+#[serde(deny_unknown_fields)]
+#[derive(Deserialize)]
+struct DenyUnknown {
+ a1: i32,
+}
+
+#[derive(Serialize)]
+#[serde(rename = "Superhero")]
+#[derive(Deserialize)]
+struct RenameStruct {
+ a1: i32,
+ #[serde(rename = "a3")]
+ a2: i32,
+}
+
+#[derive(Serialize)]
+#[serde(rename(serialize = "SuperheroSer", deserialize = "SuperheroDe"))]
+#[derive(Deserialize)]
+struct RenameStructSerializeDeserialize {
+ a1: i32,
+ #[serde(rename(serialize = "a4", deserialize = "a5"))]
+ a2: i32,
+}
+
+#[derive(Serialize)]
+#[serde(rename = "Superhero")]
+#[derive(Deserialize)]
+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(Deserialize)]
+#[serde ( rename ( serialize = "SuperheroSer" , deserialize = "SuperheroDe" ) ) ]
+#[derive(Serialize)]
+enum RenameEnumSerializeDeserialize<A> {
+
+ #[serde(rename(serialize = "dick_grayson", deserialize = "jason_todd"))]
+ Robin {
+ a: i8,
+ #[serde(rename(serialize = "c"))]
+ #[serde(rename(deserialize = "d"))]
+ b: A,
+ },
+}
+
+#[derive(Serialize)]
+struct SkipSerializingStruct< 'a , B, C> where C : ShouldSkip {
+ a: & 'a i8,
+ #[serde(skip_serializing)]
+ b: B,
+ #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
+ c: C,
+}
+
+#[derive(Serialize)]
+enum SkipSerializingEnum<'a, B, C> where C: ShouldSkip {
+ Struct {
+ a: &'a i8,
+ #[serde(skip_serializing)]
+ _b: B,
+ #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
+ c: C,
+ },
+}
+
+#[derive(Serialize)]
+struct ContainsNotSerialize<'a, B, C, D> where B: 'a , D: SerializeWith {
+ a: &'a Option<i8>,
+ #[serde(skip_serializing)]
+ b: &'a B,
+ #[serde(skip_serializing)]
+ c: Option<C>,
+ #[serde(serialize_with = "SerializeWith::serialize_with")]
+ d: D,
+}
+
+#[derive(Serialize)]
+struct SerializeWithStruct<'a, B> where B: SerializeWith {
+ a: &'a i8,
+ #[serde(serialize_with = "SerializeWith::serialize_with")]
+ b: B,
+}
+
+#[derive(Serialize)]
+enum SerializeWithEnum<'a, B> where B: SerializeWith {
+ Struct {
+ a: &'a i8,
+ #[serde(serialize_with = "SerializeWith::serialize_with")]
+ b: B,
+ },
+}
+
+#[derive(Deserialize)]
+struct DeserializeWithStruct<B> where B: DeserializeWith {
+ a: i8,
+ #[serde(deserialize_with = "DeserializeWith::deserialize_with")]
+ b: B,
+}
+
+#[derive(Deserialize)]
+enum DeserializeWithEnum<B> where B: DeserializeWith {
+ Struct {
+ a: i8,
+ #[serde(deserialize_with = "DeserializeWith::deserialize_with")]
+ b: B,
+ },
+}
+
+#[derive(Deserialize)]
+enum InvalidLengthEnum {
+ A(i32, i32, i32),
+ B(
+ #[serde(skip_deserializing)]
+ i32, i32, i32),
+}
+
+#[derive(Deserialize)]
+struct TupleStruct(i32, i32, i32);
+
+#[derive(Deserialize)]
+struct Struct {
+ a: i32,
+ b: i32,
+ #[serde(skip_deserializing)]
+ c: i32,
+}
+
+#[derive(Deserialize)]
+enum Enum {
+ Unit,
+ Simple(i32),
+ Seq(i32, i32, i32),
+ Map {
+ a: i32,
+ b: i32,
+ c: i32,
+ },
+}
+
+#[derive(Deserialize)]
+struct IgnoreBase {
+ a: i32,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct With<T> {
+ t: T,
+ #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+ x: X,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct WithRef<'a, T: 'a> {
+ #[serde(skip_deserializing)]
+ t: Option<&'a T>,
+ #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+ x: X,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct PhantomX {
+ x: PhantomData<X>,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct PhantomT<T> {
+ t: PhantomData<T>,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct NoBounds<T> {
+ t: T,
+ option: Option<T>,
+ boxed: Box<T>,
+ option_boxed: Option<Box<T>>,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+enum EnumWith<T> {
+ Unit,
+ Newtype(
+ #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+ X),
+ Tuple(T,
+ #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+ X),
+ Struct {
+ t: T,
+ #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+ x: X,
+ },
+}
+
+#[derive(Serialize)]
+struct MultipleRef<'a, 'b, 'c, T> where T: 'c, 'c: 'b, 'b: 'a {
+ t: T,
+ rrrt: &'a &'b &'c T,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct Newtype(
+ #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+ X);
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct Tuple<T>(T,
+ #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
+ X);
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+enum TreeNode<D> {
+ Split {
+ left: Box<TreeNode<D>>,
+ right: Box<TreeNode<D>>,
+ },
+ Leaf {
+ data: D,
+ },
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct ListNode<D> {
+ data: D,
+ next: Box<ListNode<D>>,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct RecursiveA {
+ b: Box<RecursiveB>,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+enum RecursiveB { A(RecursiveA), }
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct RecursiveGenericA<T> {
+ t: T,
+ b: Box<RecursiveGenericB<T>>,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+enum RecursiveGenericB<T> { T(T), A(RecursiveGenericA<T>), }
+
+#[derive(Serialize)]
+struct OptionStatic<'a> {
+ a: Option<&'a str>,
+ b: Option<&'static str>,
+}
+
+#[derive(Serialize)]
+#[serde(bound = "D: SerializeWith + DeserializeWith")]
+#[derive(Deserialize)]
+struct WithTraits1<D, E> {
+ #[serde(serialize_with = "SerializeWith::serialize_with",
+ deserialize_with = "DeserializeWith::deserialize_with")]
+ d: D,
+ #[serde(serialize_with = "SerializeWith::serialize_with",
+ deserialize_with = "DeserializeWith::deserialize_with",
+ bound = "E: SerializeWith + DeserializeWith")]
+ e: E,
+}
+
+#[derive(Serialize)]
+#[serde(bound(serialize = "D: SerializeWith",
+ deserialize = "D: DeserializeWith"))]
+#[derive(Deserialize)]
+struct WithTraits2<D, E> {
+ #[serde(serialize_with = "SerializeWith::serialize_with",
+ deserialize_with = "DeserializeWith::deserialize_with")]
+ d: D,
+ #[serde(serialize_with = "SerializeWith::serialize_with",
+ bound(serialize = "E: SerializeWith"))]
+ #[serde(deserialize_with = "DeserializeWith::deserialize_with",
+ bound(deserialize = "E: DeserializeWith"))]
+ e: E,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct CowStr<'a>(Cow<'a, str>);
+
+#[derive(Serialize)]
+#[serde(bound(deserialize = "T::Owned: Deserialize"))]
+#[derive(Deserialize)]
+struct CowT < 'a , T : ? Sized + 'a + ToOwned > ( Cow < 'a , T > ) ;
+
+#[derive(Serialize)]
+struct SerNamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C);
+
+#[derive(Deserialize)]
+struct DeNamedTuple<A, B, C>(A, B, C);
+
+#[derive(Serialize)]
+struct SerNamedMap<'a, 'b, A: 'a, B: 'b, C> {
+ a: &'a A,
+ b: &'b mut B,
+ c: C,
+}
+
+#[derive(Deserialize)]
+struct DeNamedMap<A, B, C> {
+ a: A,
+ b: < Vec < T > as a :: b :: Trait > :: AssociatedItem,
+ c: < Vec < T > > :: AssociatedItem,
+}
+
+#[derive(Serialize)]
+enum SerEnum<'a, B: 'a, C: 'a, D> where for < 'a > D: 'a {
+ Unit,
+ Seq(i8, B, &'a C, &'a mut D),
+ Map {
+ a: i8,
+ b: B,
+ c: &'a C,
+ d: &'a mut D,
+ },
+ _Unit2,
+ _Seq2(i8, B, &'a C, &'a mut D),
+ _Map2 {
+ a: i8,
+ b: B,
+ c: &'a C,
+ d: &'a mut D,
+ },
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+enum DeEnum<B, C, D> {
+ Unit,
+ Seq(i8, B, C, D),
+ Map {
+ a: i8,
+ b: B,
+ c: C,
+ d: D,
+ },
+ _Unit2,
+ _Seq2(i8, B, C, D),
+ _Map2 {
+ a: i8,
+ b: B,
+ c: C,
+ d: D,
+ },
+}
+
+#[derive(Serialize)]
+enum Lifetimes<'a> {
+ LifetimeSeq(&'a i32),
+ NoLifetimeSeq(i32),
+ LifetimeMap {
+ a: &'a i32,
+ },
+ NoLifetimeMap {
+ a: i32,
+ },
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+pub struct GenericStruct<T> {
+ x: T,
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+pub struct GenericNewTypeStruct<T>(T);
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+pub struct GenericTupleStruct<T, U>(T, U);
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+pub enum GenericEnum<T, U: for < 'a > F<'a>> {
+ Unit,
+ NewType(T),
+ Seq(T, U),
+ Map {
+ x: T,
+ y: U,
+ },
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct DefaultTyParam<T: AssociatedType<X = i32> = i32> {
+ phantom: std :: marker :: PhantomData<T>,
+}
+
+#[derive(Serialize)]
+struct UnitStruct;
+
+#[derive(Serialize)]
+struct TupleStruct(i32, i32, i32);
+
+#[derive(Serialize)]
+struct Struct {
+ a: i32,
+ b: i32,
+ c: i32,
+}
+
+#[derive(Serialize)]
+enum Enum {
+ Unit,
+ One(i32),
+ Seq(i32, i32),
+ Map {
+ a: i32,
+ b: i32,
+ },
+}
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct Bounds<T: Serialize + Deserialize> {
+ t: T,
+ option: Option<T>,
+ boxed: Box<T>,
+ option_boxed: Option<Box<T>>,
+}
+
+#[derive(Deserialize)]
+#[rustc_copy_clone_marker]
+struct UnitStruct;
+
+#[derive(Serialize)]
+#[allow(dead_code)]
+#[deny(unused_variables)]
+enum Void { }
+
+#[derive(Serialize)]
+#[derive(Deserialize)]
+struct NamedUnit;
+
+#[derive(Deserialize)]
+#[doc = r" A custom basic event not covered by the Matrix specification."]
+#[derive(Debug, Serialize)]
+pub struct CustomEvent {
+ /// The event's content.
+ content: String,
+}
diff --git a/tests/test_macro_input.rs b/tests/test_macro_input.rs
index 3c08da4..0334157 100644
--- a/tests/test_macro_input.rs
+++ b/tests/test_macro_input.rs
@@ -38,6 +38,7 @@
vis: Visibility::Public,
attrs: vec![
Attribute {
+ style: AttrStyle::Outer,
value: MetaItem::List("derive".into(), vec![
MetaItem::Word("Debug".into()),
MetaItem::Word("Clone".into()),
@@ -96,6 +97,7 @@
vis: Visibility::Public,
attrs: vec![
Attribute {
+ style: AttrStyle::Outer,
value: MetaItem::NameValue(
"doc".into(),
Lit::Str(
@@ -106,6 +108,7 @@
is_sugared_doc: true,
},
Attribute {
+ style: AttrStyle::Outer,
value: MetaItem::Word("must_use".into()),
is_sugared_doc: false,
},
diff --git a/tests/test_round_trip.rs b/tests/test_round_trip.rs
new file mode 100644
index 0000000..103fb6d
--- /dev/null
+++ b/tests/test_round_trip.rs
@@ -0,0 +1,107 @@
+#![cfg(feature = "full")]
+
+#[macro_use]
+extern crate quote;
+extern crate syn;
+extern crate syntex_pos;
+extern crate syntex_syntax;
+extern crate walkdir;
+
+use syntex_pos::Span;
+use syntex_syntax::ast::{self, Attribute, TyParam};
+use syntex_syntax::fold::{self, Folder};
+use syntex_syntax::parse::{self, ParseSess, PResult};
+
+use std::fs::File;
+use std::io::{self, Read, Write};
+
+macro_rules! errorf {
+ ($($tt:tt)*) => {
+ write!(io::stderr(), $($tt)*).unwrap();
+ };
+}
+
+#[test]
+fn test_round_trip() {
+ let mut success = true;
+
+ for entry in walkdir::WalkDir::new("tests/cases").into_iter() {
+ let entry = entry.unwrap();
+
+ let path = entry.path();
+ if path.extension().map(|e| e != "rs").unwrap_or(true) {
+ continue;
+ }
+ errorf!("=== {}: ", path.display());
+
+ let mut file = File::open(path).unwrap();
+ let mut content = String::new();
+ file.read_to_string(&mut content).unwrap();
+
+ let krate = match syn::parse_crate(&content) {
+ Ok(krate) => krate,
+ Err(msg) => {
+ errorf!("syn failed to parse\n{}\n", msg);
+ success = false;
+ continue;
+ }
+ };
+ let back = quote!(#krate).to_string();
+
+ let sess = ParseSess::new();
+ let before = syntex_parse(content, &sess).unwrap();
+ let after = match syntex_parse(back, &sess) {
+ Ok(after) => after,
+ Err(mut diagnostic) => {
+ errorf!("syntex failed to parse");
+ diagnostic.emit();
+ success = false;
+ continue;
+ }
+ };
+
+ if before == after {
+ errorf!("pass\n");
+ } else {
+ errorf!("FAIL\nbefore: {:?}\nafter: {:?}\n", before, after);
+ success = false;
+ }
+ }
+
+ assert!(success);
+}
+
+fn syntex_parse<'a>(content: String, sess: &'a ParseSess) -> PResult<'a, ast::Crate> {
+ let name = "test_round_trip".to_string();
+ let cfg = Vec::new();
+ parse::parse_crate_from_source_str(name, content, cfg, sess).map(respan_crate)
+}
+
+fn respan_crate(krate: ast::Crate) -> ast::Crate {
+ struct Respanner;
+
+ impl Folder for Respanner {
+ fn new_span(&mut self, _: Span) -> Span {
+ syntex_pos::DUMMY_SP
+ }
+
+ fn fold_ty_param(&mut self, tp: TyParam) -> TyParam {
+ TyParam {
+ // default fold_ty_param does not fold the span
+ span: self.new_span(tp.span),
+ .. fold::noop_fold_ty_param(tp, self)
+ }
+ }
+
+ fn fold_attribute(&mut self, mut at: Attribute) -> Option<Attribute> {
+ at.node.id.0 = 0;
+ fold::noop_fold_attribute(at, self)
+ }
+
+ fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
+ fold::noop_fold_mac(mac, self)
+ }
+ }
+
+ Respanner.fold_crate(krate)
+}
diff --git a/tests/test_serde_suite.rs b/tests/test_serde_suite.rs
deleted file mode 100644
index 0d6f29a..0000000
--- a/tests/test_serde_suite.rs
+++ /dev/null
@@ -1,606 +0,0 @@
-extern crate syn;
-
-#[macro_use]
-extern crate quote;
-
-/// These are all of the items from serde_codegen's test suite.
-/// Obnoxious whitespace has been added in an attempt to fool the parser.
-#[test]
-fn test_all() {
- for s in ITEMS {
- let ast = syn::parse_macro_input(s).unwrap();
- let tokens = quote!(#ast).to_string();
- assert_eq!(ast, syn::parse_macro_input(&tokens).unwrap());
- }
-
- static ITEMS: &'static [&'static str] = &[
- r#"
- # [ derive ( Serialize ) ]
- #[derive(Deserialize)]
- struct DefaultStruct <A , B, C, D, E> where C : MyDefault , E: MyDefault {
- a1 : A,
- #[serde(default)]
- a2: B,
- #[serde(default = "MyDefault::my_default")]
- a3: C,
- #[serde(skip_deserializing)]
- a4: D,
- #[serde(skip_deserializing, default = "MyDefault::my_default")]
- a5: E,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- enum DefaultEnum<A, B, C, D, E> where C: MyDefault, E: MyDefault {
- Struct {
- a1: A,
- #[serde(default)]
- a2: B,
- #[serde(default = "MyDefault::my_default")]
- a3: C,
- #[serde(skip_deserializing)]
- a4: D,
- #[serde(skip_deserializing, default = "MyDefault::my_default")]
- a5: E,
- },
- }
- "#,
- r#"
- #[derive(Deserialize)]
- struct NoStdDefault(i8);
- "#,
- r#"
- #[derive(Deserialize)]
- struct ContainsNoStdDefault <A : MyDefault> {
- #[serde(default = "MyDefault::my_default")]
- a: A,
- }
- "#,
- r#"
- #[derive(Deserialize)]
- struct ContainsNotDeserialize<A, B, C: DeserializeWith, E: MyDefault> {
- #[serde(skip_deserializing)]
- a: A,
- #[serde(skip_deserializing, default)]
- b: B,
- #[serde(deserialize_with = "DeserializeWith::deserialize_with", default)]
- c: C,
- #[serde(skip_deserializing, default = "MyDefault::my_default")]
- e: E,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[serde(deny_unknown_fields)]
- #[derive(Deserialize)]
- struct DenyUnknown {
- a1: i32,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[serde(rename = "Superhero")]
- #[derive(Deserialize)]
- struct RenameStruct {
- a1: i32,
- #[serde(rename = "a3")]
- a2: i32,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[serde(rename(serialize = "SuperheroSer", deserialize = "SuperheroDe"))]
- #[derive(Deserialize)]
- struct RenameStructSerializeDeserialize {
- a1: i32,
- #[serde(rename(serialize = "a4", deserialize = "a5"))]
- a2: i32,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[serde(rename = "Superhero")]
- #[derive(Deserialize)]
- 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,
- } ,
- }
- "#,
- r#"
- #[derive(Deserialize)]
- #[serde ( rename ( serialize = "SuperheroSer" , deserialize = "SuperheroDe" ) ) ]
- #[derive(Serialize)]
- enum RenameEnumSerializeDeserialize<A> {
-
- #[serde(rename(serialize = "dick_grayson", deserialize = "jason_todd"))]
- Robin {
- a: i8,
- #[serde(rename(serialize = "c"))]
- #[serde(rename(deserialize = "d"))]
- b: A,
- },
- }
- "#,
- r#"
- #[derive(Serialize)]
- struct SkipSerializingStruct< 'a , B, C> where C : ShouldSkip {
- a: & 'a i8,
- #[serde(skip_serializing)]
- b: B,
- #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
- c: C,
- }
- "#,
- r#"
- #[derive(Serialize)]
- enum SkipSerializingEnum<'a, B, C> where C: ShouldSkip {
- Struct {
- a: &'a i8,
- #[serde(skip_serializing)]
- _b: B,
- #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
- c: C,
- },
- }
- "#,
- r#"
- #[derive(Serialize)]
- struct ContainsNotSerialize<'a, B, C, D> where B: 'a , D: SerializeWith {
- a: &'a Option<i8>,
- #[serde(skip_serializing)]
- b: &'a B,
- #[serde(skip_serializing)]
- c: Option<C>,
- #[serde(serialize_with = "SerializeWith::serialize_with")]
- d: D,
- }
- "#,
- r#"
- #[derive(Serialize)]
- struct SerializeWithStruct<'a, B> where B: SerializeWith {
- a: &'a i8,
- #[serde(serialize_with = "SerializeWith::serialize_with")]
- b: B,
- }
- "#,
- r#"
- #[derive(Serialize)]
- enum SerializeWithEnum<'a, B> where B: SerializeWith {
- Struct {
- a: &'a i8,
- #[serde(serialize_with = "SerializeWith::serialize_with")]
- b: B,
- },
- }
- "#,
- r#"
- #[derive(Deserialize)]
- struct DeserializeWithStruct<B> where B: DeserializeWith {
- a: i8,
- #[serde(deserialize_with = "DeserializeWith::deserialize_with")]
- b: B,
- }
- "#,
- r#"
- #[derive(Deserialize)]
- enum DeserializeWithEnum<B> where B: DeserializeWith {
- Struct {
- a: i8,
- #[serde(deserialize_with = "DeserializeWith::deserialize_with")]
- b: B,
- },
- }
- "#,
- r#"
- #[derive(Deserialize)]
- enum InvalidLengthEnum {
- A(i32, i32, i32),
- B(
- #[serde(skip_deserializing)]
- i32, i32, i32),
- }
- "#,
- r#"
- #[derive(Deserialize)]
- struct TupleStruct(i32, i32, i32);
- "#,
- r#"
- #[derive(Deserialize)]
- struct Struct {
- a: i32,
- b: i32,
- #[serde(skip_deserializing)]
- c: i32,
- }
- "#,
- r#"
- #[derive(Deserialize)]
- enum Enum {
- Unit,
- Simple(i32),
- Seq(i32, i32, i32),
- Map {
- a: i32,
- b: i32,
- c: i32,
- },
- }
- "#,
- r#"
- #[derive(Deserialize)]
- struct IgnoreBase {
- a: i32,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct With<T> {
- t: T,
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- x: X,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct WithRef<'a, T: 'a> {
- #[serde(skip_deserializing)]
- t: Option<&'a T>,
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- x: X,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct PhantomX {
- x: PhantomData<X>,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct PhantomT<T> {
- t: PhantomData<T>,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct NoBounds<T> {
- t: T,
- option: Option<T>,
- boxed: Box<T>,
- option_boxed: Option<Box<T>>,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- enum EnumWith<T> {
- Unit,
- Newtype(
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- X),
- Tuple(T,
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- X),
- Struct {
- t: T,
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- x: X,
- },
- }
- "#,
- r#"
- #[derive(Serialize)]
- struct MultipleRef<'a, 'b, 'c, T> where T: 'c, 'c: 'b, 'b: 'a {
- t: T,
- rrrt: &'a &'b &'c T,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct Newtype(
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- X);
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct Tuple<T>(T,
- #[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
- X);
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- enum TreeNode<D> {
- Split {
- left: Box<TreeNode<D>>,
- right: Box<TreeNode<D>>,
- },
- Leaf {
- data: D,
- },
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct ListNode<D> {
- data: D,
- next: Box<ListNode<D>>,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct RecursiveA {
- b: Box<RecursiveB>,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- enum RecursiveB { A(RecursiveA), }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct RecursiveGenericA<T> {
- t: T,
- b: Box<RecursiveGenericB<T>>,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- enum RecursiveGenericB<T> { T(T), A(RecursiveGenericA<T>), }
- "#,
- r#"
- #[derive(Serialize)]
- struct OptionStatic<'a> {
- a: Option<&'a str>,
- b: Option<&'static str>,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[serde(bound = "D: SerializeWith + DeserializeWith")]
- #[derive(Deserialize)]
- struct WithTraits1<D, E> {
- #[serde(serialize_with = "SerializeWith::serialize_with",
- deserialize_with = "DeserializeWith::deserialize_with")]
- d: D,
- #[serde(serialize_with = "SerializeWith::serialize_with",
- deserialize_with = "DeserializeWith::deserialize_with",
- bound = "E: SerializeWith + DeserializeWith")]
- e: E,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[serde(bound(serialize = "D: SerializeWith",
- deserialize = "D: DeserializeWith"))]
- #[derive(Deserialize)]
- struct WithTraits2<D, E> {
- #[serde(serialize_with = "SerializeWith::serialize_with",
- deserialize_with = "DeserializeWith::deserialize_with")]
- d: D,
- #[serde(serialize_with = "SerializeWith::serialize_with",
- bound(serialize = "E: SerializeWith"))]
- #[serde(deserialize_with = "DeserializeWith::deserialize_with",
- bound(deserialize = "E: DeserializeWith"))]
- e: E,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct CowStr<'a>(Cow<'a, str>);
- "#,
- r#"
- #[derive(Serialize)]
- #[serde(bound(deserialize = "T::Owned: Deserialize"))]
- #[derive(Deserialize)]
- struct CowT < 'a , T : ? Sized + 'a + ToOwned > ( Cow < 'a , T > ) ;
- "#,
- r#"
- #[derive(Serialize)]
- struct SerNamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C);
- "#,
- r#"
- #[derive(Deserialize)]
- struct DeNamedTuple<A, B, C>(A, B, C);
- "#,
- r#"
- #[derive(Serialize)]
- struct SerNamedMap<'a, 'b, A: 'a, B: 'b, C> {
- a: &'a A,
- b: &'b mut B,
- c: C,
- }
- "#,
- r#"
- #[derive(Deserialize)]
- struct DeNamedMap<A, B, C> {
- a: A,
- b: < Vec < T > as a :: b :: Trait > :: AssociatedItem,
- c: < Vec < T > > :: AssociatedItem,
- }
- "#,
- r#"
- #[derive(Serialize)]
- enum SerEnum<'a, B: 'a, C: 'a, D> where for < 'a > D: 'a {
- Unit,
- Seq(i8, B, &'a C, &'a mut D),
- Map {
- a: i8,
- b: B,
- c: &'a C,
- d: &'a mut D,
- },
- _Unit2,
- _Seq2(i8, B, &'a C, &'a mut D),
- _Map2 {
- a: i8,
- b: B,
- c: &'a C,
- d: &'a mut D,
- },
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- enum DeEnum<B, C, D> {
- Unit,
- Seq(i8, B, C, D),
- Map {
- a: i8,
- b: B,
- c: C,
- d: D,
- },
- _Unit2,
- _Seq2(i8, B, C, D),
- _Map2 {
- a: i8,
- b: B,
- c: C,
- d: D,
- },
- }
- "#,
- r#"
- #[derive(Serialize)]
- enum Lifetimes<'a> {
- LifetimeSeq(&'a i32),
- NoLifetimeSeq(i32),
- LifetimeMap {
- a: &'a i32,
- },
- NoLifetimeMap {
- a: i32,
- },
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- pub struct GenericStruct<T> {
- x: T,
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- pub struct GenericNewTypeStruct<T>(T);
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- pub struct GenericTupleStruct<T, U>(T, U);
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- pub enum GenericEnum<T, U: for < 'a > F<'a>> {
- Unit,
- NewType(T),
- Seq(T, U),
- Map {
- x: T,
- y: U,
- },
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct DefaultTyParam<T: AssociatedType<X = i32> = i32> {
- phantom: std :: marker :: PhantomData<T>,
- }
- "#,
- r#"
- #[derive(Serialize)]
- struct UnitStruct;
- "#,
- r#"
- #[derive(Serialize)]
- struct TupleStruct(i32, i32, i32);
- "#,
- r#"
- #[derive(Serialize)]
- struct Struct {
- a: i32,
- b: i32,
- c: i32,
- }
- "#,
- r#"
- #[derive(Serialize)]
- enum Enum {
- Unit,
- One(i32),
- Seq(i32, i32),
- Map {
- a: i32,
- b: i32,
- },
- }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct Bounds<T: Serialize + Deserialize> {
- t: T,
- option: Option<T>,
- boxed: Box<T>,
- option_boxed: Option<Box<T>>,
- }
- "#,
- r#"
- #[derive(Deserialize)]
- #[rustc_copy_clone_marker]
- struct UnitStruct;
- "#,
- r#"
- #[derive(Serialize)]
- #[allow(dead_code)]
- #[deny(unused_variables)]
- enum Void { }
- "#,
- r#"
- #[derive(Serialize)]
- #[derive(Deserialize)]
- struct NamedUnit;
- "#,
- r#"
- #[derive(Deserialize)]
- #[doc = r" A custom basic event not covered by the Matrix specification."]
- #[derive(Debug, Serialize)]
- pub struct CustomEvent {
- /// The event's content.
- content: String,
- }
- "#,
- ];
-}