1 //! The compiler code necessary for `#[derive(RustcDecodable)]`. See encodable.rs for more.
3 use crate::deriving
::generic
::ty
::*;
4 use crate::deriving
::generic
::*;
5 use crate::deriving
::pathvec_std
;
8 use rustc_ast
::{self as ast, Expr, MetaItem, Mutability}
;
9 use rustc_expand
::base
::{Annotatable, ExtCtxt}
;
10 use rustc_span
::symbol
::{sym, Ident, Symbol}
;
13 pub fn expand_deriving_rustc_decodable(
18 push
: &mut dyn FnMut(Annotatable
),
20 let krate
= sym
::rustc_serialize
;
21 let typaram
= sym
::__D
;
23 let trait_def
= TraitDef
{
25 attributes
: Vec
::new(),
26 path
: Path
::new_(vec
![krate
, sym
::Decodable
], None
, vec
![], PathKind
::Global
),
27 additional_bounds
: Vec
::new(),
28 generics
: Bounds
::empty(),
30 supports_unions
: false,
31 methods
: vec
![MethodDef
{
36 vec
![Path
::new_(vec
![krate
, sym
::Decoder
], None
, vec
![], PathKind
::Global
)],
41 Ptr(Box
::new(Literal(Path
::new_local(typaram
))), Borrowed(None
, Mutability
::Mut
)),
44 ret_ty
: Literal(Path
::new_(
45 pathvec_std
!(result
::Result
),
49 Box
::new(Literal(Path
::new_(
50 vec
![typaram
, sym
::Error
],
58 attributes
: Vec
::new(),
60 unify_fieldless_variants
: false,
61 combine_substructure
: combine_substructure(Box
::new(|a
, b
, c
| {
62 decodable_substructure(a
, b
, c
, krate
)
65 associated_types
: Vec
::new(),
68 trait_def
.expand(cx
, mitem
, item
, push
)
71 fn decodable_substructure(
74 substr
: &Substructure
<'_
>,
77 let decoder
= substr
.nonself_args
[0].clone();
79 Ident
::new(krate
, trait_span
),
80 Ident
::new(sym
::Decodable
, trait_span
),
81 Ident
::new(sym
::decode
, trait_span
),
83 let exprdecode
= cx
.expr_path(cx
.path_global(trait_span
, recurse
));
84 // throw an underscore in front to suppress unused variable warnings
85 let blkarg
= Ident
::new(sym
::_d
, trait_span
);
86 let blkdecoder
= cx
.expr_ident(trait_span
, blkarg
);
88 match *substr
.fields
{
89 StaticStruct(_
, ref summary
) => {
90 let nfields
= match *summary
{
91 Unnamed(ref fields
, _
) => fields
.len(),
92 Named(ref fields
) => fields
.len(),
94 let fn_read_struct_field_path
: Vec
<_
> =
95 cx
.def_site_path(&[sym
::rustc_serialize
, sym
::Decoder
, sym
::read_struct_field
]);
97 let path
= cx
.path_ident(trait_span
, substr
.type_ident
);
99 decode_static_fields(cx
, trait_span
, path
, summary
, |cx
, span
, name
, field
| {
104 fn_read_struct_field_path
.clone(),
107 cx
.expr_str(span
, name
),
108 cx
.expr_usize(span
, field
),
114 let result
= cx
.expr_ok(trait_span
, result
);
115 let fn_read_struct_path
: Vec
<_
> =
116 cx
.def_site_path(&[sym
::rustc_serialize
, sym
::Decoder
, sym
::read_struct
]);
123 cx
.expr_str(trait_span
, substr
.type_ident
.name
),
124 cx
.expr_usize(trait_span
, nfields
),
125 cx
.lambda1(trait_span
, result
, blkarg
),
129 StaticEnum(_
, ref fields
) => {
130 let variant
= Ident
::new(sym
::i
, trait_span
);
132 let mut arms
= Vec
::with_capacity(fields
.len() + 1);
133 let mut variants
= Vec
::with_capacity(fields
.len());
135 let fn_read_enum_variant_arg_path
: Vec
<_
> =
136 cx
.def_site_path(&[sym
::rustc_serialize
, sym
::Decoder
, sym
::read_enum_variant_arg
]);
138 for (i
, &(ident
, v_span
, ref parts
)) in fields
.iter().enumerate() {
139 variants
.push(cx
.expr_str(v_span
, ident
.name
));
141 let path
= cx
.path(trait_span
, vec
![substr
.type_ident
, ident
]);
143 decode_static_fields(cx
, v_span
, path
, parts
, |cx
, span
, _
, field
| {
144 let idx
= cx
.expr_usize(span
, field
);
149 fn_read_enum_variant_arg_path
.clone(),
150 vec
![blkdecoder
.clone(), idx
, exprdecode
.clone()],
155 arms
.push(cx
.arm(v_span
, cx
.pat_lit(v_span
, cx
.expr_usize(v_span
, i
)), decoded
));
158 arms
.push(cx
.arm_unreachable(trait_span
));
160 let result
= cx
.expr_ok(
162 cx
.expr_match(trait_span
, cx
.expr_ident(trait_span
, variant
), arms
),
164 let lambda
= cx
.lambda(trait_span
, vec
![blkarg
, variant
], result
);
165 let variant_vec
= cx
.expr_vec(trait_span
, variants
);
166 let variant_vec
= cx
.expr_addr_of(trait_span
, variant_vec
);
167 let fn_read_enum_variant_path
: Vec
<_
> =
168 cx
.def_site_path(&[sym
::rustc_serialize
, sym
::Decoder
, sym
::read_enum_variant
]);
169 let result
= cx
.expr_call_global(
171 fn_read_enum_variant_path
,
172 vec
![blkdecoder
, variant_vec
, lambda
],
174 let fn_read_enum_path
: Vec
<_
> =
175 cx
.def_site_path(&[sym
::rustc_serialize
, sym
::Decoder
, sym
::read_enum
]);
182 cx
.expr_str(trait_span
, substr
.type_ident
.name
),
183 cx
.lambda1(trait_span
, result
, blkarg
),
187 _
=> cx
.bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
191 /// Creates a decoder for a single enum variant/struct:
192 /// - `outer_pat_path` is the path to this enum variant/struct
193 /// - `getarg` should retrieve the `usize`-th field with name `@str`.
194 fn decode_static_fields
<F
>(
195 cx
: &mut ExtCtxt
<'_
>,
197 outer_pat_path
: ast
::Path
,
198 fields
: &StaticFields
,
202 F
: FnMut(&mut ExtCtxt
<'_
>, Span
, Symbol
, usize) -> P
<Expr
>,
205 Unnamed(ref fields
, is_tuple
) => {
206 let path_expr
= cx
.expr_path(outer_pat_path
);
213 .map(|(i
, &span
)| getarg(cx
, span
, Symbol
::intern(&format
!("_field{}", i
)), i
))
216 cx
.expr_call(trait_span
, path_expr
, fields
)
219 Named(ref fields
) => {
220 // use the field's span to get nicer error messages.
224 .map(|(i
, &(ident
, span
))| {
225 let arg
= getarg(cx
, span
, ident
.name
, i
);
226 cx
.field_imm(span
, ident
, arg
)
229 cx
.expr_struct(trait_span
, outer_pat_path
, fields
)