1 use super::*;
2 
3 /// An enum variant.
4 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
5 pub struct Variant {
6     /// Name of the variant.
7     pub ident: Ident,
8 
9     /// Attributes tagged on the variant.
10     pub attrs: Vec<Attribute>,
11 
12     /// Type of variant.
13     pub data: VariantData,
14 
15     /// Explicit discriminant, e.g. `Foo = 1`
16     pub discriminant: Option<ConstExpr>,
17 }
18 
19 /// Data stored within an enum variant or struct.
20 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
21 pub enum VariantData {
22     /// Struct variant, e.g. `Point { x: f64, y: f64 }`.
23     Struct(Vec<Field>),
24 
25     /// Tuple variant, e.g. `Some(T)`.
26     Tuple(Vec<Field>),
27 
28     /// Unit variant, e.g. `None`.
29     Unit,
30 }
31 
32 impl VariantData {
33     /// Slice containing the fields stored in the variant.
fields(&self) -> &[Field]34     pub fn fields(&self) -> &[Field] {
35         match *self {
36             VariantData::Struct(ref fields) |
37             VariantData::Tuple(ref fields) => fields,
38             VariantData::Unit => &[],
39         }
40     }
41 
42     /// Mutable slice containing the fields stored in the variant.
fields_mut(&mut self) -> &mut [Field]43     pub fn fields_mut(&mut self) -> &mut [Field] {
44         match *self {
45             VariantData::Struct(ref mut fields) |
46             VariantData::Tuple(ref mut fields) => fields,
47             VariantData::Unit => &mut [],
48         }
49     }
50 }
51 
52 /// A field of a struct or enum variant.
53 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
54 pub struct Field {
55     /// Name of the field, if any.
56     ///
57     /// Fields of tuple structs have no names.
58     pub ident: Option<Ident>,
59 
60     /// Visibility of the field.
61     pub vis: Visibility,
62 
63     /// Attributes tagged on the field.
64     pub attrs: Vec<Attribute>,
65 
66     /// Type of the field.
67     pub ty: Ty,
68 }
69 
70 
71 /// Visibility level of an item.
72 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
73 pub enum Visibility {
74     /// Public, i.e. `pub`.
75     Public,
76 
77     /// Crate-visible, i.e. `pub(crate)`.
78     Crate,
79 
80     /// Restricted, e.g. `pub(some::module)`.
81     Restricted(Box<Path>),
82 
83     /// Inherited, i.e. private.
84     Inherited,
85 }
86 
87 #[cfg(feature = "parsing")]
88 pub mod parsing {
89     use super::*;
90     use WhereClause;
91     #[cfg(feature = "full")]
92     use ConstExpr;
93     use attr::parsing::outer_attr;
94     #[cfg(feature = "full")]
95     use constant::parsing::const_expr;
96     #[cfg(feature = "full")]
97     use expr::parsing::expr;
98     use generics::parsing::where_clause;
99     use ident::parsing::ident;
100     use ty::parsing::{path, ty};
101 
102     named!(pub struct_body -> (WhereClause, VariantData), alt!(
103         do_parse!(
104             wh: where_clause >>
105             body: struct_like_body >>
106             (wh, VariantData::Struct(body))
107         )
108         |
109         do_parse!(
110             body: tuple_like_body >>
111             wh: where_clause >>
112             punct!(";") >>
113             (wh, VariantData::Tuple(body))
114         )
115         |
116         do_parse!(
117             wh: where_clause >>
118             punct!(";") >>
119             (wh, VariantData::Unit)
120         )
121     ));
122 
123     named!(pub enum_body -> (WhereClause, Vec<Variant>), do_parse!(
124         wh: where_clause >>
125         punct!("{") >>
126         variants: terminated_list!(punct!(","), variant) >>
127         punct!("}") >>
128         (wh, variants)
129     ));
130 
131     named!(variant -> Variant, do_parse!(
132         attrs: many0!(outer_attr) >>
133         id: ident >>
134         data: alt!(
135             struct_like_body => { VariantData::Struct }
136             |
137             tuple_like_body => { VariantData::Tuple }
138             |
139             epsilon!() => { |_| VariantData::Unit }
140         ) >>
141         disr: option!(preceded!(punct!("="), discriminant)) >>
142         (Variant {
143             ident: id,
144             attrs: attrs,
145             data: data,
146             discriminant: disr,
147         })
148     ));
149 
150     #[cfg(not(feature = "full"))]
151     use constant::parsing::const_expr as discriminant;
152 
153     #[cfg(feature = "full")]
154     named!(discriminant -> ConstExpr, alt!(
155         terminated!(const_expr, after_discriminant)
156         |
157         terminated!(expr, after_discriminant) => { ConstExpr::Other }
158     ));
159 
160     #[cfg(feature = "full")]
161     named!(after_discriminant -> &str, peek!(alt!(punct!(",") | punct!("}"))));
162 
163     named!(pub struct_like_body -> Vec<Field>, do_parse!(
164         punct!("{") >>
165         fields: terminated_list!(punct!(","), struct_field) >>
166         punct!("}") >>
167         (fields)
168     ));
169 
170     named!(tuple_like_body -> Vec<Field>, do_parse!(
171         punct!("(") >>
172         fields: terminated_list!(punct!(","), tuple_field) >>
173         punct!(")") >>
174         (fields)
175     ));
176 
177     named!(struct_field -> Field, do_parse!(
178         attrs: many0!(outer_attr) >>
179         vis: visibility >>
180         id: ident >>
181         punct!(":") >>
182         ty: ty >>
183         (Field {
184             ident: Some(id),
185             vis: vis,
186             attrs: attrs,
187             ty: ty,
188         })
189     ));
190 
191     named!(tuple_field -> Field, do_parse!(
192         attrs: many0!(outer_attr) >>
193         vis: visibility >>
194         ty: ty >>
195         (Field {
196             ident: None,
197             vis: vis,
198             attrs: attrs,
199             ty: ty,
200         })
201     ));
202 
203     named!(pub visibility -> Visibility, alt!(
204         do_parse!(
205             keyword!("pub") >>
206             punct!("(") >>
207             keyword!("crate") >>
208             punct!(")") >>
209             (Visibility::Crate)
210         )
211         |
212         do_parse!(
213             keyword!("pub") >>
214             punct!("(") >>
215             restricted: path >>
216             punct!(")") >>
217             (Visibility::Restricted(Box::new(restricted)))
218         )
219         |
220         keyword!("pub") => { |_| Visibility::Public }
221         |
222         epsilon!() => { |_| Visibility::Inherited }
223     ));
224 }
225 
226 #[cfg(feature = "printing")]
227 mod printing {
228     use super::*;
229     use quote::{Tokens, ToTokens};
230 
231     impl ToTokens for Variant {
to_tokens(&self, tokens: &mut Tokens)232         fn to_tokens(&self, tokens: &mut Tokens) {
233             for attr in &self.attrs {
234                 attr.to_tokens(tokens);
235             }
236             self.ident.to_tokens(tokens);
237             self.data.to_tokens(tokens);
238             if let Some(ref disr) = self.discriminant {
239                 tokens.append("=");
240                 disr.to_tokens(tokens);
241             }
242         }
243     }
244 
245     impl ToTokens for VariantData {
to_tokens(&self, tokens: &mut Tokens)246         fn to_tokens(&self, tokens: &mut Tokens) {
247             match *self {
248                 VariantData::Struct(ref fields) => {
249                     tokens.append("{");
250                     tokens.append_separated(fields, ",");
251                     tokens.append("}");
252                 }
253                 VariantData::Tuple(ref fields) => {
254                     tokens.append("(");
255                     tokens.append_separated(fields, ",");
256                     tokens.append(")");
257                 }
258                 VariantData::Unit => {}
259             }
260         }
261     }
262 
263     impl ToTokens for Field {
to_tokens(&self, tokens: &mut Tokens)264         fn to_tokens(&self, tokens: &mut Tokens) {
265             for attr in &self.attrs {
266                 attr.to_tokens(tokens);
267             }
268             self.vis.to_tokens(tokens);
269             if let Some(ref ident) = self.ident {
270                 ident.to_tokens(tokens);
271                 tokens.append(":");
272             }
273             self.ty.to_tokens(tokens);
274         }
275     }
276 
277     impl ToTokens for Visibility {
to_tokens(&self, tokens: &mut Tokens)278         fn to_tokens(&self, tokens: &mut Tokens) {
279             match *self {
280                 Visibility::Public => tokens.append("pub"),
281                 Visibility::Crate => {
282                     tokens.append("pub");
283                     tokens.append("(");
284                     tokens.append("crate");
285                     tokens.append(")");
286                 }
287                 Visibility::Restricted(ref path) => {
288                     tokens.append("pub");
289                     tokens.append("(");
290                     path.to_tokens(tokens);
291                     tokens.append(")");
292                 }
293                 Visibility::Inherited => {}
294             }
295         }
296     }
297 }
298