]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_builtin_macros/src/deriving/encodable.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_builtin_macros / src / deriving / encodable.rs
CommitLineData
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 88use crate::deriving::generic::ty::*;
dfeec247
XL
89use crate::deriving::generic::*;
90use crate::deriving::pathvec_std;
f2b60f7d 91use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability};
dfeec247 92use rustc_expand::base::{Annotatable, ExtCtxt};
3dfed10e 93use rustc_span::symbol::{sym, Ident, Symbol};
dfeec247 94use rustc_span::Span;
9ffffee4 95use thin_vec::{thin_vec, ThinVec};
970d7e83 96
dfeec247
XL
97pub fn expand_deriving_rustc_encodable(
98 cx: &mut ExtCtxt<'_>,
99 span: Span,
100 mitem: &MetaItem,
101 item: &Annotatable,
102 push: &mut dyn FnMut(Annotatable),
487cf647 103 is_const: bool,
dfeec247 104) {
3dfed10e
XL
105 let krate = sym::rustc_serialize;
106 let typaram = sym::__S;
54a0048b 107
970d7e83 108 let trait_def = TraitDef {
3b2f2976 109 span,
064997fb 110 path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
2b03887a 111 skip_path_as_bound: false,
9ffffee4 112 needs_copy_as_bound_if_packed: true,
1a4d82fc 113 additional_bounds: Vec::new(),
9e0c209e 114 supports_unions: false,
dfeec247 115 methods: vec![MethodDef {
3dfed10e
XL
116 name: sym::encode,
117 generics: Bounds {
dfeec247
XL
118 bounds: vec![(
119 typaram,
064997fb 120 vec![Path::new_(vec![krate, sym::Encoder], vec![], PathKind::Global)],
dfeec247
XL
121 )],
122 },
064997fb
FG
123 explicit_self: true,
124 nonself_args: vec![(
125 Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut),
136023e0 126 sym::s,
dfeec247 127 )],
064997fb 128 ret_ty: Path(Path::new_(
3dfed10e 129 pathvec_std!(result::Result),
dfeec247 130 vec![
064997fb
FG
131 Box::new(Unit),
132 Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))),
dfeec247
XL
133 ],
134 PathKind::Std,
135 )),
f2b60f7d 136 attributes: AttrVec::new(),
9c376795 137 fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
dfeec247
XL
138 combine_substructure: combine_substructure(Box::new(|a, b, c| {
139 encodable_substructure(a, b, c, krate)
140 })),
141 }],
85aaf69f 142 associated_types: Vec::new(),
487cf647 143 is_const,
970d7e83
LB
144 };
145
62682a34 146 trait_def.expand(cx, mitem, item, push)
970d7e83
LB
147}
148
dfeec247
XL
149fn encodable_substructure(
150 cx: &mut ExtCtxt<'_>,
151 trait_span: Span,
152 substr: &Substructure<'_>,
3dfed10e 153 krate: Symbol,
064997fb
FG
154) -> BlockOrExpr {
155 let encoder = substr.nonselflike_args[0].clone();
970d7e83 156 // throw an underscore in front to suppress unused variable warnings
3dfed10e 157 let blkarg = Ident::new(sym::_e, trait_span);
1a4d82fc 158 let blkencoder = cx.expr_ident(trait_span, blkarg);
dfeec247
XL
159 let fn_path = cx.expr_path(cx.path_global(
160 trait_span,
161 vec![
3dfed10e
XL
162 Ident::new(krate, trait_span),
163 Ident::new(sym::Encodable, trait_span),
164 Ident::new(sym::encode, trait_span),
dfeec247
XL
165 ],
166 ));
970d7e83 167
487cf647
FG
168 match substr.fields {
169 Struct(_, fields) => {
6a06907d
XL
170 let fn_emit_struct_field_path =
171 cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]);
9ffffee4 172 let mut stmts = ThinVec::new();
064997fb 173 for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() {
1a4d82fc 174 let name = match name {
476ff2be
SL
175 Some(id) => id.name,
176 None => Symbol::intern(&format!("_field{}", i)),
970d7e83 177 };
064997fb 178 let self_ref = cx.expr_addr_of(span, self_expr.clone());
9ffffee4
FG
179 let enc =
180 cx.expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]);
476ff2be 181 let lambda = cx.lambda1(span, enc, blkarg);
6a06907d 182 let call = cx.expr_call_global(
dfeec247 183 span,
6a06907d 184 fn_emit_struct_field_path.clone(),
9ffffee4 185 thin_vec![
6a06907d
XL
186 blkencoder.clone(),
187 cx.expr_str(span, name),
188 cx.expr_usize(span, i),
189 lambda,
190 ],
dfeec247 191 );
1a4d82fc
JJ
192
193 // last call doesn't need a try!
c34b1796 194 let last = fields.len() - 1;
1a4d82fc
JJ
195 let call = if i != last {
196 cx.expr_try(span, call)
197 } else {
7453a54e 198 cx.expr(span, ExprKind::Ret(Some(call)))
1a4d82fc 199 };
2c00a5a8 200
94b46f34 201 let stmt = cx.stmt_expr(call);
2c00a5a8 202 stmts.push(stmt);
970d7e83
LB
203 }
204
1a4d82fc 205 // unit structs have no fields and need to return Ok()
0531ce1d 206 let blk = if stmts.is_empty() {
9ffffee4 207 let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new()));
0531ce1d
XL
208 cx.lambda1(trait_span, ok, blkarg)
209 } else {
210 cx.lambda_stmts_1(trait_span, stmts, blkarg)
211 };
1a4d82fc 212
6a06907d
XL
213 let fn_emit_struct_path =
214 cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]);
215
064997fb 216 let expr = cx.expr_call_global(
dfeec247 217 trait_span,
6a06907d 218 fn_emit_struct_path,
9ffffee4 219 thin_vec![
6a06907d 220 encoder,
dfeec247
XL
221 cx.expr_str(trait_span, substr.type_ident.name),
222 cx.expr_usize(trait_span, fields.len()),
223 blk,
224 ],
064997fb
FG
225 );
226 BlockOrExpr::new_expr(expr)
970d7e83
LB
227 }
228
487cf647 229 EnumMatching(idx, _, variant, fields) => {
970d7e83
LB
230 // We're not generating an AST that the borrow checker is expecting,
231 // so we need to generate a unique local variable to take the
232 // mutable loan out on, otherwise we get conflicts which don't
233 // actually exist.
1a4d82fc
JJ
234 let me = cx.stmt_let(trait_span, false, blkarg, encoder);
235 let encoder = cx.expr_ident(trait_span, blkarg);
6a06907d
XL
236
237 let fn_emit_enum_variant_arg_path: Vec<_> =
238 cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant_arg]);
239
9ffffee4 240 let mut stmts = ThinVec::new();
9346a6ac 241 if !fields.is_empty() {
c34b1796 242 let last = fields.len() - 1;
064997fb
FG
243 for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() {
244 let self_ref = cx.expr_addr_of(span, self_expr.clone());
9ffffee4
FG
245 let enc = cx.expr_call(
246 span,
247 fn_path.clone(),
248 thin_vec![self_ref, blkencoder.clone()],
249 );
476ff2be 250 let lambda = cx.lambda1(span, enc, blkarg);
6a06907d
XL
251
252 let call = cx.expr_call_global(
dfeec247 253 span,
6a06907d 254 fn_emit_enum_variant_arg_path.clone(),
9ffffee4 255 thin_vec![blkencoder.clone(), cx.expr_usize(span, i), lambda],
dfeec247 256 );
c34b1796
AL
257 let call = if i != last {
258 cx.expr_try(span, call)
259 } else {
7453a54e 260 cx.expr(span, ExprKind::Ret(Some(call)))
c34b1796
AL
261 };
262 stmts.push(cx.stmt_expr(call));
263 }
264 } else {
9ffffee4 265 let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new()));
7453a54e 266 let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok)));
1a4d82fc
JJ
267 stmts.push(cx.stmt_expr(ret_ok));
268 }
269
270 let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
e1599b0c 271 let name = cx.expr_str(trait_span, variant.ident.name);
6a06907d
XL
272
273 let fn_emit_enum_variant_path: Vec<_> =
274 cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant]);
275
276 let call = cx.expr_call_global(
dfeec247 277 trait_span,
6a06907d 278 fn_emit_enum_variant_path,
9ffffee4 279 thin_vec![
6a06907d 280 blkencoder,
dfeec247 281 name,
487cf647 282 cx.expr_usize(trait_span, *idx),
dfeec247
XL
283 cx.expr_usize(trait_span, fields.len()),
284 blk,
285 ],
286 );
6a06907d 287
476ff2be 288 let blk = cx.lambda1(trait_span, call, blkarg);
6a06907d
XL
289 let fn_emit_enum_path: Vec<_> =
290 cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]);
064997fb 291 let expr = cx.expr_call_global(
dfeec247 292 trait_span,
6a06907d 293 fn_emit_enum_path,
9ffffee4 294 thin_vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk],
dfeec247 295 );
9ffffee4 296 BlockOrExpr::new_mixed(thin_vec![me], Some(expr))
970d7e83
LB
297 }
298
5bcae85e 299 _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"),
ba9703b0 300 }
970d7e83 301}