1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use super::*;

/// Struct or enum sent to a `proc_macro_derive` macro.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct DeriveInput {
    /// Name of the struct or enum.
    pub ident: Ident,

    /// Visibility of the struct or enum.
    pub vis: Visibility,

    /// Attributes tagged on the whole struct or enum.
    pub attrs: Vec<Attribute>,

    /// Generics required to complete the definition.
    pub generics: Generics,

    /// Data within the struct or enum.
    pub body: Body,
}

/// Body of a derived struct or enum.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Body {
    /// It's an enum.
    Enum(Vec<Variant>),

    /// It's a struct.
    Struct(VariantData),
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use Generics;
    use attr::parsing::outer_attr;
    use data::parsing::{visibility, struct_body, enum_body};
    use generics::parsing::generics;
    use ident::parsing::ident;

    named!(pub derive_input -> DeriveInput, do_parse!(
        attrs: many0!(outer_attr) >>
        vis: visibility >>
        which: alt!(keyword!("struct") | keyword!("enum")) >>
        id: ident >>
        generics: generics >>
        item: switch!(value!(which),
            "struct" => map!(struct_body, move |(wh, body)| DeriveInput {
                ident: id,
                vis: vis,
                attrs: attrs,
                generics: Generics {
                    where_clause: wh,
                    .. generics
                },
                body: Body::Struct(body),
            })
            |
            "enum" => map!(enum_body, move |(wh, body)| DeriveInput {
                ident: id,
                vis: vis,
                attrs: attrs,
                generics: Generics {
                    where_clause: wh,
                    .. generics
                },
                body: Body::Enum(body),
            })
        ) >>
        (item)
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use attr::FilterAttrs;
    use data::VariantData;
    use quote::{Tokens, ToTokens};

    impl ToTokens for DeriveInput {
        fn to_tokens(&self, tokens: &mut Tokens) {
            for attr in self.attrs.outer() {
                attr.to_tokens(tokens);
            }
            self.vis.to_tokens(tokens);
            match self.body {
                Body::Enum(_) => tokens.append("enum"),
                Body::Struct(_) => tokens.append("struct"),
            }
            self.ident.to_tokens(tokens);
            self.generics.to_tokens(tokens);
            match self.body {
                Body::Enum(ref variants) => {
                    self.generics.where_clause.to_tokens(tokens);
                    tokens.append("{");
                    for variant in variants {
                        variant.to_tokens(tokens);
                        tokens.append(",");
                    }
                    tokens.append("}");
                }
                Body::Struct(ref variant_data) => {
                    match *variant_data {
                        VariantData::Struct(_) => {
                            self.generics.where_clause.to_tokens(tokens);
                            variant_data.to_tokens(tokens);
                            // no semicolon
                        }
                        VariantData::Tuple(_) => {
                            variant_data.to_tokens(tokens);
                            self.generics.where_clause.to_tokens(tokens);
                            tokens.append(";");
                        }
                        VariantData::Unit => {
                            self.generics.where_clause.to_tokens(tokens);
                            tokens.append(";");
                        }
                    }
                }
            }
        }
    }
}