1 //! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more.
3 use crate::deriving::{self, pathvec_std};
4 use crate::deriving::generic::*;
5 use crate::deriving::generic::ty::*;
8 use syntax::ast::{Expr, MetaItem, Mutability};
9 use syntax::ext::base::{Annotatable, ExtCtxt};
11 use syntax::symbol::Symbol;
14 pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt<'_>,
18 push: &mut dyn FnMut(Annotatable)) {
19 expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize")
22 pub fn expand_deriving_decodable(cx: &mut ExtCtxt<'_>,
26 push: &mut dyn FnMut(Annotatable)) {
27 expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
30 fn expand_deriving_decodable_imp(cx: &mut ExtCtxt<'_>,
34 push: &mut dyn FnMut(Annotatable),
35 krate: &'static str) {
36 let typaram = &*deriving::hygienic_type_parameter(item, "__D");
38 let trait_def = TraitDef {
40 attributes: Vec::new(),
41 path: Path::new_(vec![krate, "Decodable"], None, vec![], PathKind::Global),
42 additional_bounds: Vec::new(),
43 generics: LifetimeBounds::empty(),
45 supports_unions: false,
46 methods: vec![MethodDef {
48 generics: LifetimeBounds {
49 lifetimes: Vec::new(),
50 bounds: vec![(typaram,
51 vec![Path::new_(vec![krate, "Decoder"],
57 args: vec![(Ptr(Box::new(Literal(Path::new_local(typaram))),
58 Borrowed(None, Mutability::Mutable)), "d")],
60 Literal(Path::new_(pathvec_std!(cx, result::Result),
62 vec![Box::new(Self_), Box::new(Literal(Path::new_(
63 vec![typaram, "Error"], None, vec![], PathKind::Local
66 attributes: Vec::new(),
68 unify_fieldless_variants: false,
69 combine_substructure: combine_substructure(Box::new(|a, b, c| {
70 decodable_substructure(a, b, c, krate)
73 associated_types: Vec::new(),
76 trait_def.expand(cx, mitem, item, push)
79 fn decodable_substructure(cx: &mut ExtCtxt<'_>,
81 substr: &Substructure<'_>,
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);
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(),
97 let read_struct_field = cx.ident_of("read_struct_field");
99 let path = cx.path_ident(trait_span, substr.type_ident);
101 decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| {
103 cx.expr_method_call(span,
106 vec![cx.expr_str(span, name),
107 cx.expr_usize(span, field),
108 exprdecode.clone()]))
110 let result = cx.expr_ok(trait_span, result);
111 cx.expr_method_call(trait_span,
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)])
118 StaticEnum(_, ref fields) => {
119 let variant = cx.ident_of("i");
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");
125 for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
126 variants.push(cx.expr_str(v_span, ident.name));
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);
132 cx.expr_method_call(span,
135 vec![idx, exprdecode.clone()]))
138 arms.push(cx.arm(v_span,
139 vec![cx.pat_lit(v_span, cx.expr_usize(v_span, i))],
143 arms.push(cx.arm_unreachable(trait_span));
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,
153 cx.ident_of("read_enum_variant"),
154 vec![variant_vec, lambda]);
155 cx.expr_method_call(trait_span,
157 cx.ident_of("read_enum"),
158 vec![cx.expr_str(trait_span, substr.type_ident.name),
159 cx.lambda1(trait_span, result, blkarg)])
161 _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
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<'_>,
170 outer_pat_path: ast::Path,
171 fields: &StaticFields,
174 where F: FnMut(&mut ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>
177 Unnamed(ref fields, is_tuple) => {
178 let path_expr = cx.expr_path(outer_pat_path);
182 let fields = fields.iter()
185 getarg(cx, span, Symbol::intern(&format!("_field{}", i)), i)
189 cx.expr_call(trait_span, path_expr, fields)
192 Named(ref fields) => {
193 // use the field's span to get nicer error messages.
194 let fields = fields.iter()
196 .map(|(i, &(ident, span))| {
197 let arg = getarg(cx, span, ident.name, i);
198 cx.field_imm(span, ident, arg)
201 cx.expr_struct(trait_span, outer_pat_path, fields)