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