]> git.proxmox.com Git - rustc.git/blame - src/libsyntax_ext/deriving/decodable.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / libsyntax_ext / deriving / decodable.rs
CommitLineData
970d7e83
LB
1// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
1a4d82fc 11//! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more.
970d7e83 12
54a0048b 13use deriving;
9cc50fc6
SL
14use deriving::generic::*;
15use deriving::generic::ty::*;
16
17use syntax::ast;
7453a54e 18use syntax::ast::{MetaItem, Expr, Mutability};
9cc50fc6
SL
19use syntax::codemap::Span;
20use syntax::ext::base::{ExtCtxt, Annotatable};
21use syntax::ext::build::AstBuilder;
22use syntax::parse::token::InternedString;
23use syntax::parse::token;
24use syntax::ptr::P;
1a4d82fc 25
d9579d0f
AL
26pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt,
27 span: Span,
28 mitem: &MetaItem,
62682a34 29 item: &Annotatable,
d9579d0f 30 push: &mut FnMut(Annotatable))
1a4d82fc
JJ
31{
32 expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize")
33}
34
d9579d0f
AL
35pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
36 span: Span,
37 mitem: &MetaItem,
62682a34 38 item: &Annotatable,
d9579d0f 39 push: &mut FnMut(Annotatable))
1a4d82fc
JJ
40{
41 expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
42}
970d7e83 43
d9579d0f
AL
44fn expand_deriving_decodable_imp(cx: &mut ExtCtxt,
45 span: Span,
46 mitem: &MetaItem,
62682a34 47 item: &Annotatable,
d9579d0f
AL
48 push: &mut FnMut(Annotatable),
49 krate: &'static str)
1a4d82fc 50{
e9174d1e 51 if cx.crate_root != Some("std") {
85aaf69f 52 // FIXME(#21880): lift this requirement.
e9174d1e
SL
53 cx.span_err(span, "this trait cannot be derived with #![no_std] \
54 or #![no_core]");
55 return
85aaf69f
SL
56 }
57
54a0048b
SL
58 let typaram = &*deriving::hygienic_type_parameter(item, "__D");
59
970d7e83 60 let trait_def = TraitDef {
1a4d82fc
JJ
61 span: span,
62 attributes: Vec::new(),
63 path: Path::new_(vec!(krate, "Decodable"), None, vec!(), true),
64 additional_bounds: Vec::new(),
65 generics: LifetimeBounds::empty(),
e9174d1e 66 is_unsafe: false,
1a4d82fc 67 methods: vec!(
970d7e83
LB
68 MethodDef {
69 name: "decode",
1a4d82fc
JJ
70 generics: LifetimeBounds {
71 lifetimes: Vec::new(),
54a0048b
SL
72 bounds: vec![(typaram,
73 vec![Path::new_(vec!(krate, "Decoder"), None, vec!(), true)])]
1a4d82fc 74 },
970d7e83 75 explicit_self: None,
54a0048b 76 args: vec!(Ptr(Box::new(Literal(Path::new_local(typaram))),
7453a54e 77 Borrowed(None, Mutability::Mutable))),
1a4d82fc 78 ret_ty: Literal(Path::new_(
85aaf69f 79 pathvec_std!(cx, core::result::Result),
1a4d82fc 80 None,
d9579d0f 81 vec!(Box::new(Self_), Box::new(Literal(Path::new_(
54a0048b 82 vec![typaram, "Error"], None, vec![], false
d9579d0f 83 )))),
1a4d82fc
JJ
84 true
85 )),
86 attributes: Vec::new(),
62682a34 87 is_unsafe: false,
c34b1796 88 combine_substructure: combine_substructure(Box::new(|a, b, c| {
1a4d82fc 89 decodable_substructure(a, b, c, krate)
c34b1796 90 })),
85aaf69f
SL
91 }
92 ),
93 associated_types: Vec::new(),
970d7e83
LB
94 };
95
62682a34 96 trait_def.expand(cx, mitem, item, push)
970d7e83
LB
97}
98
1a4d82fc
JJ
99fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
100 substr: &Substructure,
101 krate: &str) -> P<Expr> {
102 let decoder = substr.nonself_args[0].clone();
103 let recurse = vec!(cx.ident_of(krate),
970d7e83 104 cx.ident_of("Decodable"),
1a4d82fc 105 cx.ident_of("decode"));
85aaf69f 106 let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
970d7e83
LB
107 // throw an underscore in front to suppress unused variable warnings
108 let blkarg = cx.ident_of("_d");
1a4d82fc 109 let blkdecoder = cx.expr_ident(trait_span, blkarg);
970d7e83
LB
110
111 return match *substr.fields {
112 StaticStruct(_, ref summary) => {
113 let nfields = match *summary {
1a4d82fc
JJ
114 Unnamed(ref fields) => fields.len(),
115 Named(ref fields) => fields.len()
970d7e83
LB
116 };
117 let read_struct_field = cx.ident_of("read_struct_field");
118
1a4d82fc
JJ
119 let path = cx.path_ident(trait_span, substr.type_ident);
120 let result = decode_static_fields(cx,
121 trait_span,
122 path,
123 summary,
124 |cx, span, name, field| {
125 cx.expr_try(span,
126 cx.expr_method_call(span, blkdecoder.clone(), read_struct_field,
127 vec!(cx.expr_str(span, name),
85aaf69f
SL
128 cx.expr_usize(span, field),
129 exprdecode.clone())))
1a4d82fc
JJ
130 });
131 let result = cx.expr_ok(trait_span, result);
132 cx.expr_method_call(trait_span,
133 decoder,
134 cx.ident_of("read_struct"),
135 vec!(
c1a9b12d 136 cx.expr_str(trait_span, substr.type_ident.name.as_str()),
85aaf69f 137 cx.expr_usize(trait_span, nfields),
1a4d82fc
JJ
138 cx.lambda_expr_1(trait_span, result, blkarg)
139 ))
970d7e83
LB
140 }
141 StaticEnum(_, ref fields) => {
142 let variant = cx.ident_of("i");
143
1a4d82fc
JJ
144 let mut arms = Vec::new();
145 let mut variants = Vec::new();
970d7e83
LB
146 let rvariant_arg = cx.ident_of("read_enum_variant_arg");
147
c1a9b12d
SL
148 for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
149 variants.push(cx.expr_str(v_span, ident.name.as_str()));
1a4d82fc 150
c1a9b12d 151 let path = cx.path(trait_span, vec![substr.type_ident, ident]);
1a4d82fc
JJ
152 let decoded = decode_static_fields(cx,
153 v_span,
154 path,
155 parts,
156 |cx, span, _, field| {
85aaf69f 157 let idx = cx.expr_usize(span, field);
1a4d82fc
JJ
158 cx.expr_try(span,
159 cx.expr_method_call(span, blkdecoder.clone(), rvariant_arg,
85aaf69f 160 vec!(idx, exprdecode.clone())))
1a4d82fc
JJ
161 });
162
163 arms.push(cx.arm(v_span,
85aaf69f 164 vec!(cx.pat_lit(v_span, cx.expr_usize(v_span, i))),
970d7e83
LB
165 decoded));
166 }
167
1a4d82fc 168 arms.push(cx.arm_unreachable(trait_span));
970d7e83 169
1a4d82fc
JJ
170 let result = cx.expr_ok(trait_span,
171 cx.expr_match(trait_span,
172 cx.expr_ident(trait_span, variant), arms));
173 let lambda = cx.lambda_expr(trait_span, vec!(blkarg, variant), result);
174 let variant_vec = cx.expr_vec(trait_span, variants);
175 let variant_vec = cx.expr_addr_of(trait_span, variant_vec);
176 let result = cx.expr_method_call(trait_span, blkdecoder,
970d7e83 177 cx.ident_of("read_enum_variant"),
1a4d82fc
JJ
178 vec!(variant_vec, lambda));
179 cx.expr_method_call(trait_span,
180 decoder,
181 cx.ident_of("read_enum"),
182 vec!(
c1a9b12d 183 cx.expr_str(trait_span, substr.type_ident.name.as_str()),
1a4d82fc
JJ
184 cx.lambda_expr_1(trait_span, result, blkarg)
185 ))
970d7e83 186 }
85aaf69f 187 _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)")
970d7e83
LB
188 };
189}
1a4d82fc
JJ
190
191/// Create a decoder for a single enum variant/struct:
192/// - `outer_pat_path` is the path to this enum variant/struct
85aaf69f 193/// - `getarg` should retrieve the `usize`-th field with name `@str`.
1a4d82fc
JJ
194fn decode_static_fields<F>(cx: &mut ExtCtxt,
195 trait_span: Span,
196 outer_pat_path: ast::Path,
197 fields: &StaticFields,
198 mut getarg: F)
199 -> P<Expr> where
85aaf69f 200 F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P<Expr>,
1a4d82fc
JJ
201{
202 match *fields {
203 Unnamed(ref fields) => {
204 let path_expr = cx.expr_path(outer_pat_path);
205 if fields.is_empty() {
206 path_expr
207 } else {
208 let fields = fields.iter().enumerate().map(|(i, &span)| {
209 getarg(cx, span,
c34b1796 210 token::intern_and_get_ident(&format!("_field{}", i)),
1a4d82fc
JJ
211 i)
212 }).collect();
213
214 cx.expr_call(trait_span, path_expr, fields)
215 }
216 }
217 Named(ref fields) => {
218 // use the field's span to get nicer error messages.
c1a9b12d
SL
219 let fields = fields.iter().enumerate().map(|(i, &(ident, span))| {
220 let arg = getarg(cx, span, ident.name.as_str(), i);
221 cx.field_imm(span, ident, arg)
1a4d82fc
JJ
222 }).collect();
223 cx.expr_struct(trait_span, outer_pat_path, fields)
224 }
225 }
226}