]> git.lizzy.rs Git - rust.git/blob - src/rustc/metadata/encoder.rs
Merge remote-tracking branch 'original/incoming' into incoming
[rust.git] / src / rustc / metadata / encoder.rs
1 // Metadata encoding
2
3 use util::ppaux::ty_to_str;
4
5 use std::{ebml, map};
6 use std::map::HashMap;
7 use io::WriterUtil;
8 use ebml::Serializer;
9 use syntax::ast::*;
10 use syntax::print::pprust;
11 use syntax::{ast_util, visit};
12 use syntax::ast_util::*;
13 use common::*;
14 use middle::ty;
15 use middle::ty::node_id_to_type;
16 use middle::resolve;
17 use syntax::ast_map;
18 use syntax::attr;
19 use str::to_bytes;
20 use syntax::ast;
21 use syntax::diagnostic::span_handler;
22
23 use hash::{Hash, HashUtil};
24 use to_bytes::IterBytes;
25
26 export encode_parms;
27 export encode_metadata;
28 export encoded_ty;
29 export reachable;
30 export encode_inlined_item;
31 export metadata_encoding_version;
32
33 // used by astencode:
34 export def_to_str;
35 export encode_ctxt;
36 export write_type;
37 export write_vstore;
38 export encode_def_id;
39
40 type abbrev_map = map::HashMap<ty::t, tyencode::ty_abbrev>;
41
42 type encode_inlined_item = fn@(ecx: @encode_ctxt,
43                                ebml_w: ebml::Serializer,
44                                path: ast_map::path,
45                                ii: ast::inlined_item);
46
47 type encode_parms = {
48     diag: span_handler,
49     tcx: ty::ctxt,
50     reachable: HashMap<ast::node_id, ()>,
51     reexports2: middle::resolve::ExportMap2,
52     item_symbols: HashMap<ast::node_id, ~str>,
53     discrim_symbols: HashMap<ast::node_id, ~str>,
54     link_meta: link_meta,
55     cstore: cstore::CStore,
56     encode_inlined_item: encode_inlined_item
57 };
58
59 type stats = {
60     mut inline_bytes: uint,
61     mut attr_bytes: uint,
62     mut dep_bytes: uint,
63     mut item_bytes: uint,
64     mut index_bytes: uint,
65     mut zero_bytes: uint,
66     mut total_bytes: uint,
67
68     mut n_inlines: uint
69 };
70
71 enum encode_ctxt = {
72     diag: span_handler,
73     tcx: ty::ctxt,
74     stats: stats,
75     reachable: HashMap<ast::node_id, ()>,
76     reexports2: middle::resolve::ExportMap2,
77     item_symbols: HashMap<ast::node_id, ~str>,
78     discrim_symbols: HashMap<ast::node_id, ~str>,
79     link_meta: link_meta,
80     cstore: cstore::CStore,
81     encode_inlined_item: encode_inlined_item,
82     type_abbrevs: abbrev_map
83 };
84
85 fn reachable(ecx: @encode_ctxt, id: node_id) -> bool {
86     ecx.reachable.contains_key(id)
87 }
88
89 fn encode_name(ecx: @encode_ctxt, ebml_w: ebml::Serializer, name: ident) {
90     ebml_w.wr_tagged_str(tag_paths_data_name, ecx.tcx.sess.str_of(name));
91 }
92
93 fn encode_impl_type_basename(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
94                              name: ident) {
95     ebml_w.wr_tagged_str(tag_item_impl_type_basename,
96                          ecx.tcx.sess.str_of(name));
97 }
98
99 fn encode_def_id(ebml_w: ebml::Serializer, id: def_id) {
100     ebml_w.wr_tagged_str(tag_def_id, def_to_str(id));
101 }
102
103 fn encode_region_param(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
104                        it: @ast::item) {
105     let opt_rp = ecx.tcx.region_paramd_items.find(it.id);
106     for opt_rp.each |rp| {
107         do ebml_w.wr_tag(tag_region_param) {
108             (*rp).serialize(&ebml_w);
109         }
110     }
111 }
112
113 fn encode_mutability(ebml_w: ebml::Serializer, mt: class_mutability) {
114     do ebml_w.wr_tag(tag_class_mut) {
115         let val = match mt {
116           class_immutable => 'a',
117           class_mutable => 'm'
118         };
119         ebml_w.writer.write(&[val as u8]);
120     }
121 }
122
123 type entry<T> = {val: T, pos: uint};
124
125 fn add_to_index(ecx: @encode_ctxt, ebml_w: ebml::Serializer, path: &[ident],
126                 index: &mut ~[entry<~str>], name: ident) {
127     let mut full_path = ~[];
128     full_path.push_all(path);
129     full_path.push(name);
130     index.push(
131         {val: ast_util::path_name_i(full_path,
132                                     ecx.tcx.sess.parse_sess.interner),
133          pos: ebml_w.writer.tell()});
134 }
135
136 fn encode_trait_ref(ebml_w: ebml::Serializer, ecx: @encode_ctxt,
137                     t: @trait_ref) {
138     ebml_w.start_tag(tag_impl_trait);
139     encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, t.ref_id));
140     ebml_w.end_tag();
141 }
142
143
144 // Item info table encoding
145 fn encode_family(ebml_w: ebml::Serializer, c: char) {
146     ebml_w.start_tag(tag_items_data_item_family);
147     ebml_w.writer.write(&[c as u8]);
148     ebml_w.end_tag();
149 }
150
151 fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) }
152
153 fn encode_ty_type_param_bounds(ebml_w: ebml::Serializer, ecx: @encode_ctxt,
154                                params: @~[ty::param_bounds]) {
155     let ty_str_ctxt = @{diag: ecx.diag,
156                         ds: def_to_str,
157                         tcx: ecx.tcx,
158                         reachable: |a| reachable(ecx, a),
159                         abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
160     for params.each |param| {
161         ebml_w.start_tag(tag_items_data_item_ty_param_bounds);
162         tyencode::enc_bounds(ebml_w.writer, ty_str_ctxt, *param);
163         ebml_w.end_tag();
164     }
165 }
166
167 fn encode_type_param_bounds(ebml_w: ebml::Serializer, ecx: @encode_ctxt,
168                             params: ~[ty_param]) {
169     let ty_param_bounds =
170         @params.map(|param| ecx.tcx.ty_param_bounds.get(param.id));
171     encode_ty_type_param_bounds(ebml_w, ecx, ty_param_bounds);
172 }
173
174
175 fn encode_variant_id(ebml_w: ebml::Serializer, vid: def_id) {
176     ebml_w.start_tag(tag_items_data_item_variant);
177     ebml_w.writer.write(str::to_bytes(def_to_str(vid)));
178     ebml_w.end_tag();
179 }
180
181 fn write_type(ecx: @encode_ctxt, ebml_w: ebml::Serializer, typ: ty::t) {
182     let ty_str_ctxt =
183         @{diag: ecx.diag,
184           ds: def_to_str,
185           tcx: ecx.tcx,
186           reachable: |a| reachable(ecx, a),
187           abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
188     tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ);
189 }
190
191 fn write_vstore(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
192                 vstore: ty::vstore) {
193     let ty_str_ctxt =
194         @{diag: ecx.diag,
195           ds: def_to_str,
196           tcx: ecx.tcx,
197           reachable: |a| reachable(ecx, a),
198           abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
199     tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore);
200 }
201
202 fn encode_type(ecx: @encode_ctxt, ebml_w: ebml::Serializer, typ: ty::t) {
203     ebml_w.start_tag(tag_items_data_item_type);
204     write_type(ecx, ebml_w, typ);
205     ebml_w.end_tag();
206 }
207
208 fn encode_symbol(ecx: @encode_ctxt, ebml_w: ebml::Serializer, id: node_id) {
209     ebml_w.start_tag(tag_items_data_item_symbol);
210     let sym = match ecx.item_symbols.find(id) {
211       Some(x) => x,
212       None => {
213         ecx.diag.handler().bug(
214             fmt!("encode_symbol: id not found %d", id));
215       }
216     };
217     ebml_w.writer.write(str::to_bytes(sym));
218     ebml_w.end_tag();
219 }
220
221 fn encode_discriminant(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
222                        id: node_id) {
223     ebml_w.start_tag(tag_items_data_item_symbol);
224     ebml_w.writer.write(str::to_bytes(ecx.discrim_symbols.get(id)));
225     ebml_w.end_tag();
226 }
227
228 fn encode_disr_val(_ecx: @encode_ctxt, ebml_w: ebml::Serializer,
229                    disr_val: int) {
230     ebml_w.start_tag(tag_disr_val);
231     ebml_w.writer.write(str::to_bytes(int::to_str(disr_val,10u)));
232     ebml_w.end_tag();
233 }
234
235 fn encode_parent_item(ebml_w: ebml::Serializer, id: def_id) {
236     ebml_w.start_tag(tag_items_data_parent_item);
237     ebml_w.writer.write(str::to_bytes(def_to_str(id)));
238     ebml_w.end_tag();
239 }
240
241 fn encode_enum_variant_info(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
242                             id: node_id, variants: ~[variant],
243                             path: ast_map::path, index: @mut ~[entry<int>],
244                             ty_params: ~[ty_param]) {
245     let mut disr_val = 0;
246     let mut i = 0;
247     let vi = ty::enum_variants(ecx.tcx, {crate: local_crate, node: id});
248     for variants.each |variant| {
249         index.push({val: variant.node.id, pos: ebml_w.writer.tell()});
250         ebml_w.start_tag(tag_items_data_item);
251         encode_def_id(ebml_w, local_def(variant.node.id));
252         encode_family(ebml_w, 'v');
253         encode_name(ecx, ebml_w, variant.node.name);
254         encode_parent_item(ebml_w, local_def(id));
255         encode_type(ecx, ebml_w,
256                     node_id_to_type(ecx.tcx, variant.node.id));
257         match variant.node.kind {
258             ast::tuple_variant_kind(args)
259                     if args.len() > 0 && ty_params.len() == 0 => {
260                 encode_symbol(ecx, ebml_w, variant.node.id);
261             }
262             ast::tuple_variant_kind(_) | ast::struct_variant_kind(_) |
263             ast::enum_variant_kind(_) => {}
264         }
265         encode_discriminant(ecx, ebml_w, variant.node.id);
266         if vi[i].disr_val != disr_val {
267             encode_disr_val(ecx, ebml_w, vi[i].disr_val);
268             disr_val = vi[i].disr_val;
269         }
270         encode_type_param_bounds(ebml_w, ecx, ty_params);
271         encode_path(ecx, ebml_w, path, ast_map::path_name(variant.node.name));
272         ebml_w.end_tag();
273         disr_val += 1;
274         i += 1;
275     }
276 }
277
278 fn encode_path(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
279                path: ast_map::path, name: ast_map::path_elt) {
280     fn encode_path_elt(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
281                        elt: ast_map::path_elt) {
282         let (tag, name) = match elt {
283           ast_map::path_mod(name) => (tag_path_elt_mod, name),
284           ast_map::path_name(name) => (tag_path_elt_name, name)
285         };
286
287         ebml_w.wr_tagged_str(tag, ecx.tcx.sess.str_of(name));
288     }
289
290     do ebml_w.wr_tag(tag_path) {
291         ebml_w.wr_tagged_u32(tag_path_len, (vec::len(path) + 1u) as u32);
292         for vec::each(path) |pe| {
293             encode_path_elt(ecx, ebml_w, *pe);
294         }
295         encode_path_elt(ecx, ebml_w, name);
296     }
297 }
298
299 fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: ebml::Serializer, md: _mod,
300                        id: node_id, path: ast_map::path, name: ident) {
301     ebml_w.start_tag(tag_items_data_item);
302     encode_def_id(ebml_w, local_def(id));
303     encode_family(ebml_w, 'm');
304     encode_name(ecx, ebml_w, name);
305     debug!("(encoding info for module) encoding info for module ID %d", id);
306
307     // Encode info about all the module children.
308     for md.items.each |item| {
309         match item.node {
310             item_impl(*) | item_class(*) => {
311                 let (ident, did) = (item.ident, item.id);
312                 debug!("(encoding info for module) ... encoding impl %s \
313                         (%?/%?), exported? %?",
314                         ecx.tcx.sess.str_of(ident),
315                         did,
316                         ast_map::node_id_to_str(ecx.tcx.items, did, ecx.tcx
317                                                 .sess.parse_sess.interner),
318                         ast_util::is_exported(ident, md));
319
320                 ebml_w.start_tag(tag_mod_impl);
321                 ebml_w.wr_str(def_to_str(local_def(did)));
322                 ebml_w.end_tag();
323             }
324             _ => {} // XXX: Encode these too.
325         }
326     }
327
328     encode_path(ecx, ebml_w, path, ast_map::path_mod(name));
329
330     // Encode the reexports of this module.
331     debug!("(encoding info for module) encoding reexports for %d", id);
332     match ecx.reexports2.find(id) {
333         Some(exports) => {
334             debug!("(encoding info for module) found reexports for %d", id);
335             for exports.each |exp| {
336                 debug!("(encoding info for module) reexport '%s' for %d",
337                        exp.name, id);
338                 ebml_w.start_tag(tag_items_data_item_reexport);
339                 ebml_w.start_tag(tag_items_data_item_reexport_def_id);
340                 ebml_w.wr_str(def_to_str(exp.def_id));
341                 ebml_w.end_tag();
342                 ebml_w.start_tag(tag_items_data_item_reexport_name);
343                 ebml_w.wr_str(exp.name);
344                 ebml_w.end_tag();
345                 ebml_w.end_tag();
346             }
347         }
348         None => {
349             debug!("(encoding info for module) found no reexports for %d",
350                    id);
351         }
352     }
353
354     ebml_w.end_tag();
355 }
356
357 fn encode_visibility(ebml_w: ebml::Serializer, visibility: visibility) {
358     encode_family(ebml_w, match visibility {
359         public => 'g',
360         private => 'j',
361         inherited => 'N'
362     });
363 }
364
365 fn encode_self_type(ebml_w: ebml::Serializer, self_type: ast::self_ty_) {
366     ebml_w.start_tag(tag_item_trait_method_self_ty);
367
368     // Encode the base self type.
369     let ch;
370     match self_type {
371         sty_static =>       { ch = 's' as u8; }
372         sty_by_ref =>       { ch = 'r' as u8; }
373         sty_value =>        { ch = 'v' as u8; }
374         sty_region(_) =>    { ch = '&' as u8; }
375         sty_box(_) =>       { ch = '@' as u8; }
376         sty_uniq(_) =>      { ch = '~' as u8; }
377     }
378     ebml_w.writer.write(&[ ch ]);
379
380     // Encode mutability.
381     match self_type {
382         sty_static | sty_by_ref | sty_value => { /* No-op. */ }
383         sty_region(m_imm) | sty_box(m_imm) | sty_uniq(m_imm) => {
384             ebml_w.writer.write(&[ 'i' as u8 ]);
385         }
386         sty_region(m_mutbl) | sty_box(m_mutbl) | sty_uniq(m_mutbl) => {
387             ebml_w.writer.write(&[ 'm' as u8 ]);
388         }
389         sty_region(m_const) | sty_box(m_const) | sty_uniq(m_const) => {
390             ebml_w.writer.write(&[ 'c' as u8 ]);
391         }
392     }
393
394     ebml_w.end_tag();
395 }
396
397 fn encode_method_sort(ebml_w: ebml::Serializer, sort: char) {
398     ebml_w.start_tag(tag_item_trait_method_sort);
399     ebml_w.writer.write(&[ sort as u8 ]);
400     ebml_w.end_tag();
401 }
402
403 /* Returns an index of items in this class */
404 fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
405                          id: node_id, path: ast_map::path,
406                          class_tps: ~[ty_param],
407                          fields: ~[@struct_field],
408                          methods: ~[@method],
409                          global_index: @mut~[entry<int>]) -> ~[entry<int>] {
410     /* Each class has its own index, since different classes
411        may have fields with the same name */
412     let index = @mut ~[];
413     let tcx = ecx.tcx;
414      /* We encode both private and public fields -- need to include
415         private fields to get the offsets right */
416     for fields.each |field| {
417         match field.node.kind {
418             named_field(nm, mt, vis) => {
419                 let id = field.node.id;
420                 index.push({val: id, pos: ebml_w.writer.tell()});
421                 global_index.push({val: id,
422                                     pos: ebml_w.writer.tell()});
423                 ebml_w.start_tag(tag_items_data_item);
424                 debug!("encode_info_for_class: doing %s %d",
425                        tcx.sess.str_of(nm), id);
426                 encode_visibility(ebml_w, vis);
427                 encode_name(ecx, ebml_w, nm);
428                 encode_path(ecx, ebml_w, path, ast_map::path_name(nm));
429                 encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
430                 encode_mutability(ebml_w, mt);
431                 encode_def_id(ebml_w, local_def(id));
432                 ebml_w.end_tag();
433             }
434             unnamed_field => {}
435         }
436     }
437
438     for methods.each |m| {
439         match m.vis {
440             public | inherited => {
441                 index.push({val: m.id, pos: ebml_w.writer.tell()});
442                 global_index.push(
443                     {val: m.id, pos: ebml_w.writer.tell()});
444                 let impl_path = vec::append_one(path,
445                                                 ast_map::path_name(m.ident));
446                 debug!("encode_info_for_class: doing %s %d",
447                        ecx.tcx.sess.str_of(m.ident), m.id);
448                 encode_info_for_method(ecx, ebml_w, impl_path,
449                                        should_inline(m.attrs), id, *m,
450                                        vec::append(class_tps, m.tps));
451             }
452             _ => { /* don't encode private methods */ }
453         }
454     }
455
456     *index
457 }
458
459 // This is for encoding info for ctors and dtors
460 fn encode_info_for_ctor(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
461                         id: node_id, ident: ident, path: ast_map::path,
462                         item: Option<inlined_item>, tps: ~[ty_param]) {
463         ebml_w.start_tag(tag_items_data_item);
464         encode_name(ecx, ebml_w, ident);
465         encode_def_id(ebml_w, local_def(id));
466         encode_family(ebml_w, purity_fn_family(ast::impure_fn));
467         encode_type_param_bounds(ebml_w, ecx, tps);
468         let its_ty = node_id_to_type(ecx.tcx, id);
469         debug!("fn name = %s ty = %s its node id = %d",
470                ecx.tcx.sess.str_of(ident),
471                util::ppaux::ty_to_str(ecx.tcx, its_ty), id);
472         encode_type(ecx, ebml_w, its_ty);
473         encode_path(ecx, ebml_w, path, ast_map::path_name(ident));
474         match item {
475            Some(it) => {
476              ecx.encode_inlined_item(ecx, ebml_w, path, it);
477            }
478            None => {
479              encode_symbol(ecx, ebml_w, id);
480            }
481         }
482         ebml_w.end_tag();
483 }
484
485 fn encode_info_for_method(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
486                           impl_path: ast_map::path, should_inline: bool,
487                           parent_id: node_id,
488                           m: @method, all_tps: ~[ty_param]) {
489     debug!("encode_info_for_method: %d %s %u", m.id,
490            ecx.tcx.sess.str_of(m.ident), all_tps.len());
491     ebml_w.start_tag(tag_items_data_item);
492     encode_def_id(ebml_w, local_def(m.id));
493     match m.self_ty.node {
494         ast::sty_static => {
495             encode_family(ebml_w, purity_static_method_family(m.purity));
496         }
497         _ => encode_family(ebml_w, purity_fn_family(m.purity))
498     }
499     encode_type_param_bounds(ebml_w, ecx, all_tps);
500     encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id));
501     encode_name(ecx, ebml_w, m.ident);
502     encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident));
503     encode_self_type(ebml_w, m.self_ty.node);
504     if all_tps.len() > 0u || should_inline {
505         ecx.encode_inlined_item(
506            ecx, ebml_w, impl_path,
507            ii_method(local_def(parent_id), m));
508     } else {
509         encode_symbol(ecx, ebml_w, m.id);
510     }
511     ebml_w.end_tag();
512 }
513
514 fn purity_fn_family(p: purity) -> char {
515     match p {
516       unsafe_fn => 'u',
517       pure_fn => 'p',
518       impure_fn => 'f',
519       extern_fn => 'e'
520     }
521 }
522 fn purity_static_method_family(p: purity) -> char {
523     match p {
524       unsafe_fn => 'U',
525       pure_fn => 'P',
526       impure_fn => 'F',
527       _ => fail ~"extern fn can't be static"
528     }
529 }
530
531
532 fn should_inline(attrs: ~[attribute]) -> bool {
533     match attr::find_inline_attr(attrs) {
534         attr::ia_none | attr::ia_never  => false,
535         attr::ia_hint | attr::ia_always => true
536     }
537 }
538
539
540 fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
541                         item: @item, index: @mut ~[entry<int>],
542                         path: ast_map::path) {
543
544     let tcx = ecx.tcx;
545     let must_write =
546         match item.node {
547           item_enum(_, _) | item_impl(*)
548           | item_trait(*) | item_class(*) => true,
549           _ => false
550         };
551     if !must_write && !reachable(ecx, item.id) { return; }
552
553     fn add_to_index_(item: @item, ebml_w: ebml::Serializer,
554                      index: @mut ~[entry<int>]) {
555         index.push({val: item.id, pos: ebml_w.writer.tell()});
556     }
557     let add_to_index = |copy ebml_w| add_to_index_(item, ebml_w, index);
558
559     match item.node {
560       item_const(_, _) => {
561         add_to_index();
562         ebml_w.start_tag(tag_items_data_item);
563         encode_def_id(ebml_w, local_def(item.id));
564         encode_family(ebml_w, 'c');
565         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
566         encode_symbol(ecx, ebml_w, item.id);
567         encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
568         ebml_w.end_tag();
569       }
570       item_fn(_, purity, tps, _) => {
571         add_to_index();
572         ebml_w.start_tag(tag_items_data_item);
573         encode_def_id(ebml_w, local_def(item.id));
574         encode_family(ebml_w, purity_fn_family(purity));
575         encode_type_param_bounds(ebml_w, ecx, tps);
576         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
577         encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
578         encode_attributes(ebml_w, item.attrs);
579         if tps.len() > 0u || should_inline(item.attrs) {
580             ecx.encode_inlined_item(ecx, ebml_w, path, ii_item(item));
581         } else {
582             encode_symbol(ecx, ebml_w, item.id);
583         }
584         ebml_w.end_tag();
585       }
586       item_mod(m) => {
587         add_to_index();
588         encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident);
589       }
590       item_foreign_mod(_) => {
591         add_to_index();
592         ebml_w.start_tag(tag_items_data_item);
593         encode_def_id(ebml_w, local_def(item.id));
594         encode_family(ebml_w, 'n');
595         encode_name(ecx, ebml_w, item.ident);
596         encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
597         ebml_w.end_tag();
598       }
599       item_ty(_, tps) => {
600         add_to_index();
601         ebml_w.start_tag(tag_items_data_item);
602         encode_def_id(ebml_w, local_def(item.id));
603         encode_family(ebml_w, 'y');
604         encode_type_param_bounds(ebml_w, ecx, tps);
605         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
606         encode_name(ecx, ebml_w, item.ident);
607         encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
608         encode_region_param(ecx, ebml_w, item);
609         ebml_w.end_tag();
610       }
611       item_enum(enum_definition, tps) => {
612         add_to_index();
613         do ebml_w.wr_tag(tag_items_data_item) {
614             encode_def_id(ebml_w, local_def(item.id));
615             encode_family(ebml_w, 't');
616             encode_type_param_bounds(ebml_w, ecx, tps);
617             encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
618             encode_name(ecx, ebml_w, item.ident);
619             for enum_definition.variants.each |v| {
620                 encode_variant_id(ebml_w, local_def(v.node.id));
621             }
622             ecx.encode_inlined_item(ecx, ebml_w, path, ii_item(item));
623             encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
624             encode_region_param(ecx, ebml_w, item);
625         }
626         encode_enum_variant_info(ecx, ebml_w, item.id,
627                                  enum_definition.variants, path, index, tps);
628       }
629       item_class(struct_def, tps) => {
630         /* First, encode the fields and methods
631            These come first because we need to write them to make
632            the index, and the index needs to be in the item for the
633            class itself */
634         let idx = encode_info_for_class(ecx, ebml_w, item.id, path, tps,
635                                         struct_def.fields, struct_def.methods,
636                                         index);
637         /* Encode the dtor */
638         do struct_def.dtor.iter |dtor| {
639             index.push({val: dtor.node.id, pos: ebml_w.writer.tell()});
640           encode_info_for_ctor(ecx, ebml_w, dtor.node.id,
641                                ecx.tcx.sess.ident_of(
642                                    ecx.tcx.sess.str_of(item.ident) +
643                                    ~"_dtor"),
644                                path, if tps.len() > 0u {
645                                    Some(ii_dtor(*dtor, item.ident, tps,
646                                                 local_def(item.id))) }
647                                else { None }, tps);
648         }
649
650         /* Index the class*/
651         add_to_index();
652         /* Now, make an item for the class itself */
653         ebml_w.start_tag(tag_items_data_item);
654         encode_def_id(ebml_w, local_def(item.id));
655         encode_family(ebml_w, 'S');
656         encode_type_param_bounds(ebml_w, ecx, tps);
657         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
658         encode_name(ecx, ebml_w, item.ident);
659         encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
660         encode_region_param(ecx, ebml_w, item);
661         for struct_def.traits.each |t| {
662            encode_trait_ref(ebml_w, ecx, *t);
663         }
664         /* Encode the dtor */
665         /* Encode id for dtor */
666         do struct_def.dtor.iter |dtor| {
667             do ebml_w.wr_tag(tag_item_dtor) {
668                 encode_def_id(ebml_w, local_def(dtor.node.id));
669             }
670         };
671
672         /* Encode def_ids for each field and method
673          for methods, write all the stuff get_trait_method
674         needs to know*/
675         for struct_def.fields.each |f| {
676             match f.node.kind {
677                 named_field(ident, _, vis) => {
678                    ebml_w.start_tag(tag_item_field);
679                    encode_visibility(ebml_w, vis);
680                    encode_name(ecx, ebml_w, ident);
681                    encode_def_id(ebml_w, local_def(f.node.id));
682                    ebml_w.end_tag();
683                 }
684                 unnamed_field => {}
685             }
686         }
687
688         for struct_def.methods.each |m| {
689            match m.vis {
690               private => { /* do nothing */ }
691               public | inherited => {
692                 /* Write the info that's needed when viewing this class
693                    as a trait */
694                 ebml_w.start_tag(tag_item_trait_method);
695                 encode_family(ebml_w, purity_fn_family(m.purity));
696                 encode_name(ecx, ebml_w, m.ident);
697                 encode_type_param_bounds(ebml_w, ecx, m.tps);
698                 encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id));
699                 encode_def_id(ebml_w, local_def(m.id));
700                 encode_self_type(ebml_w, m.self_ty.node);
701                 ebml_w.end_tag();
702                 /* Write the info that's needed when viewing this class
703                    as an impl (just the method def_id and self type) */
704                 ebml_w.start_tag(tag_item_impl_method);
705                 ebml_w.writer.write(to_bytes(def_to_str(local_def(m.id))));
706                 ebml_w.end_tag();
707               }
708            }
709         }
710         /* Each class has its own index -- encode it */
711         let bkts = create_index(idx);
712         encode_index(ebml_w, bkts, write_int);
713         ebml_w.end_tag();
714       }
715       item_impl(tps, opt_trait, ty, methods) => {
716         add_to_index();
717         ebml_w.start_tag(tag_items_data_item);
718         encode_def_id(ebml_w, local_def(item.id));
719         encode_family(ebml_w, 'i');
720         encode_region_param(ecx, ebml_w, item);
721         encode_type_param_bounds(ebml_w, ecx, tps);
722         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
723         encode_name(ecx, ebml_w, item.ident);
724         encode_attributes(ebml_w, item.attrs);
725         match ty.node {
726             ast::ty_path(path, _) if path.idents.len() == 1 => {
727                 encode_impl_type_basename(ecx, ebml_w,
728                                           ast_util::path_to_ident(path));
729             }
730             _ => {}
731         }
732         for methods.each |m| {
733             ebml_w.start_tag(tag_item_impl_method);
734             ebml_w.writer.write(str::to_bytes(def_to_str(local_def(m.id))));
735             ebml_w.end_tag();
736         }
737         do opt_trait.iter() |associated_trait| {
738            encode_trait_ref(ebml_w, ecx, *associated_trait)
739         }
740         encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
741         ebml_w.end_tag();
742
743         let impl_path = vec::append_one(path,
744                                         ast_map::path_name(item.ident));
745         for methods.each |m| {
746             index.push({val: m.id, pos: ebml_w.writer.tell()});
747             encode_info_for_method(ecx, ebml_w, impl_path,
748                                    should_inline(m.attrs), item.id, *m,
749                                    vec::append(tps, m.tps));
750         }
751       }
752       item_trait(tps, traits, ms) => {
753         let provided_methods = dvec::DVec();
754
755         add_to_index();
756         ebml_w.start_tag(tag_items_data_item);
757         encode_def_id(ebml_w, local_def(item.id));
758         encode_family(ebml_w, 'I');
759         encode_region_param(ecx, ebml_w, item);
760         encode_type_param_bounds(ebml_w, ecx, tps);
761         encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
762         encode_name(ecx, ebml_w, item.ident);
763         encode_attributes(ebml_w, item.attrs);
764         let mut i = 0u;
765         for vec::each(*ty::trait_methods(tcx, local_def(item.id))) |mty| {
766             match ms[i] {
767               required(ty_m) => {
768                 ebml_w.start_tag(tag_item_trait_method);
769                 encode_def_id(ebml_w, local_def(ty_m.id));
770                 encode_name(ecx, ebml_w, mty.ident);
771                 encode_type_param_bounds(ebml_w, ecx, ty_m.tps);
772                 encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty));
773                 encode_family(ebml_w, purity_fn_family(mty.fty.meta.purity));
774                 encode_self_type(ebml_w, mty.self_ty);
775                 encode_method_sort(ebml_w, 'r');
776                 ebml_w.end_tag();
777               }
778               provided(m) => {
779                 provided_methods.push(m);
780
781                 ebml_w.start_tag(tag_item_trait_method);
782                 encode_def_id(ebml_w, local_def(m.id));
783                 encode_name(ecx, ebml_w, mty.ident);
784                 encode_type_param_bounds(ebml_w, ecx, m.tps);
785                 encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty));
786                 encode_family(ebml_w, purity_fn_family(mty.fty.meta.purity));
787                 encode_self_type(ebml_w, mty.self_ty);
788                 encode_method_sort(ebml_w, 'p');
789                 ebml_w.end_tag();
790               }
791             }
792             i += 1u;
793         }
794         encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
795         for traits.each |associated_trait| {
796            encode_trait_ref(ebml_w, ecx, *associated_trait)
797         }
798         ebml_w.end_tag();
799
800         // Now, output all of the static methods as items.  Note that for the
801         // method info, we output static methods with type signatures as
802         // written. Here, we output the *real* type signatures. I feel like
803         // maybe we should only ever handle the real type signatures.
804         for vec::each(ms) |m| {
805             let ty_m = ast_util::trait_method_to_ty_method(*m);
806             if ty_m.self_ty.node != ast::sty_static { loop; }
807
808             index.push({val: ty_m.id, pos: ebml_w.writer.tell()});
809
810             ebml_w.start_tag(tag_items_data_item);
811             encode_def_id(ebml_w, local_def(ty_m.id));
812             encode_parent_item(ebml_w, local_def(item.id));
813             encode_name(ecx, ebml_w, ty_m.ident);
814             encode_family(ebml_w,
815                           purity_static_method_family(ty_m.purity));
816             let polyty = ecx.tcx.tcache.get(local_def(ty_m.id));
817             encode_ty_type_param_bounds(ebml_w, ecx, polyty.bounds);
818             encode_type(ecx, ebml_w, polyty.ty);
819             encode_path(ecx, ebml_w, path, ast_map::path_name(ty_m.ident));
820             ebml_w.end_tag();
821         }
822
823         // Finally, output all the provided methods as items.
824         for provided_methods.each |m| {
825             index.push({val: m.id, pos: ebml_w.writer.tell()});
826             encode_info_for_method(ecx, ebml_w, path, true, item.id, *m,
827                                    m.tps);
828         }
829       }
830       item_mac(*) => fail ~"item macros unimplemented"
831     }
832 }
833
834 fn encode_info_for_foreign_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
835                                 nitem: @foreign_item,
836                                 index: @mut ~[entry<int>],
837                                 path: ast_map::path, abi: foreign_abi) {
838     if !reachable(ecx, nitem.id) { return; }
839     index.push({val: nitem.id, pos: ebml_w.writer.tell()});
840
841     ebml_w.start_tag(tag_items_data_item);
842     match nitem.node {
843       foreign_item_fn(_, purity, tps) => {
844         encode_def_id(ebml_w, local_def(nitem.id));
845         encode_family(ebml_w, purity_fn_family(purity));
846         encode_type_param_bounds(ebml_w, ecx, tps);
847         encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
848         if abi == foreign_abi_rust_intrinsic {
849             ecx.encode_inlined_item(ecx, ebml_w, path,
850                                     ii_foreign(nitem));
851         } else {
852             encode_symbol(ecx, ebml_w, nitem.id);
853         }
854         encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident));
855       }
856       foreign_item_const(*) => {
857         encode_def_id(ebml_w, local_def(nitem.id));
858         encode_family(ebml_w, 'c');
859         encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
860         encode_symbol(ecx, ebml_w, nitem.id);
861         encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident));
862       }
863     }
864     ebml_w.end_tag();
865 }
866
867 fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
868                          crate: @crate) -> ~[entry<int>] {
869     let index = @mut ~[];
870     ebml_w.start_tag(tag_items_data);
871     index.push({val: crate_node_id, pos: ebml_w.writer.tell()});
872     encode_info_for_mod(ecx, ebml_w, crate.node.module,
873                         crate_node_id, ~[],
874                         syntax::parse::token::special_idents::invalid);
875     visit::visit_crate(*crate, (), visit::mk_vt(@{
876         visit_expr: |_e, _cx, _v| { },
877         visit_item: |i, cx, v, copy ebml_w| {
878             visit::visit_item(i, cx, v);
879             match ecx.tcx.items.get(i.id) {
880               ast_map::node_item(_, pt) => {
881                 encode_info_for_item(ecx, ebml_w, i, index, *pt);
882               }
883               _ => fail ~"bad item"
884             }
885         },
886         visit_foreign_item: |ni, cx, v, copy ebml_w| {
887             visit::visit_foreign_item(ni, cx, v);
888             match ecx.tcx.items.get(ni.id) {
889               ast_map::node_foreign_item(_, abi, pt) => {
890                 encode_info_for_foreign_item(ecx, ebml_w, ni,
891                                              index, *pt, abi);
892               }
893               // case for separate item and foreign-item tables
894               _ => fail ~"bad foreign item"
895             }
896         }
897         ,.. *visit::default_visitor()
898     }));
899     ebml_w.end_tag();
900     return *index;
901 }
902
903
904 // Path and definition ID indexing
905
906 fn create_index<T: Copy Hash IterBytes>(index: ~[entry<T>]) ->
907    ~[@~[entry<T>]] {
908     let mut buckets: ~[@mut ~[entry<T>]] = ~[];
909     for uint::range(0u, 256u) |_i| { buckets.push(@mut ~[]); };
910     for index.each |elt| {
911         let h = elt.val.hash() as uint;
912         buckets[h % 256].push(*elt);
913     }
914
915     let mut buckets_frozen = ~[];
916     for buckets.each |bucket| {
917         buckets_frozen.push(@**bucket);
918     }
919     return buckets_frozen;
920 }
921
922 fn encode_index<T>(ebml_w: ebml::Serializer, buckets: ~[@~[entry<T>]],
923                    write_fn: fn(io::Writer, T)) {
924     let writer = ebml_w.writer;
925     ebml_w.start_tag(tag_index);
926     let mut bucket_locs: ~[uint] = ~[];
927     ebml_w.start_tag(tag_index_buckets);
928     for buckets.each |bucket| {
929         bucket_locs.push(ebml_w.writer.tell());
930         ebml_w.start_tag(tag_index_buckets_bucket);
931         for vec::each(**bucket) |elt| {
932             ebml_w.start_tag(tag_index_buckets_bucket_elt);
933             assert elt.pos < 0xffff_ffff;
934             writer.write_be_u32(elt.pos as u32);
935             write_fn(writer, elt.val);
936             ebml_w.end_tag();
937         }
938         ebml_w.end_tag();
939     }
940     ebml_w.end_tag();
941     ebml_w.start_tag(tag_index_table);
942     for bucket_locs.each |pos| {
943         assert *pos < 0xffff_ffff;
944         writer.write_be_u32(*pos as u32);
945     }
946     ebml_w.end_tag();
947     ebml_w.end_tag();
948 }
949
950 fn write_str(writer: io::Writer, &&s: ~str) { writer.write_str(s); }
951
952 fn write_int(writer: io::Writer, &&n: int) {
953     assert n < 0x7fff_ffff;
954     writer.write_be_u32(n as u32);
955 }
956
957 fn encode_meta_item(ebml_w: ebml::Serializer, mi: meta_item) {
958     match mi.node {
959       meta_word(name) => {
960         ebml_w.start_tag(tag_meta_item_word);
961         ebml_w.start_tag(tag_meta_item_name);
962         ebml_w.writer.write(str::to_bytes(name));
963         ebml_w.end_tag();
964         ebml_w.end_tag();
965       }
966       meta_name_value(name, value) => {
967         match value.node {
968           lit_str(value) => {
969             ebml_w.start_tag(tag_meta_item_name_value);
970             ebml_w.start_tag(tag_meta_item_name);
971             ebml_w.writer.write(str::to_bytes(name));
972             ebml_w.end_tag();
973             ebml_w.start_tag(tag_meta_item_value);
974             ebml_w.writer.write(str::to_bytes(*value));
975             ebml_w.end_tag();
976             ebml_w.end_tag();
977           }
978           _ => {/* FIXME (#623): encode other variants */ }
979         }
980       }
981       meta_list(name, items) => {
982         ebml_w.start_tag(tag_meta_item_list);
983         ebml_w.start_tag(tag_meta_item_name);
984         ebml_w.writer.write(str::to_bytes(name));
985         ebml_w.end_tag();
986         for items.each |inner_item| {
987             encode_meta_item(ebml_w, **inner_item);
988         }
989         ebml_w.end_tag();
990       }
991     }
992 }
993
994 fn encode_attributes(ebml_w: ebml::Serializer, attrs: ~[attribute]) {
995     ebml_w.start_tag(tag_attributes);
996     for attrs.each |attr| {
997         ebml_w.start_tag(tag_attribute);
998         encode_meta_item(ebml_w, attr.node.value);
999         ebml_w.end_tag();
1000     }
1001     ebml_w.end_tag();
1002 }
1003
1004 // So there's a special crate attribute called 'link' which defines the
1005 // metadata that Rust cares about for linking crates. This attribute requires
1006 // 'name' and 'vers' items, so if the user didn't provide them we will throw
1007 // them in anyway with default values.
1008 fn synthesize_crate_attrs(ecx: @encode_ctxt, crate: @crate) -> ~[attribute] {
1009
1010     fn synthesize_link_attr(ecx: @encode_ctxt, items: ~[@meta_item]) ->
1011        attribute {
1012
1013         assert (ecx.link_meta.name != ~"");
1014         assert (ecx.link_meta.vers != ~"");
1015
1016         let name_item =
1017             attr::mk_name_value_item_str(~"name", ecx.link_meta.name);
1018         let vers_item =
1019             attr::mk_name_value_item_str(~"vers", ecx.link_meta.vers);
1020
1021         let other_items =
1022             {
1023                 let tmp = attr::remove_meta_items_by_name(items, ~"name");
1024                 attr::remove_meta_items_by_name(tmp, ~"vers")
1025             };
1026
1027         let meta_items = vec::append(~[name_item, vers_item], other_items);
1028         let link_item = attr::mk_list_item(~"link", meta_items);
1029
1030         return attr::mk_attr(link_item);
1031     }
1032
1033     let mut attrs: ~[attribute] = ~[];
1034     let mut found_link_attr = false;
1035     for crate.node.attrs.each |attr| {
1036         attrs.push(
1037             if attr::get_attr_name(*attr) != ~"link" {
1038                 *attr
1039             } else {
1040                 match attr.node.value.node {
1041                   meta_list(_, l) => {
1042                     found_link_attr = true;;
1043                     synthesize_link_attr(ecx, l)
1044                   }
1045                   _ => *attr
1046                 }
1047             });
1048     }
1049
1050     if !found_link_attr { attrs.push(synthesize_link_attr(ecx, ~[])); }
1051
1052     return attrs;
1053 }
1054
1055 fn encode_crate_deps(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
1056                      cstore: cstore::CStore) {
1057
1058     fn get_ordered_deps(ecx: @encode_ctxt, cstore: cstore::CStore)
1059         -> ~[decoder::crate_dep] {
1060
1061         type hashkv = @{key: crate_num, val: cstore::crate_metadata};
1062         type numdep = decoder::crate_dep;
1063
1064         // Pull the cnums and name,vers,hash out of cstore
1065         let mut deps: ~[numdep] = ~[];
1066         do cstore::iter_crate_data(cstore) |key, val| {
1067             let dep = {cnum: key, name: ecx.tcx.sess.ident_of(val.name),
1068                        vers: decoder::get_crate_vers(val.data),
1069                        hash: decoder::get_crate_hash(val.data)};
1070             deps.push(dep);
1071         };
1072
1073         // Sort by cnum
1074         pure fn lteq(kv1: &numdep, kv2: &numdep) -> bool {
1075             kv1.cnum <= kv2.cnum
1076         }
1077         std::sort::quick_sort(deps, lteq);
1078
1079         // Sanity-check the crate numbers
1080         let mut expected_cnum = 1;
1081         for deps.each |n| {
1082             assert (n.cnum == expected_cnum);
1083             expected_cnum += 1;
1084         }
1085
1086         // mut -> immutable hack for vec::map
1087         return vec::slice(deps, 0u, vec::len(deps));
1088     }
1089
1090     // We're just going to write a list of crate 'name-hash-version's, with
1091     // the assumption that they are numbered 1 to n.
1092     // FIXME (#2166): This is not nearly enough to support correct versioning
1093     // but is enough to get transitive crate dependencies working.
1094     ebml_w.start_tag(tag_crate_deps);
1095     for get_ordered_deps(ecx, cstore).each |dep| {
1096         encode_crate_dep(ecx, ebml_w, *dep);
1097     }
1098     ebml_w.end_tag();
1099 }
1100
1101 fn encode_crate_dep(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
1102                     dep: decoder::crate_dep) {
1103     ebml_w.start_tag(tag_crate_dep);
1104     ebml_w.start_tag(tag_crate_dep_name);
1105     ebml_w.writer.write(str::to_bytes(ecx.tcx.sess.str_of(dep.name)));
1106     ebml_w.end_tag();
1107     ebml_w.start_tag(tag_crate_dep_vers);
1108     ebml_w.writer.write(str::to_bytes(dep.vers));
1109     ebml_w.end_tag();
1110     ebml_w.start_tag(tag_crate_dep_hash);
1111     ebml_w.writer.write(str::to_bytes(dep.hash));
1112     ebml_w.end_tag();
1113     ebml_w.end_tag();
1114 }
1115
1116 fn encode_hash(ebml_w: ebml::Serializer, hash: ~str) {
1117     ebml_w.start_tag(tag_crate_hash);
1118     ebml_w.writer.write(str::to_bytes(hash));
1119     ebml_w.end_tag();
1120 }
1121
1122 // NB: Increment this as you change the metadata encoding version.
1123 const metadata_encoding_version : &[u8] = &[0x72, //'r' as u8,
1124                                             0x75, //'u' as u8,
1125                                             0x73, //'s' as u8,
1126                                             0x74, //'t' as u8,
1127                                             0, 0, 0, 1 ];
1128
1129 fn encode_metadata(parms: encode_parms, crate: @crate) -> ~[u8] {
1130     let wr = @io::BytesWriter();
1131     let stats =
1132         {mut inline_bytes: 0,
1133          mut attr_bytes: 0,
1134          mut dep_bytes: 0,
1135          mut item_bytes: 0,
1136          mut index_bytes: 0,
1137          mut zero_bytes: 0,
1138          mut total_bytes: 0,
1139          mut n_inlines: 0};
1140     let ecx: @encode_ctxt = @encode_ctxt({
1141         diag: parms.diag,
1142         tcx: parms.tcx,
1143         stats: move stats,
1144         reachable: parms.reachable,
1145         reexports2: parms.reexports2,
1146         item_symbols: parms.item_symbols,
1147         discrim_symbols: parms.discrim_symbols,
1148         link_meta: parms.link_meta,
1149         cstore: parms.cstore,
1150         encode_inlined_item: parms.encode_inlined_item,
1151         type_abbrevs: ty::new_ty_hash()
1152      });
1153
1154     let ebml_w = ebml::Serializer(wr as io::Writer);
1155
1156     encode_hash(ebml_w, ecx.link_meta.extras_hash);
1157
1158     let mut i = wr.pos;
1159     let crate_attrs = synthesize_crate_attrs(ecx, crate);
1160     encode_attributes(ebml_w, crate_attrs);
1161     ecx.stats.attr_bytes = wr.pos - i;
1162
1163     i = wr.pos;
1164     encode_crate_deps(ecx, ebml_w, ecx.cstore);
1165     ecx.stats.dep_bytes = wr.pos - i;
1166
1167     // Encode and index the items.
1168     ebml_w.start_tag(tag_items);
1169     i = wr.pos;
1170     let items_index = encode_info_for_items(ecx, ebml_w, crate);
1171     ecx.stats.item_bytes = wr.pos - i;
1172
1173     i = wr.pos;
1174     let items_buckets = create_index(items_index);
1175     encode_index(ebml_w, items_buckets, write_int);
1176     ecx.stats.index_bytes = wr.pos - i;
1177     ebml_w.end_tag();
1178
1179     ecx.stats.total_bytes = wr.pos;
1180
1181     if (parms.tcx.sess.meta_stats()) {
1182
1183         do wr.bytes.borrow |v| {
1184             do v.each |e| {
1185                 if *e == 0 {
1186                     ecx.stats.zero_bytes += 1;
1187                 }
1188                 true
1189             }
1190         }
1191
1192         io::println("metadata stats:");
1193         io::println(fmt!("    inline bytes: %u", ecx.stats.inline_bytes));
1194         io::println(fmt!(" attribute bytes: %u", ecx.stats.attr_bytes));
1195         io::println(fmt!("       dep bytes: %u", ecx.stats.dep_bytes));
1196         io::println(fmt!("      item bytes: %u", ecx.stats.item_bytes));
1197         io::println(fmt!("     index bytes: %u", ecx.stats.index_bytes));
1198         io::println(fmt!("      zero bytes: %u", ecx.stats.zero_bytes));
1199         io::println(fmt!("     total bytes: %u", ecx.stats.total_bytes));
1200     }
1201
1202     // Pad this, since something (LLVM, presumably) is cutting off the
1203     // remaining % 4 bytes.
1204     wr.write(&[0u8, 0u8, 0u8, 0u8]);
1205
1206     // FIXME #3396: weird bug here, for reasons unclear this emits random
1207     // looking bytes (mostly 0x1) if we use the version byte-array constant
1208     // above; so we use a string constant inline instead.
1209     //
1210     // Should be:
1211     //
1212     //   vec::from_slice(metadata_encoding_version) +
1213
1214     (do str::as_bytes(&~"rust\x00\x00\x00\x01") |bytes| {
1215         vec::slice(*bytes, 0, 8)
1216     }) + flate::deflate_bytes(wr.bytes.check_out(|buf| buf))
1217 }
1218
1219 // Get the encoded string for a type
1220 fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str {
1221     let cx = @{diag: tcx.diag,
1222                ds: def_to_str,
1223                tcx: tcx,
1224                reachable: |_id| false,
1225                abbrevs: tyencode::ac_no_abbrevs};
1226     do io::with_str_writer |wr| {
1227         tyencode::enc_ty(wr, cx, t);
1228     }
1229 }
1230
1231
1232 // Local Variables:
1233 // mode: rust
1234 // fill-column: 78;
1235 // indent-tabs-mode: nil
1236 // c-basic-offset: 4
1237 // buffer-file-coding-system: utf-8-unix
1238 // End: