Other item kinds
diff --git a/src/data.rs b/src/data.rs
new file mode 100644
index 0000000..64c893d
--- /dev/null
+++ b/src/data.rs
@@ -0,0 +1,213 @@
+use super::*;
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct Variant {
+    pub ident: Ident,
+    pub attrs: Vec<Attribute>,
+    pub data: VariantData,
+    /// Explicit discriminant, e.g. `Foo = 1`
+    pub discriminant: Option<Discriminant>,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum VariantData {
+    Struct(Vec<Field>),
+    Tuple(Vec<Field>),
+    Unit,
+}
+
+impl VariantData {
+    pub fn fields(&self) -> &[Field] {
+        match *self {
+            VariantData::Struct(ref fields) |
+            VariantData::Tuple(ref fields) => fields,
+            VariantData::Unit => &[],
+        }
+    }
+}
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct Field {
+    pub ident: Option<Ident>,
+    pub vis: Visibility,
+    pub attrs: Vec<Attribute>,
+    pub ty: Ty,
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum Visibility {
+    Public,
+    Inherited,
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub struct Discriminant {
+    pub value: u64,
+    pub ty: IntTy,
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+    use super::*;
+    use attr::parsing::attribute;
+    use ident::parsing::ident;
+    use lit::parsing::int;
+    use ty::parsing::ty;
+    use nom::multispace;
+
+    named!(pub struct_body -> VariantData, alt!(
+        struct_like_body => { VariantData::Struct }
+        |
+        terminated!(tuple_like_body, punct!(";")) => { VariantData::Tuple }
+        |
+        punct!(";") => { |_| VariantData::Unit }
+    ));
+
+    named!(pub enum_body -> Vec<Variant>, do_parse!(
+        punct!("{") >>
+        variants: separated_list!(punct!(","), variant) >>
+        option!(punct!(",")) >>
+        punct!("}") >>
+        (variants)
+    ));
+
+    named!(variant -> Variant, do_parse!(
+        attrs: many0!(attribute) >>
+        id: ident >>
+        data: alt!(
+            struct_like_body => { VariantData::Struct }
+            |
+            tuple_like_body => { VariantData::Tuple }
+            |
+            epsilon!() => { |_| VariantData::Unit }
+        ) >>
+        disr: option!(preceded!(punct!("="), discriminant)) >>
+        (Variant {
+            ident: id,
+            attrs: attrs,
+            data: data,
+            discriminant: disr,
+        })
+    ));
+
+    named!(struct_like_body -> Vec<Field>, do_parse!(
+        punct!("{") >>
+        fields: separated_list!(punct!(","), struct_field) >>
+        option!(punct!(",")) >>
+        punct!("}") >>
+        (fields)
+    ));
+
+    named!(tuple_like_body -> Vec<Field>, do_parse!(
+        punct!("(") >>
+        fields: separated_list!(punct!(","), tuple_field) >>
+        option!(punct!(",")) >>
+        punct!(")") >>
+        (fields)
+    ));
+
+    named!(struct_field -> Field, do_parse!(
+        attrs: many0!(attribute) >>
+        vis: visibility >>
+        id: ident >>
+        punct!(":") >>
+        ty: ty >>
+        (Field {
+            ident: Some(id),
+            vis: vis,
+            attrs: attrs,
+            ty: ty,
+        })
+    ));
+
+    named!(tuple_field -> Field, do_parse!(
+        attrs: many0!(attribute) >>
+        vis: visibility >>
+        ty: ty >>
+        (Field {
+            ident: None,
+            vis: vis,
+            attrs: attrs,
+            ty: ty,
+        })
+    ));
+
+    named!(pub visibility -> Visibility, alt!(
+        do_parse!(
+            punct!("pub") >>
+            multispace >>
+            (Visibility::Public)
+        )
+        |
+        epsilon!() => { |_| Visibility::Inherited }
+    ));
+
+    named!(discriminant -> Discriminant, map!(
+        int,
+        |(value, ty)| Discriminant {
+            value: value,
+            ty: ty,
+        }
+    ));
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+    use super::*;
+    use lit::Lit;
+    use quote::{Tokens, ToTokens};
+
+    impl ToTokens for Variant {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            for attr in &self.attrs {
+                attr.to_tokens(tokens);
+            }
+            self.ident.to_tokens(tokens);
+            self.data.to_tokens(tokens);
+            if let Some(ref disr) = self.discriminant {
+                tokens.append("=");
+                disr.to_tokens(tokens);
+            }
+        }
+    }
+
+    impl ToTokens for VariantData {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            match *self {
+                VariantData::Struct(ref fields) => {
+                    tokens.append("{");
+                    tokens.append_separated(fields, ",");
+                    tokens.append("}");
+                }
+                VariantData::Tuple(ref fields) => {
+                    tokens.append("(");
+                    tokens.append_separated(fields, ",");
+                    tokens.append(")");
+                }
+                VariantData::Unit => {}
+            }
+        }
+    }
+
+    impl ToTokens for Field {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            for attr in &self.attrs {
+                attr.to_tokens(tokens);
+            }
+            if let Visibility::Public = self.vis {
+                tokens.append("pub");
+            }
+            if let Some(ref ident) = self.ident {
+                ident.to_tokens(tokens);
+                tokens.append(":");
+            }
+            self.ty.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for Discriminant {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            Lit::Int(self.value, self.ty).to_tokens(tokens);
+        }
+    }
+}