]>
Commit | Line | Data |
---|---|---|
e1599b0c XL |
1 | //! The compiler code necessary to implement the `#[derive(RustcEncodable)]` |
2 | //! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that | |
3 | //! type-defining items may be tagged with | |
4 | //! `#[derive(RustcEncodable, RustcDecodable)]`. | |
1a4d82fc JJ |
5 | //! |
6 | //! For example, a type like: | |
7 | //! | |
04454e1e | 8 | //! ```ignore (old code) |
e1599b0c | 9 | //! #[derive(RustcEncodable, RustcDecodable)] |
85aaf69f | 10 | //! struct Node { id: usize } |
1a4d82fc JJ |
11 | //! ``` |
12 | //! | |
13 | //! would generate two implementations like: | |
14 | //! | |
04454e1e | 15 | //! ```ignore (old code) |
041b39d2 | 16 | //! # struct Node { id: usize } |
1a4d82fc JJ |
17 | //! impl<S: Encoder<E>, E> Encodable<S, E> for Node { |
18 | //! fn encode(&self, s: &mut S) -> Result<(), E> { | |
19 | //! s.emit_struct("Node", 1, |this| { | |
20 | //! this.emit_struct_field("id", 0, |this| { | |
21 | //! Encodable::encode(&self.id, this) | |
85aaf69f | 22 | //! /* this.emit_usize(self.id) can also be used */ |
1a4d82fc JJ |
23 | //! }) |
24 | //! }) | |
25 | //! } | |
26 | //! } | |
27 | //! | |
28 | //! impl<D: Decoder<E>, E> Decodable<D, E> for Node { | |
29 | //! fn decode(d: &mut D) -> Result<Node, E> { | |
30 | //! d.read_struct("Node", 1, |this| { | |
31 | //! match this.read_struct_field("id", 0, |this| Decodable::decode(this)) { | |
32 | //! Ok(id) => Ok(Node { id: id }), | |
33 | //! Err(e) => Err(e), | |
34 | //! } | |
35 | //! }) | |
36 | //! } | |
37 | //! } | |
38 | //! ``` | |
39 | //! | |
40 | //! Other interesting scenarios are when the item has type parameters or | |
9fa01778 | 41 | //! references other non-built-in types. A type definition like: |
1a4d82fc | 42 | //! |
04454e1e | 43 | //! ```ignore (old code) |
e1599b0c XL |
44 | //! # #[derive(RustcEncodable, RustcDecodable)] |
45 | //! # struct Span; | |
46 | //! #[derive(RustcEncodable, RustcDecodable)] | |
1a4d82fc JJ |
47 | //! struct Spanned<T> { node: T, span: Span } |
48 | //! ``` | |
49 | //! | |
50 | //! would yield functions like: | |
51 | //! | |
04454e1e | 52 | //! ```ignore (old code) |
e1599b0c XL |
53 | //! # #[derive(RustcEncodable, RustcDecodable)] |
54 | //! # struct Span; | |
041b39d2 | 55 | //! # struct Spanned<T> { node: T, span: Span } |
1a4d82fc JJ |
56 | //! impl< |
57 | //! S: Encoder<E>, | |
58 | //! E, | |
59 | //! T: Encodable<S, E> | |
60 | //! > Encodable<S, E> for Spanned<T> { | |
61 | //! fn encode(&self, s: &mut S) -> Result<(), E> { | |
62 | //! s.emit_struct("Spanned", 2, |this| { | |
63 | //! this.emit_struct_field("node", 0, |this| self.node.encode(this)) | |
c34b1796 | 64 | //! .unwrap(); |
1a4d82fc JJ |
65 | //! this.emit_struct_field("span", 1, |this| self.span.encode(this)) |
66 | //! }) | |
67 | //! } | |
68 | //! } | |
69 | //! | |
70 | //! impl< | |
71 | //! D: Decoder<E>, | |
72 | //! E, | |
73 | //! T: Decodable<D, E> | |
74 | //! > Decodable<D, E> for Spanned<T> { | |
75 | //! fn decode(d: &mut D) -> Result<Spanned<T>, E> { | |
76 | //! d.read_struct("Spanned", 2, |this| { | |
77 | //! Ok(Spanned { | |
78 | //! node: this.read_struct_field("node", 0, |this| Decodable::decode(this)) | |
c34b1796 | 79 | //! .unwrap(), |
1a4d82fc | 80 | //! span: this.read_struct_field("span", 1, |this| Decodable::decode(this)) |
c34b1796 | 81 | //! .unwrap(), |
1a4d82fc JJ |
82 | //! }) |
83 | //! }) | |
84 | //! } | |
85 | //! } | |
86 | //! ``` | |
970d7e83 | 87 | |
9fa01778 | 88 | use crate::deriving::generic::ty::*; |
dfeec247 XL |
89 | use crate::deriving::generic::*; |
90 | use crate::deriving::pathvec_std; | |
9cc50fc6 | 91 | |
064997fb | 92 | use rustc_ast::{ExprKind, MetaItem, Mutability}; |
dfeec247 | 93 | use rustc_expand::base::{Annotatable, ExtCtxt}; |
3dfed10e | 94 | use rustc_span::symbol::{sym, Ident, Symbol}; |
dfeec247 | 95 | use rustc_span::Span; |
970d7e83 | 96 | |
dfeec247 XL |
97 | pub fn expand_deriving_rustc_encodable( |
98 | cx: &mut ExtCtxt<'_>, | |
99 | span: Span, | |
100 | mitem: &MetaItem, | |
101 | item: &Annotatable, | |
102 | push: &mut dyn FnMut(Annotatable), | |
103 | ) { | |
3dfed10e XL |
104 | let krate = sym::rustc_serialize; |
105 | let typaram = sym::__S; | |
54a0048b | 106 | |
970d7e83 | 107 | let trait_def = TraitDef { |
3b2f2976 | 108 | span, |
1a4d82fc | 109 | attributes: Vec::new(), |
064997fb | 110 | path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), |
1a4d82fc | 111 | additional_bounds: Vec::new(), |
3dfed10e | 112 | generics: Bounds::empty(), |
9e0c209e | 113 | supports_unions: false, |
dfeec247 | 114 | methods: vec![MethodDef { |
3dfed10e XL |
115 | name: sym::encode, |
116 | generics: Bounds { | |
dfeec247 XL |
117 | bounds: vec![( |
118 | typaram, | |
064997fb | 119 | vec![Path::new_(vec![krate, sym::Encoder], vec![], PathKind::Global)], |
dfeec247 XL |
120 | )], |
121 | }, | |
064997fb FG |
122 | explicit_self: true, |
123 | nonself_args: vec![( | |
124 | Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), | |
136023e0 | 125 | sym::s, |
dfeec247 | 126 | )], |
064997fb | 127 | ret_ty: Path(Path::new_( |
3dfed10e | 128 | pathvec_std!(result::Result), |
dfeec247 | 129 | vec![ |
064997fb FG |
130 | Box::new(Unit), |
131 | Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))), | |
dfeec247 XL |
132 | ], |
133 | PathKind::Std, | |
134 | )), | |
135 | attributes: Vec::new(), | |
dfeec247 XL |
136 | unify_fieldless_variants: false, |
137 | combine_substructure: combine_substructure(Box::new(|a, b, c| { | |
138 | encodable_substructure(a, b, c, krate) | |
139 | })), | |
140 | }], | |
85aaf69f | 141 | associated_types: Vec::new(), |
970d7e83 LB |
142 | }; |
143 | ||
62682a34 | 144 | trait_def.expand(cx, mitem, item, push) |
970d7e83 LB |
145 | } |
146 | ||
dfeec247 XL |
147 | fn encodable_substructure( |
148 | cx: &mut ExtCtxt<'_>, | |
149 | trait_span: Span, | |
150 | substr: &Substructure<'_>, | |
3dfed10e | 151 | krate: Symbol, |
064997fb FG |
152 | ) -> BlockOrExpr { |
153 | let encoder = substr.nonselflike_args[0].clone(); | |
970d7e83 | 154 | // throw an underscore in front to suppress unused variable warnings |
3dfed10e | 155 | let blkarg = Ident::new(sym::_e, trait_span); |
1a4d82fc | 156 | let blkencoder = cx.expr_ident(trait_span, blkarg); |
dfeec247 XL |
157 | let fn_path = cx.expr_path(cx.path_global( |
158 | trait_span, | |
159 | vec![ | |
3dfed10e XL |
160 | Ident::new(krate, trait_span), |
161 | Ident::new(sym::Encodable, trait_span), | |
162 | Ident::new(sym::encode, trait_span), | |
dfeec247 XL |
163 | ], |
164 | )); | |
970d7e83 | 165 | |
ba9703b0 | 166 | match *substr.fields { |
7453a54e | 167 | Struct(_, ref fields) => { |
6a06907d XL |
168 | let fn_emit_struct_field_path = |
169 | cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]); | |
1a4d82fc | 170 | let mut stmts = Vec::new(); |
064997fb | 171 | for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() { |
1a4d82fc | 172 | let name = match name { |
476ff2be SL |
173 | Some(id) => id.name, |
174 | None => Symbol::intern(&format!("_field{}", i)), | |
970d7e83 | 175 | }; |
064997fb | 176 | let self_ref = cx.expr_addr_of(span, self_expr.clone()); |
a7813a04 | 177 | let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); |
476ff2be | 178 | let lambda = cx.lambda1(span, enc, blkarg); |
6a06907d | 179 | let call = cx.expr_call_global( |
dfeec247 | 180 | span, |
6a06907d XL |
181 | fn_emit_struct_field_path.clone(), |
182 | vec![ | |
183 | blkencoder.clone(), | |
184 | cx.expr_str(span, name), | |
185 | cx.expr_usize(span, i), | |
186 | lambda, | |
187 | ], | |
dfeec247 | 188 | ); |
1a4d82fc JJ |
189 | |
190 | // last call doesn't need a try! | |
c34b1796 | 191 | let last = fields.len() - 1; |
1a4d82fc JJ |
192 | let call = if i != last { |
193 | cx.expr_try(span, call) | |
194 | } else { | |
7453a54e | 195 | cx.expr(span, ExprKind::Ret(Some(call))) |
1a4d82fc | 196 | }; |
2c00a5a8 | 197 | |
94b46f34 | 198 | let stmt = cx.stmt_expr(call); |
2c00a5a8 | 199 | stmts.push(stmt); |
970d7e83 LB |
200 | } |
201 | ||
1a4d82fc | 202 | // unit structs have no fields and need to return Ok() |
0531ce1d | 203 | let blk = if stmts.is_empty() { |
7453a54e | 204 | let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, vec![])); |
0531ce1d XL |
205 | cx.lambda1(trait_span, ok, blkarg) |
206 | } else { | |
207 | cx.lambda_stmts_1(trait_span, stmts, blkarg) | |
208 | }; | |
1a4d82fc | 209 | |
6a06907d XL |
210 | let fn_emit_struct_path = |
211 | cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]); | |
212 | ||
064997fb | 213 | let expr = cx.expr_call_global( |
dfeec247 | 214 | trait_span, |
6a06907d | 215 | fn_emit_struct_path, |
dfeec247 | 216 | vec![ |
6a06907d | 217 | encoder, |
dfeec247 XL |
218 | cx.expr_str(trait_span, substr.type_ident.name), |
219 | cx.expr_usize(trait_span, fields.len()), | |
220 | blk, | |
221 | ], | |
064997fb FG |
222 | ); |
223 | BlockOrExpr::new_expr(expr) | |
970d7e83 LB |
224 | } |
225 | ||
041b39d2 | 226 | EnumMatching(idx, _, variant, ref fields) => { |
970d7e83 LB |
227 | // We're not generating an AST that the borrow checker is expecting, |
228 | // so we need to generate a unique local variable to take the | |
229 | // mutable loan out on, otherwise we get conflicts which don't | |
230 | // actually exist. | |
1a4d82fc JJ |
231 | let me = cx.stmt_let(trait_span, false, blkarg, encoder); |
232 | let encoder = cx.expr_ident(trait_span, blkarg); | |
6a06907d XL |
233 | |
234 | let fn_emit_enum_variant_arg_path: Vec<_> = | |
235 | cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant_arg]); | |
236 | ||
1a4d82fc | 237 | let mut stmts = Vec::new(); |
9346a6ac | 238 | if !fields.is_empty() { |
c34b1796 | 239 | let last = fields.len() - 1; |
064997fb FG |
240 | for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() { |
241 | let self_ref = cx.expr_addr_of(span, self_expr.clone()); | |
5bcae85e SL |
242 | let enc = |
243 | cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); | |
476ff2be | 244 | let lambda = cx.lambda1(span, enc, blkarg); |
6a06907d XL |
245 | |
246 | let call = cx.expr_call_global( | |
dfeec247 | 247 | span, |
6a06907d XL |
248 | fn_emit_enum_variant_arg_path.clone(), |
249 | vec![blkencoder.clone(), cx.expr_usize(span, i), lambda], | |
dfeec247 | 250 | ); |
c34b1796 AL |
251 | let call = if i != last { |
252 | cx.expr_try(span, call) | |
253 | } else { | |
7453a54e | 254 | cx.expr(span, ExprKind::Ret(Some(call))) |
c34b1796 AL |
255 | }; |
256 | stmts.push(cx.stmt_expr(call)); | |
257 | } | |
258 | } else { | |
7453a54e SL |
259 | let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, vec![])); |
260 | let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok))); | |
1a4d82fc JJ |
261 | stmts.push(cx.stmt_expr(ret_ok)); |
262 | } | |
263 | ||
264 | let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg); | |
e1599b0c | 265 | let name = cx.expr_str(trait_span, variant.ident.name); |
6a06907d XL |
266 | |
267 | let fn_emit_enum_variant_path: Vec<_> = | |
268 | cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant]); | |
269 | ||
270 | let call = cx.expr_call_global( | |
dfeec247 | 271 | trait_span, |
6a06907d | 272 | fn_emit_enum_variant_path, |
dfeec247 | 273 | vec![ |
6a06907d | 274 | blkencoder, |
dfeec247 XL |
275 | name, |
276 | cx.expr_usize(trait_span, idx), | |
277 | cx.expr_usize(trait_span, fields.len()), | |
278 | blk, | |
279 | ], | |
280 | ); | |
6a06907d | 281 | |
476ff2be | 282 | let blk = cx.lambda1(trait_span, call, blkarg); |
6a06907d XL |
283 | let fn_emit_enum_path: Vec<_> = |
284 | cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]); | |
064997fb | 285 | let expr = cx.expr_call_global( |
dfeec247 | 286 | trait_span, |
6a06907d XL |
287 | fn_emit_enum_path, |
288 | vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk], | |
dfeec247 | 289 | ); |
064997fb | 290 | BlockOrExpr::new_mixed(vec![me], Some(expr)) |
970d7e83 LB |
291 | } |
292 | ||
5bcae85e | 293 | _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"), |
ba9703b0 | 294 | } |
970d7e83 | 295 | } |