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::*;
6 use crate::deriving::warn_if_deprecated;
9 use syntax::ast::{Expr, MetaItem, Mutability};
10 use syntax::ext::base::{Annotatable, ExtCtxt};
11 use syntax::ext::build::AstBuilder;
13 use syntax::symbol::Symbol;
16 pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt<'_>,
20 push: &mut dyn FnMut(Annotatable)) {
21 expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize")
24 pub fn expand_deriving_decodable(cx: &mut ExtCtxt<'_>,
28 push: &mut dyn FnMut(Annotatable)) {
29 warn_if_deprecated(cx, span, "Decodable");
30 expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
33 fn expand_deriving_decodable_imp(cx: &mut ExtCtxt<'_>,
37 push: &mut dyn FnMut(Annotatable),
38 krate: &'static str) {
39 let typaram = &*deriving::hygienic_type_parameter(item, "__D");
41 let trait_def = TraitDef {
43 attributes: Vec::new(),
44 path: Path::new_(vec![krate, "Decodable"], None, vec![], PathKind::Global),
45 additional_bounds: Vec::new(),
46 generics: LifetimeBounds::empty(),
48 supports_unions: false,
49 methods: vec![MethodDef {
51 generics: LifetimeBounds {
52 lifetimes: Vec::new(),
53 bounds: vec![(typaram,
54 vec![Path::new_(vec![krate, "Decoder"],
60 args: vec![(Ptr(Box::new(Literal(Path::new_local(typaram))),
61 Borrowed(None, Mutability::Mutable)), "d")],
63 Literal(Path::new_(pathvec_std!(cx, result::Result),
65 vec![Box::new(Self_), Box::new(Literal(Path::new_(
66 vec![typaram, "Error"], None, vec![], PathKind::Local
69 attributes: Vec::new(),
71 unify_fieldless_variants: false,
72 combine_substructure: combine_substructure(Box::new(|a, b, c| {
73 decodable_substructure(a, b, c, krate)
76 associated_types: Vec::new(),
79 trait_def.expand(cx, mitem, item, push)
82 fn decodable_substructure(cx: &mut ExtCtxt<'_>,
84 substr: &Substructure<'_>,
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);
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(),
100 let read_struct_field = cx.ident_of("read_struct_field");
102 let path = cx.path_ident(trait_span, substr.type_ident);
104 decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| {
106 cx.expr_method_call(span,
109 vec![cx.expr_str(span, name),
110 cx.expr_usize(span, field),
111 exprdecode.clone()]))
113 let result = cx.expr_ok(trait_span, result);
114 cx.expr_method_call(trait_span,
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)])
121 StaticEnum(_, ref fields) => {
122 let variant = cx.ident_of("i");
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");
128 for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
129 variants.push(cx.expr_str(v_span, ident.name));
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);
135 cx.expr_method_call(span,
138 vec![idx, exprdecode.clone()]))
141 arms.push(cx.arm(v_span,
142 vec![cx.pat_lit(v_span, cx.expr_usize(v_span, i))],
146 arms.push(cx.arm_unreachable(trait_span));
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,
156 cx.ident_of("read_enum_variant"),
157 vec![variant_vec, lambda]);
158 cx.expr_method_call(trait_span,
160 cx.ident_of("read_enum"),
161 vec![cx.expr_str(trait_span, substr.type_ident.name),
162 cx.lambda1(trait_span, result, blkarg)])
164 _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
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<'_>,
173 outer_pat_path: ast::Path,
174 fields: &StaticFields,
177 where F: FnMut(&mut ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>
180 Unnamed(ref fields, is_tuple) => {
181 let path_expr = cx.expr_path(outer_pat_path);
185 let fields = fields.iter()
188 getarg(cx, span, Symbol::intern(&format!("_field{}", i)), i)
192 cx.expr_call(trait_span, path_expr, fields)
195 Named(ref fields) => {
196 // use the field's span to get nicer error messages.
197 let fields = fields.iter()
199 .map(|(i, &(ident, span))| {
200 let arg = getarg(cx, span, ident.name, i);
201 cx.field_imm(span, ident, arg)
204 cx.expr_struct(trait_span, outer_pat_path, fields)