]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_ext/deriving/decodable.rs
Replace AstBuilder with inherent methods
[rust.git] / src / libsyntax_ext / deriving / decodable.rs
1 //! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more.
2
3 use crate::deriving::{self, pathvec_std};
4 use crate::deriving::generic::*;
5 use crate::deriving::generic::ty::*;
6
7 use syntax::ast;
8 use syntax::ast::{Expr, MetaItem, Mutability};
9 use syntax::ext::base::{Annotatable, ExtCtxt};
10 use syntax::ptr::P;
11 use syntax::symbol::Symbol;
12 use syntax_pos::Span;
13
14 pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt<'_>,
15                                        span: Span,
16                                        mitem: &MetaItem,
17                                        item: &Annotatable,
18                                        push: &mut dyn FnMut(Annotatable)) {
19     expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize")
20 }
21
22 pub fn expand_deriving_decodable(cx: &mut ExtCtxt<'_>,
23                                  span: Span,
24                                  mitem: &MetaItem,
25                                  item: &Annotatable,
26                                  push: &mut dyn FnMut(Annotatable)) {
27     expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
28 }
29
30 fn expand_deriving_decodable_imp(cx: &mut ExtCtxt<'_>,
31                                  span: Span,
32                                  mitem: &MetaItem,
33                                  item: &Annotatable,
34                                  push: &mut dyn FnMut(Annotatable),
35                                  krate: &'static str) {
36     let typaram = &*deriving::hygienic_type_parameter(item, "__D");
37
38     let trait_def = TraitDef {
39         span,
40         attributes: Vec::new(),
41         path: Path::new_(vec![krate, "Decodable"], None, vec![], PathKind::Global),
42         additional_bounds: Vec::new(),
43         generics: LifetimeBounds::empty(),
44         is_unsafe: false,
45         supports_unions: false,
46         methods: vec![MethodDef {
47                           name: "decode",
48                           generics: LifetimeBounds {
49                               lifetimes: Vec::new(),
50                               bounds: vec![(typaram,
51                                             vec![Path::new_(vec![krate, "Decoder"],
52                                                             None,
53                                                             vec![],
54                                                             PathKind::Global)])],
55                           },
56                           explicit_self: None,
57                           args: vec![(Ptr(Box::new(Literal(Path::new_local(typaram))),
58                                          Borrowed(None, Mutability::Mutable)), "d")],
59                           ret_ty:
60                               Literal(Path::new_(pathvec_std!(cx, result::Result),
61                                                  None,
62                                                  vec![Box::new(Self_), Box::new(Literal(Path::new_(
63                         vec![typaram, "Error"], None, vec![], PathKind::Local
64                     )))],
65                                                  PathKind::Std)),
66                           attributes: Vec::new(),
67                           is_unsafe: false,
68                           unify_fieldless_variants: false,
69                           combine_substructure: combine_substructure(Box::new(|a, b, c| {
70                               decodable_substructure(a, b, c, krate)
71                           })),
72                       }],
73         associated_types: Vec::new(),
74     };
75
76     trait_def.expand(cx, mitem, item, push)
77 }
78
79 fn decodable_substructure(cx: &mut ExtCtxt<'_>,
80                           trait_span: Span,
81                           substr: &Substructure<'_>,
82                           krate: &str)
83                           -> P<Expr> {
84     let decoder = substr.nonself_args[0].clone();
85     let recurse = vec![cx.ident_of(krate), cx.ident_of("Decodable"), cx.ident_of("decode")];
86     let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
87     // throw an underscore in front to suppress unused variable warnings
88     let blkarg = cx.ident_of("_d");
89     let blkdecoder = cx.expr_ident(trait_span, blkarg);
90
91     return match *substr.fields {
92         StaticStruct(_, ref summary) => {
93             let nfields = match *summary {
94                 Unnamed(ref fields, _) => fields.len(),
95                 Named(ref fields) => fields.len(),
96             };
97             let read_struct_field = cx.ident_of("read_struct_field");
98
99             let path = cx.path_ident(trait_span, substr.type_ident);
100             let result =
101                 decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| {
102                     cx.expr_try(span,
103                                 cx.expr_method_call(span,
104                                                     blkdecoder.clone(),
105                                                     read_struct_field,
106                                                     vec![cx.expr_str(span, name),
107                                                          cx.expr_usize(span, field),
108                                                          exprdecode.clone()]))
109                 });
110             let result = cx.expr_ok(trait_span, result);
111             cx.expr_method_call(trait_span,
112                                 decoder,
113                                 cx.ident_of("read_struct"),
114                                 vec![cx.expr_str(trait_span, substr.type_ident.name),
115                                      cx.expr_usize(trait_span, nfields),
116                                      cx.lambda1(trait_span, result, blkarg)])
117         }
118         StaticEnum(_, ref fields) => {
119             let variant = cx.ident_of("i");
120
121             let mut arms = Vec::with_capacity(fields.len() + 1);
122             let mut variants = Vec::with_capacity(fields.len());
123             let rvariant_arg = cx.ident_of("read_enum_variant_arg");
124
125             for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
126                 variants.push(cx.expr_str(v_span, ident.name));
127
128                 let path = cx.path(trait_span, vec![substr.type_ident, ident]);
129                 let decoded = decode_static_fields(cx, v_span, path, parts, |cx, span, _, field| {
130                     let idx = cx.expr_usize(span, field);
131                     cx.expr_try(span,
132                                 cx.expr_method_call(span,
133                                                     blkdecoder.clone(),
134                                                     rvariant_arg,
135                                                     vec![idx, exprdecode.clone()]))
136                 });
137
138                 arms.push(cx.arm(v_span,
139                                  vec![cx.pat_lit(v_span, cx.expr_usize(v_span, i))],
140                                  decoded));
141             }
142
143             arms.push(cx.arm_unreachable(trait_span));
144
145             let result =
146                 cx.expr_ok(trait_span,
147                            cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms));
148             let lambda = cx.lambda(trait_span, vec![blkarg, variant], result);
149             let variant_vec = cx.expr_vec(trait_span, variants);
150             let variant_vec = cx.expr_addr_of(trait_span, variant_vec);
151             let result = cx.expr_method_call(trait_span,
152                                              blkdecoder,
153                                              cx.ident_of("read_enum_variant"),
154                                              vec![variant_vec, lambda]);
155             cx.expr_method_call(trait_span,
156                                 decoder,
157                                 cx.ident_of("read_enum"),
158                                 vec![cx.expr_str(trait_span, substr.type_ident.name),
159                                      cx.lambda1(trait_span, result, blkarg)])
160         }
161         _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
162     };
163 }
164
165 /// Creates a decoder for a single enum variant/struct:
166 /// - `outer_pat_path` is the path to this enum variant/struct
167 /// - `getarg` should retrieve the `usize`-th field with name `@str`.
168 fn decode_static_fields<F>(cx: &mut ExtCtxt<'_>,
169                            trait_span: Span,
170                            outer_pat_path: ast::Path,
171                            fields: &StaticFields,
172                            mut getarg: F)
173                            -> P<Expr>
174     where F: FnMut(&mut ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>
175 {
176     match *fields {
177         Unnamed(ref fields, is_tuple) => {
178             let path_expr = cx.expr_path(outer_pat_path);
179             if !is_tuple {
180                 path_expr
181             } else {
182                 let fields = fields.iter()
183                     .enumerate()
184                     .map(|(i, &span)| {
185                         getarg(cx, span, Symbol::intern(&format!("_field{}", i)), i)
186                     })
187                     .collect();
188
189                 cx.expr_call(trait_span, path_expr, fields)
190             }
191         }
192         Named(ref fields) => {
193             // use the field's span to get nicer error messages.
194             let fields = fields.iter()
195                 .enumerate()
196                 .map(|(i, &(ident, span))| {
197                     let arg = getarg(cx, span, ident.name, i);
198                     cx.field_imm(span, ident, arg)
199                 })
200                 .collect();
201             cx.expr_struct(trait_span, outer_pat_path, fields)
202         }
203     }
204 }