]> git.proxmox.com Git - rustc.git/blob - src/vendor/serde_derive_internals/src/ast.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / vendor / serde_derive_internals / src / ast.rs
1 // Copyright 2017 Serde Developers
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8
9 use syn;
10 use attr;
11 use check;
12 use Ctxt;
13
14 pub struct Container<'a> {
15 pub ident: syn::Ident,
16 pub attrs: attr::Container,
17 pub body: Body<'a>,
18 pub generics: &'a syn::Generics,
19 }
20
21 pub enum Body<'a> {
22 Enum(Vec<Variant<'a>>),
23 Struct(Style, Vec<Field<'a>>),
24 }
25
26 pub struct Variant<'a> {
27 pub ident: syn::Ident,
28 pub attrs: attr::Variant,
29 pub style: Style,
30 pub fields: Vec<Field<'a>>,
31 }
32
33 pub struct Field<'a> {
34 pub ident: Option<syn::Ident>,
35 pub attrs: attr::Field,
36 pub ty: &'a syn::Ty,
37 }
38
39 #[derive(Copy, Clone)]
40 pub enum Style {
41 Struct,
42 Tuple,
43 Newtype,
44 Unit,
45 }
46
47 impl<'a> Container<'a> {
48 pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput) -> Container<'a> {
49 let attrs = attr::Container::from_ast(cx, item);
50
51 let mut body = match item.body {
52 syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)),
53 syn::Body::Struct(ref variant_data) => {
54 let (style, fields) = struct_from_ast(cx, variant_data, None);
55 Body::Struct(style, fields)
56 }
57 };
58
59 match body {
60 Body::Enum(ref mut variants) => {
61 for ref mut variant in variants {
62 variant.attrs.rename_by_rule(attrs.rename_all());
63 for ref mut field in &mut variant.fields {
64 field.attrs.rename_by_rule(variant.attrs.rename_all());
65 }
66 }
67 }
68 Body::Struct(_, ref mut fields) => {
69 for field in fields {
70 field.attrs.rename_by_rule(attrs.rename_all());
71 }
72 }
73 }
74
75 let item = Container {
76 ident: item.ident.clone(),
77 attrs: attrs,
78 body: body,
79 generics: &item.generics,
80 };
81 check::check(cx, &item);
82 item
83 }
84 }
85
86 impl<'a> Body<'a> {
87 pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
88 match *self {
89 Body::Enum(ref variants) => {
90 Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
91 }
92 Body::Struct(_, ref fields) => Box::new(fields.iter()),
93 }
94 }
95
96 pub fn has_getter(&self) -> bool {
97 self.all_fields().any(|f| f.attrs.getter().is_some())
98 }
99 }
100
101 fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>> {
102 variants
103 .iter()
104 .map(
105 |variant| {
106 let attrs = attr::Variant::from_ast(cx, variant);
107 let (style, fields) = struct_from_ast(cx, &variant.data, Some(&attrs));
108 Variant {
109 ident: variant.ident.clone(),
110 attrs: attrs,
111 style: style,
112 fields: fields,
113 }
114 },
115 )
116 .collect()
117 }
118
119 fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData, attrs: Option<&attr::Variant>) -> (Style, Vec<Field<'a>>) {
120 match *data {
121 syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields, attrs)),
122 syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
123 (Style::Newtype, fields_from_ast(cx, fields, attrs))
124 }
125 syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields, attrs)),
126 syn::VariantData::Unit => (Style::Unit, Vec::new()),
127 }
128 }
129
130 fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field], attrs: Option<&attr::Variant>) -> Vec<Field<'a>> {
131 fields
132 .iter()
133 .enumerate()
134 .map(
135 |(i, field)| {
136 Field {
137 ident: field.ident.clone(),
138 attrs: attr::Field::from_ast(cx, i, field, attrs),
139 ty: &field.ty,
140 }
141 },
142 )
143 .collect()
144 }