| // Metadata encoding |
| |
| use util::ppaux::ty_to_str; |
| |
| use std::{ebml, map}; |
| use std::map::HashMap; |
| use io::WriterUtil; |
| use ebml::Serializer; |
| use syntax::ast::*; |
| use syntax::print::pprust; |
| use syntax::{ast_util, visit}; |
| use syntax::ast_util::*; |
| use common::*; |
| use middle::ty; |
| use middle::ty::node_id_to_type; |
| use middle::resolve; |
| use syntax::ast_map; |
| use syntax::attr; |
| use str::to_bytes; |
| use syntax::ast; |
| use syntax::diagnostic::span_handler; |
| |
| use hash::{Hash, HashUtil}; |
| use to_bytes::IterBytes; |
| |
| export encode_parms; |
| export encode_metadata; |
| export encoded_ty; |
| export reachable; |
| export encode_inlined_item; |
| export metadata_encoding_version; |
| |
| // used by astencode: |
| export def_to_str; |
| export encode_ctxt; |
| export write_type; |
| export write_vstore; |
| export encode_def_id; |
| |
| type abbrev_map = map::HashMap<ty::t, tyencode::ty_abbrev>; |
| |
| type encode_inlined_item = fn@(ecx: @encode_ctxt, |
| ebml_w: ebml::Serializer, |
| path: ast_map::path, |
| ii: ast::inlined_item); |
| |
| type encode_parms = { |
| diag: span_handler, |
| tcx: ty::ctxt, |
| reachable: HashMap<ast::node_id, ()>, |
| reexports2: middle::resolve::ExportMap2, |
| item_symbols: HashMap<ast::node_id, ~str>, |
| discrim_symbols: HashMap<ast::node_id, ~str>, |
| link_meta: link_meta, |
| cstore: cstore::cstore, |
| encode_inlined_item: encode_inlined_item |
| }; |
| |
| type stats = { |
| mut inline_bytes: uint, |
| mut attr_bytes: uint, |
| mut dep_bytes: uint, |
| mut item_bytes: uint, |
| mut index_bytes: uint, |
| mut zero_bytes: uint, |
| mut total_bytes: uint, |
| |
| mut n_inlines: uint |
| }; |
| |
| enum encode_ctxt = { |
| diag: span_handler, |
| tcx: ty::ctxt, |
| stats: stats, |
| reachable: HashMap<ast::node_id, ()>, |
| reexports2: middle::resolve::ExportMap2, |
| item_symbols: HashMap<ast::node_id, ~str>, |
| discrim_symbols: HashMap<ast::node_id, ~str>, |
| link_meta: link_meta, |
| cstore: cstore::cstore, |
| encode_inlined_item: encode_inlined_item, |
| type_abbrevs: abbrev_map |
| }; |
| |
| fn reachable(ecx: @encode_ctxt, id: node_id) -> bool { |
| ecx.reachable.contains_key(id) |
| } |
| |
| fn encode_name(ecx: @encode_ctxt, ebml_w: ebml::Serializer, name: ident) { |
| ebml_w.wr_tagged_str(tag_paths_data_name, ecx.tcx.sess.str_of(name)); |
| } |
| |
| fn encode_def_id(ebml_w: ebml::Serializer, id: def_id) { |
| ebml_w.wr_tagged_str(tag_def_id, def_to_str(id)); |
| } |
| |
| fn encode_region_param(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| it: @ast::item) { |
| let opt_rp = ecx.tcx.region_paramd_items.find(it.id); |
| for opt_rp.each |rp| { |
| do ebml_w.wr_tag(tag_region_param) { |
| (*rp).serialize(&ebml_w); |
| } |
| } |
| } |
| |
| fn encode_mutability(ebml_w: ebml::Serializer, mt: class_mutability) { |
| do ebml_w.wr_tag(tag_class_mut) { |
| let val = match mt { |
| class_immutable => 'a', |
| class_mutable => 'm' |
| }; |
| ebml_w.writer.write(&[val as u8]); |
| } |
| } |
| |
| type entry<T> = {val: T, pos: uint}; |
| |
| fn add_to_index(ecx: @encode_ctxt, ebml_w: ebml::Serializer, path: &[ident], |
| index: &mut ~[entry<~str>], name: ident) { |
| let mut full_path = ~[]; |
| full_path.push_all(path); |
| full_path.push(name); |
| index.push( |
| {val: ast_util::path_name_i(full_path, |
| ecx.tcx.sess.parse_sess.interner), |
| pos: ebml_w.writer.tell()}); |
| } |
| |
| fn encode_trait_ref(ebml_w: ebml::Serializer, ecx: @encode_ctxt, |
| t: @trait_ref) { |
| ebml_w.start_tag(tag_impl_trait); |
| encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, t.ref_id)); |
| ebml_w.end_tag(); |
| } |
| |
| |
| // Item info table encoding |
| fn encode_family(ebml_w: ebml::Serializer, c: char) { |
| ebml_w.start_tag(tag_items_data_item_family); |
| ebml_w.writer.write(&[c as u8]); |
| ebml_w.end_tag(); |
| } |
| |
| fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) } |
| |
| fn encode_ty_type_param_bounds(ebml_w: ebml::Serializer, ecx: @encode_ctxt, |
| params: @~[ty::param_bounds]) { |
| let ty_str_ctxt = @{diag: ecx.diag, |
| ds: def_to_str, |
| tcx: ecx.tcx, |
| reachable: |a| reachable(ecx, a), |
| abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; |
| for params.each |param| { |
| ebml_w.start_tag(tag_items_data_item_ty_param_bounds); |
| tyencode::enc_bounds(ebml_w.writer, ty_str_ctxt, *param); |
| ebml_w.end_tag(); |
| } |
| } |
| |
| fn encode_type_param_bounds(ebml_w: ebml::Serializer, ecx: @encode_ctxt, |
| params: ~[ty_param]) { |
| let ty_param_bounds = |
| @params.map(|param| ecx.tcx.ty_param_bounds.get(param.id)); |
| encode_ty_type_param_bounds(ebml_w, ecx, ty_param_bounds); |
| } |
| |
| |
| fn encode_variant_id(ebml_w: ebml::Serializer, vid: def_id) { |
| ebml_w.start_tag(tag_items_data_item_variant); |
| ebml_w.writer.write(str::to_bytes(def_to_str(vid))); |
| ebml_w.end_tag(); |
| } |
| |
| fn write_type(ecx: @encode_ctxt, ebml_w: ebml::Serializer, typ: ty::t) { |
| let ty_str_ctxt = |
| @{diag: ecx.diag, |
| ds: def_to_str, |
| tcx: ecx.tcx, |
| reachable: |a| reachable(ecx, a), |
| abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; |
| tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ); |
| } |
| |
| fn write_vstore(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| vstore: ty::vstore) { |
| let ty_str_ctxt = |
| @{diag: ecx.diag, |
| ds: def_to_str, |
| tcx: ecx.tcx, |
| reachable: |a| reachable(ecx, a), |
| abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; |
| tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore); |
| } |
| |
| fn encode_type(ecx: @encode_ctxt, ebml_w: ebml::Serializer, typ: ty::t) { |
| ebml_w.start_tag(tag_items_data_item_type); |
| write_type(ecx, ebml_w, typ); |
| ebml_w.end_tag(); |
| } |
| |
| fn encode_symbol(ecx: @encode_ctxt, ebml_w: ebml::Serializer, id: node_id) { |
| ebml_w.start_tag(tag_items_data_item_symbol); |
| let sym = match ecx.item_symbols.find(id) { |
| Some(x) => x, |
| None => { |
| ecx.diag.handler().bug( |
| fmt!("encode_symbol: id not found %d", id)); |
| } |
| }; |
| ebml_w.writer.write(str::to_bytes(sym)); |
| ebml_w.end_tag(); |
| } |
| |
| fn encode_discriminant(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| id: node_id) { |
| ebml_w.start_tag(tag_items_data_item_symbol); |
| ebml_w.writer.write(str::to_bytes(ecx.discrim_symbols.get(id))); |
| ebml_w.end_tag(); |
| } |
| |
| fn encode_disr_val(_ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| disr_val: int) { |
| ebml_w.start_tag(tag_disr_val); |
| ebml_w.writer.write(str::to_bytes(int::to_str(disr_val,10u))); |
| ebml_w.end_tag(); |
| } |
| |
| fn encode_parent_item(ebml_w: ebml::Serializer, id: def_id) { |
| ebml_w.start_tag(tag_items_data_parent_item); |
| ebml_w.writer.write(str::to_bytes(def_to_str(id))); |
| ebml_w.end_tag(); |
| } |
| |
| fn encode_enum_variant_info(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| id: node_id, variants: ~[variant], |
| path: ast_map::path, index: @mut ~[entry<int>], |
| ty_params: ~[ty_param]) { |
| let mut disr_val = 0; |
| let mut i = 0; |
| let vi = ty::enum_variants(ecx.tcx, {crate: local_crate, node: id}); |
| for variants.each |variant| { |
| index.push({val: variant.node.id, pos: ebml_w.writer.tell()}); |
| ebml_w.start_tag(tag_items_data_item); |
| encode_def_id(ebml_w, local_def(variant.node.id)); |
| encode_family(ebml_w, 'v'); |
| encode_name(ecx, ebml_w, variant.node.name); |
| encode_parent_item(ebml_w, local_def(id)); |
| encode_type(ecx, ebml_w, |
| node_id_to_type(ecx.tcx, variant.node.id)); |
| match variant.node.kind { |
| ast::tuple_variant_kind(args) |
| if args.len() > 0 && ty_params.len() == 0 => { |
| encode_symbol(ecx, ebml_w, variant.node.id); |
| } |
| ast::tuple_variant_kind(_) | ast::struct_variant_kind(_) | |
| ast::enum_variant_kind(_) => {} |
| } |
| encode_discriminant(ecx, ebml_w, variant.node.id); |
| if vi[i].disr_val != disr_val { |
| encode_disr_val(ecx, ebml_w, vi[i].disr_val); |
| disr_val = vi[i].disr_val; |
| } |
| encode_type_param_bounds(ebml_w, ecx, ty_params); |
| encode_path(ecx, ebml_w, path, ast_map::path_name(variant.node.name)); |
| ebml_w.end_tag(); |
| disr_val += 1; |
| i += 1; |
| } |
| } |
| |
| fn encode_path(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| path: ast_map::path, name: ast_map::path_elt) { |
| fn encode_path_elt(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| elt: ast_map::path_elt) { |
| let (tag, name) = match elt { |
| ast_map::path_mod(name) => (tag_path_elt_mod, name), |
| ast_map::path_name(name) => (tag_path_elt_name, name) |
| }; |
| |
| ebml_w.wr_tagged_str(tag, ecx.tcx.sess.str_of(name)); |
| } |
| |
| do ebml_w.wr_tag(tag_path) { |
| ebml_w.wr_tagged_u32(tag_path_len, (vec::len(path) + 1u) as u32); |
| for vec::each(path) |pe| { |
| encode_path_elt(ecx, ebml_w, *pe); |
| } |
| encode_path_elt(ecx, ebml_w, name); |
| } |
| } |
| |
| fn encode_info_for_mod(ecx: @encode_ctxt, ebml_w: ebml::Serializer, md: _mod, |
| id: node_id, path: ast_map::path, name: ident) { |
| ebml_w.start_tag(tag_items_data_item); |
| encode_def_id(ebml_w, local_def(id)); |
| encode_family(ebml_w, 'm'); |
| encode_name(ecx, ebml_w, name); |
| debug!("(encoding info for module) encoding info for module ID %d", id); |
| |
| // Encode info about all the module children. |
| for md.items.each |item| { |
| match item.node { |
| item_impl(*) | item_class(*) => { |
| let (ident, did) = (item.ident, item.id); |
| debug!("(encoding info for module) ... encoding impl %s \ |
| (%?/%?), exported? %?", |
| ecx.tcx.sess.str_of(ident), |
| did, |
| ast_map::node_id_to_str(ecx.tcx.items, did, ecx.tcx |
| .sess.parse_sess.interner), |
| ast_util::is_exported(ident, md)); |
| |
| ebml_w.start_tag(tag_mod_impl); |
| ebml_w.wr_str(def_to_str(local_def(did))); |
| ebml_w.end_tag(); |
| } |
| _ => {} // XXX: Encode these too. |
| } |
| } |
| |
| encode_path(ecx, ebml_w, path, ast_map::path_mod(name)); |
| |
| // Encode the reexports of this module. |
| debug!("(encoding info for module) encoding reexports for %d", id); |
| match ecx.reexports2.find(id) { |
| Some(exports) => { |
| debug!("(encoding info for module) found reexports for %d", id); |
| for exports.each |exp| { |
| debug!("(encoding info for module) reexport '%s' for %d", |
| exp.name, id); |
| ebml_w.start_tag(tag_items_data_item_reexport); |
| ebml_w.start_tag(tag_items_data_item_reexport_def_id); |
| ebml_w.wr_str(def_to_str(exp.def_id)); |
| ebml_w.end_tag(); |
| ebml_w.start_tag(tag_items_data_item_reexport_name); |
| ebml_w.wr_str(exp.name); |
| ebml_w.end_tag(); |
| ebml_w.end_tag(); |
| } |
| } |
| None => { |
| debug!("(encoding info for module) found no reexports for %d", |
| id); |
| } |
| } |
| |
| ebml_w.end_tag(); |
| } |
| |
| fn encode_visibility(ebml_w: ebml::Serializer, visibility: visibility) { |
| encode_family(ebml_w, match visibility { |
| public => 'g', |
| private => 'j', |
| inherited => 'N' |
| }); |
| } |
| |
| fn encode_self_type(ebml_w: ebml::Serializer, self_type: ast::self_ty_) { |
| ebml_w.start_tag(tag_item_trait_method_self_ty); |
| |
| // Encode the base self type. |
| let ch; |
| match self_type { |
| sty_static => { ch = 's' as u8; } |
| sty_by_ref => { ch = 'r' as u8; } |
| sty_value => { ch = 'v' as u8; } |
| sty_region(_) => { ch = '&' as u8; } |
| sty_box(_) => { ch = '@' as u8; } |
| sty_uniq(_) => { ch = '~' as u8; } |
| } |
| ebml_w.writer.write(&[ ch ]); |
| |
| // Encode mutability. |
| match self_type { |
| sty_static | sty_by_ref | sty_value => { /* No-op. */ } |
| sty_region(m_imm) | sty_box(m_imm) | sty_uniq(m_imm) => { |
| ebml_w.writer.write(&[ 'i' as u8 ]); |
| } |
| sty_region(m_mutbl) | sty_box(m_mutbl) | sty_uniq(m_mutbl) => { |
| ebml_w.writer.write(&[ 'm' as u8 ]); |
| } |
| sty_region(m_const) | sty_box(m_const) | sty_uniq(m_const) => { |
| ebml_w.writer.write(&[ 'c' as u8 ]); |
| } |
| } |
| |
| ebml_w.end_tag(); |
| } |
| |
| /* Returns an index of items in this class */ |
| fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| id: node_id, path: ast_map::path, |
| class_tps: ~[ty_param], |
| fields: ~[@struct_field], |
| methods: ~[@method], |
| global_index: @mut~[entry<int>]) -> ~[entry<int>] { |
| /* Each class has its own index, since different classes |
| may have fields with the same name */ |
| let index = @mut ~[]; |
| let tcx = ecx.tcx; |
| /* We encode both private and public fields -- need to include |
| private fields to get the offsets right */ |
| for fields.each |field| { |
| match field.node.kind { |
| named_field(nm, mt, vis) => { |
| let id = field.node.id; |
| index.push({val: id, pos: ebml_w.writer.tell()}); |
| global_index.push({val: id, |
| pos: ebml_w.writer.tell()}); |
| ebml_w.start_tag(tag_items_data_item); |
| debug!("encode_info_for_class: doing %s %d", |
| tcx.sess.str_of(nm), id); |
| encode_visibility(ebml_w, vis); |
| encode_name(ecx, ebml_w, nm); |
| encode_path(ecx, ebml_w, path, ast_map::path_name(nm)); |
| encode_type(ecx, ebml_w, node_id_to_type(tcx, id)); |
| encode_mutability(ebml_w, mt); |
| encode_def_id(ebml_w, local_def(id)); |
| ebml_w.end_tag(); |
| } |
| unnamed_field => {} |
| } |
| } |
| |
| for methods.each |m| { |
| match m.vis { |
| public | inherited => { |
| index.push({val: m.id, pos: ebml_w.writer.tell()}); |
| global_index.push( |
| {val: m.id, pos: ebml_w.writer.tell()}); |
| let impl_path = vec::append_one(path, |
| ast_map::path_name(m.ident)); |
| debug!("encode_info_for_class: doing %s %d", |
| ecx.tcx.sess.str_of(m.ident), m.id); |
| encode_info_for_method(ecx, ebml_w, impl_path, |
| should_inline(m.attrs), id, *m, |
| vec::append(class_tps, m.tps)); |
| } |
| _ => { /* don't encode private methods */ } |
| } |
| } |
| |
| *index |
| } |
| |
| // This is for encoding info for ctors and dtors |
| fn encode_info_for_ctor(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| id: node_id, ident: ident, path: ast_map::path, |
| item: Option<inlined_item>, tps: ~[ty_param]) { |
| ebml_w.start_tag(tag_items_data_item); |
| encode_name(ecx, ebml_w, ident); |
| encode_def_id(ebml_w, local_def(id)); |
| encode_family(ebml_w, purity_fn_family(ast::impure_fn)); |
| encode_type_param_bounds(ebml_w, ecx, tps); |
| let its_ty = node_id_to_type(ecx.tcx, id); |
| debug!("fn name = %s ty = %s its node id = %d", |
| ecx.tcx.sess.str_of(ident), |
| util::ppaux::ty_to_str(ecx.tcx, its_ty), id); |
| encode_type(ecx, ebml_w, its_ty); |
| encode_path(ecx, ebml_w, path, ast_map::path_name(ident)); |
| match item { |
| Some(it) => { |
| ecx.encode_inlined_item(ecx, ebml_w, path, it); |
| } |
| None => { |
| encode_symbol(ecx, ebml_w, id); |
| } |
| } |
| ebml_w.end_tag(); |
| } |
| |
| fn encode_info_for_method(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| impl_path: ast_map::path, should_inline: bool, |
| parent_id: node_id, |
| m: @method, all_tps: ~[ty_param]) { |
| debug!("encode_info_for_method: %d %s %u", m.id, |
| ecx.tcx.sess.str_of(m.ident), all_tps.len()); |
| ebml_w.start_tag(tag_items_data_item); |
| encode_def_id(ebml_w, local_def(m.id)); |
| encode_family(ebml_w, purity_fn_family(m.purity)); |
| encode_type_param_bounds(ebml_w, ecx, all_tps); |
| encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id)); |
| encode_name(ecx, ebml_w, m.ident); |
| encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident)); |
| encode_self_type(ebml_w, m.self_ty.node); |
| if all_tps.len() > 0u || should_inline { |
| ecx.encode_inlined_item( |
| ecx, ebml_w, impl_path, |
| ii_method(local_def(parent_id), m)); |
| } else { |
| encode_symbol(ecx, ebml_w, m.id); |
| } |
| ebml_w.end_tag(); |
| } |
| |
| fn purity_fn_family(p: purity) -> char { |
| match p { |
| unsafe_fn => 'u', |
| pure_fn => 'p', |
| impure_fn => 'f', |
| extern_fn => 'e' |
| } |
| } |
| fn purity_static_method_family(p: purity) -> char { |
| match p { |
| unsafe_fn => 'U', |
| pure_fn => 'P', |
| impure_fn => 'F', |
| _ => fail ~"extern fn can't be static" |
| } |
| } |
| |
| |
| fn should_inline(attrs: ~[attribute]) -> bool { |
| match attr::find_inline_attr(attrs) { |
| attr::ia_none | attr::ia_never => false, |
| attr::ia_hint | attr::ia_always => true |
| } |
| } |
| |
| |
| fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| item: @item, index: @mut ~[entry<int>], |
| path: ast_map::path) { |
| |
| let tcx = ecx.tcx; |
| let must_write = |
| match item.node { |
| item_enum(_, _) | item_impl(*) |
| | item_trait(*) | item_class(*) => true, |
| _ => false |
| }; |
| if !must_write && !reachable(ecx, item.id) { return; } |
| |
| fn add_to_index_(item: @item, ebml_w: ebml::Serializer, |
| index: @mut ~[entry<int>]) { |
| index.push({val: item.id, pos: ebml_w.writer.tell()}); |
| } |
| let add_to_index = |copy ebml_w| add_to_index_(item, ebml_w, index); |
| |
| match item.node { |
| item_const(_, _) => { |
| add_to_index(); |
| ebml_w.start_tag(tag_items_data_item); |
| encode_def_id(ebml_w, local_def(item.id)); |
| encode_family(ebml_w, 'c'); |
| encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); |
| encode_symbol(ecx, ebml_w, item.id); |
| encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); |
| ebml_w.end_tag(); |
| } |
| item_fn(_, purity, tps, _) => { |
| add_to_index(); |
| ebml_w.start_tag(tag_items_data_item); |
| encode_def_id(ebml_w, local_def(item.id)); |
| encode_family(ebml_w, purity_fn_family(purity)); |
| encode_type_param_bounds(ebml_w, ecx, tps); |
| encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); |
| encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); |
| encode_attributes(ebml_w, item.attrs); |
| if tps.len() > 0u || should_inline(item.attrs) { |
| ecx.encode_inlined_item(ecx, ebml_w, path, ii_item(item)); |
| } else { |
| encode_symbol(ecx, ebml_w, item.id); |
| } |
| ebml_w.end_tag(); |
| } |
| item_mod(m) => { |
| add_to_index(); |
| encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident); |
| } |
| item_foreign_mod(_) => { |
| add_to_index(); |
| ebml_w.start_tag(tag_items_data_item); |
| encode_def_id(ebml_w, local_def(item.id)); |
| encode_family(ebml_w, 'n'); |
| encode_name(ecx, ebml_w, item.ident); |
| encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); |
| ebml_w.end_tag(); |
| } |
| item_ty(_, tps) => { |
| add_to_index(); |
| ebml_w.start_tag(tag_items_data_item); |
| encode_def_id(ebml_w, local_def(item.id)); |
| encode_family(ebml_w, 'y'); |
| encode_type_param_bounds(ebml_w, ecx, tps); |
| encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); |
| encode_name(ecx, ebml_w, item.ident); |
| encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); |
| encode_region_param(ecx, ebml_w, item); |
| ebml_w.end_tag(); |
| } |
| item_enum(enum_definition, tps) => { |
| add_to_index(); |
| do ebml_w.wr_tag(tag_items_data_item) { |
| encode_def_id(ebml_w, local_def(item.id)); |
| encode_family(ebml_w, 't'); |
| encode_type_param_bounds(ebml_w, ecx, tps); |
| encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); |
| encode_name(ecx, ebml_w, item.ident); |
| for enum_definition.variants.each |v| { |
| encode_variant_id(ebml_w, local_def(v.node.id)); |
| } |
| ecx.encode_inlined_item(ecx, ebml_w, path, ii_item(item)); |
| encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); |
| encode_region_param(ecx, ebml_w, item); |
| } |
| encode_enum_variant_info(ecx, ebml_w, item.id, |
| enum_definition.variants, path, index, tps); |
| } |
| item_class(struct_def, tps) => { |
| /* First, encode the fields and methods |
| These come first because we need to write them to make |
| the index, and the index needs to be in the item for the |
| class itself */ |
| let idx = encode_info_for_class(ecx, ebml_w, item.id, path, tps, |
| struct_def.fields, struct_def.methods, |
| index); |
| /* Encode the dtor */ |
| do struct_def.dtor.iter |dtor| { |
| index.push({val: dtor.node.id, pos: ebml_w.writer.tell()}); |
| encode_info_for_ctor(ecx, ebml_w, dtor.node.id, |
| ecx.tcx.sess.ident_of( |
| ecx.tcx.sess.str_of(item.ident) + |
| ~"_dtor"), |
| path, if tps.len() > 0u { |
| Some(ii_dtor(*dtor, item.ident, tps, |
| local_def(item.id))) } |
| else { None }, tps); |
| } |
| |
| /* Index the class*/ |
| add_to_index(); |
| /* Now, make an item for the class itself */ |
| ebml_w.start_tag(tag_items_data_item); |
| encode_def_id(ebml_w, local_def(item.id)); |
| |
| match struct_def.ctor { |
| None => encode_family(ebml_w, 'S'), |
| Some(_) => encode_family(ebml_w, 'C') |
| } |
| |
| encode_type_param_bounds(ebml_w, ecx, tps); |
| encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); |
| encode_name(ecx, ebml_w, item.ident); |
| encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); |
| encode_region_param(ecx, ebml_w, item); |
| for struct_def.traits.each |t| { |
| encode_trait_ref(ebml_w, ecx, *t); |
| } |
| /* Encode the dtor */ |
| /* Encode id for dtor */ |
| do struct_def.dtor.iter |dtor| { |
| do ebml_w.wr_tag(tag_item_dtor) { |
| encode_def_id(ebml_w, local_def(dtor.node.id)); |
| } |
| }; |
| |
| /* Encode def_ids for each field and method |
| for methods, write all the stuff get_trait_method |
| needs to know*/ |
| for struct_def.fields.each |f| { |
| match f.node.kind { |
| named_field(ident, _, vis) => { |
| ebml_w.start_tag(tag_item_field); |
| encode_visibility(ebml_w, vis); |
| encode_name(ecx, ebml_w, ident); |
| encode_def_id(ebml_w, local_def(f.node.id)); |
| ebml_w.end_tag(); |
| } |
| unnamed_field => {} |
| } |
| } |
| |
| for struct_def.methods.each |m| { |
| match m.vis { |
| private => { /* do nothing */ } |
| public | inherited => { |
| /* Write the info that's needed when viewing this class |
| as a trait */ |
| ebml_w.start_tag(tag_item_trait_method); |
| encode_family(ebml_w, purity_fn_family(m.purity)); |
| encode_name(ecx, ebml_w, m.ident); |
| encode_type_param_bounds(ebml_w, ecx, m.tps); |
| encode_type(ecx, ebml_w, node_id_to_type(tcx, m.id)); |
| encode_def_id(ebml_w, local_def(m.id)); |
| encode_self_type(ebml_w, m.self_ty.node); |
| ebml_w.end_tag(); |
| /* Write the info that's needed when viewing this class |
| as an impl (just the method def_id and self type) */ |
| ebml_w.start_tag(tag_item_impl_method); |
| ebml_w.writer.write(to_bytes(def_to_str(local_def(m.id)))); |
| ebml_w.end_tag(); |
| } |
| } |
| } |
| /* Each class has its own index -- encode it */ |
| let bkts = create_index(idx); |
| encode_index(ebml_w, bkts, write_int); |
| ebml_w.end_tag(); |
| |
| /* Encode the constructor */ |
| for struct_def.ctor.each |ctor| { |
| debug!("encoding info for ctor %s %d", |
| ecx.tcx.sess.str_of(item.ident), ctor.node.id); |
| index.push({ |
| val: ctor.node.id, |
| pos: ebml_w.writer.tell() |
| }); |
| encode_info_for_ctor(ecx, ebml_w, ctor.node.id, item.ident, |
| path, if tps.len() > 0u { |
| Some(ii_ctor(*ctor, item.ident, tps, |
| local_def(item.id))) } |
| else { None }, tps); |
| } |
| } |
| item_impl(tps, opt_trait, _, methods) => { |
| add_to_index(); |
| ebml_w.start_tag(tag_items_data_item); |
| encode_def_id(ebml_w, local_def(item.id)); |
| encode_family(ebml_w, 'i'); |
| encode_region_param(ecx, ebml_w, item); |
| encode_type_param_bounds(ebml_w, ecx, tps); |
| encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); |
| encode_name(ecx, ebml_w, item.ident); |
| encode_attributes(ebml_w, item.attrs); |
| for methods.each |m| { |
| ebml_w.start_tag(tag_item_impl_method); |
| ebml_w.writer.write(str::to_bytes(def_to_str(local_def(m.id)))); |
| ebml_w.end_tag(); |
| } |
| do opt_trait.iter() |associated_trait| { |
| encode_trait_ref(ebml_w, ecx, *associated_trait) |
| } |
| encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); |
| ebml_w.end_tag(); |
| |
| let impl_path = vec::append_one(path, |
| ast_map::path_name(item.ident)); |
| for methods.each |m| { |
| index.push({val: m.id, pos: ebml_w.writer.tell()}); |
| encode_info_for_method(ecx, ebml_w, impl_path, |
| should_inline(m.attrs), item.id, *m, |
| vec::append(tps, m.tps)); |
| } |
| } |
| item_trait(tps, traits, ms) => { |
| add_to_index(); |
| ebml_w.start_tag(tag_items_data_item); |
| encode_def_id(ebml_w, local_def(item.id)); |
| encode_family(ebml_w, 'I'); |
| encode_region_param(ecx, ebml_w, item); |
| encode_type_param_bounds(ebml_w, ecx, tps); |
| encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); |
| encode_name(ecx, ebml_w, item.ident); |
| encode_attributes(ebml_w, item.attrs); |
| let mut i = 0u; |
| for vec::each(*ty::trait_methods(tcx, local_def(item.id))) |mty| { |
| match ms[i] { |
| required(ty_m) => { |
| ebml_w.start_tag(tag_item_trait_method); |
| encode_def_id(ebml_w, local_def(ty_m.id)); |
| encode_name(ecx, ebml_w, mty.ident); |
| encode_type_param_bounds(ebml_w, ecx, ty_m.tps); |
| encode_type(ecx, ebml_w, ty::mk_fn(tcx, mty.fty)); |
| encode_family(ebml_w, purity_fn_family(mty.fty.meta.purity)); |
| encode_self_type(ebml_w, mty.self_ty); |
| ebml_w.end_tag(); |
| } |
| provided(m) => { |
| encode_info_for_method(ecx, ebml_w, path, |
| should_inline(m.attrs), item.id, |
| m, m.tps); |
| } |
| } |
| i += 1u; |
| } |
| encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); |
| for traits.each |associated_trait| { |
| encode_trait_ref(ebml_w, ecx, *associated_trait) |
| } |
| ebml_w.end_tag(); |
| |
| // Now, output all of the static methods as items. Note that for the |
| // method info, we output static methods with type signatures as |
| // written. Here, we output the *real* type signatures. I feel like |
| // maybe we should only ever handle the real type signatures. |
| for vec::each(ms) |m| { |
| let ty_m = ast_util::trait_method_to_ty_method(*m); |
| if ty_m.self_ty.node != ast::sty_static { loop; } |
| |
| index.push({val: ty_m.id, pos: ebml_w.writer.tell()}); |
| |
| ebml_w.start_tag(tag_items_data_item); |
| encode_def_id(ebml_w, local_def(ty_m.id)); |
| encode_name(ecx, ebml_w, ty_m.ident); |
| encode_family(ebml_w, |
| purity_static_method_family(ty_m.purity)); |
| let polyty = ecx.tcx.tcache.get(local_def(ty_m.id)); |
| encode_ty_type_param_bounds(ebml_w, ecx, polyty.bounds); |
| encode_type(ecx, ebml_w, polyty.ty); |
| encode_path(ecx, ebml_w, path, ast_map::path_name(ty_m.ident)); |
| ebml_w.end_tag(); |
| } |
| |
| |
| } |
| item_mac(*) => fail ~"item macros unimplemented" |
| } |
| } |
| |
| fn encode_info_for_foreign_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| nitem: @foreign_item, |
| index: @mut ~[entry<int>], |
| path: ast_map::path, abi: foreign_abi) { |
| if !reachable(ecx, nitem.id) { return; } |
| index.push({val: nitem.id, pos: ebml_w.writer.tell()}); |
| |
| ebml_w.start_tag(tag_items_data_item); |
| match nitem.node { |
| foreign_item_fn(_, purity, tps) => { |
| encode_def_id(ebml_w, local_def(nitem.id)); |
| encode_family(ebml_w, purity_fn_family(purity)); |
| encode_type_param_bounds(ebml_w, ecx, tps); |
| encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); |
| if abi == foreign_abi_rust_intrinsic { |
| ecx.encode_inlined_item(ecx, ebml_w, path, |
| ii_foreign(nitem)); |
| } else { |
| encode_symbol(ecx, ebml_w, nitem.id); |
| } |
| encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident)); |
| } |
| foreign_item_const(*) => { |
| encode_def_id(ebml_w, local_def(nitem.id)); |
| encode_family(ebml_w, 'c'); |
| encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); |
| encode_symbol(ecx, ebml_w, nitem.id); |
| encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident)); |
| } |
| } |
| ebml_w.end_tag(); |
| } |
| |
| fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| crate: @crate) -> ~[entry<int>] { |
| let index = @mut ~[]; |
| ebml_w.start_tag(tag_items_data); |
| index.push({val: crate_node_id, pos: ebml_w.writer.tell()}); |
| encode_info_for_mod(ecx, ebml_w, crate.node.module, |
| crate_node_id, ~[], |
| syntax::parse::token::special_idents::invalid); |
| visit::visit_crate(*crate, (), visit::mk_vt(@{ |
| visit_expr: |_e, _cx, _v| { }, |
| visit_item: |i, cx, v, copy ebml_w| { |
| visit::visit_item(i, cx, v); |
| match ecx.tcx.items.get(i.id) { |
| ast_map::node_item(_, pt) => { |
| encode_info_for_item(ecx, ebml_w, i, index, *pt); |
| } |
| _ => fail ~"bad item" |
| } |
| }, |
| visit_foreign_item: |ni, cx, v, copy ebml_w| { |
| visit::visit_foreign_item(ni, cx, v); |
| match ecx.tcx.items.get(ni.id) { |
| ast_map::node_foreign_item(_, abi, pt) => { |
| encode_info_for_foreign_item(ecx, ebml_w, ni, |
| index, *pt, abi); |
| } |
| // case for separate item and foreign-item tables |
| _ => fail ~"bad foreign item" |
| } |
| } |
| ,.. *visit::default_visitor() |
| })); |
| ebml_w.end_tag(); |
| return *index; |
| } |
| |
| |
| // Path and definition ID indexing |
| |
| fn create_index<T: Copy Hash IterBytes>(index: ~[entry<T>]) -> |
| ~[@~[entry<T>]] { |
| let mut buckets: ~[@mut ~[entry<T>]] = ~[]; |
| for uint::range(0u, 256u) |_i| { buckets.push(@mut ~[]); }; |
| for index.each |elt| { |
| let h = elt.val.hash() as uint; |
| buckets[h % 256].push(*elt); |
| } |
| |
| let mut buckets_frozen = ~[]; |
| for buckets.each |bucket| { |
| buckets_frozen.push(@**bucket); |
| } |
| return buckets_frozen; |
| } |
| |
| fn encode_index<T>(ebml_w: ebml::Serializer, buckets: ~[@~[entry<T>]], |
| write_fn: fn(io::Writer, T)) { |
| let writer = ebml_w.writer; |
| ebml_w.start_tag(tag_index); |
| let mut bucket_locs: ~[uint] = ~[]; |
| ebml_w.start_tag(tag_index_buckets); |
| for buckets.each |bucket| { |
| bucket_locs.push(ebml_w.writer.tell()); |
| ebml_w.start_tag(tag_index_buckets_bucket); |
| for vec::each(**bucket) |elt| { |
| ebml_w.start_tag(tag_index_buckets_bucket_elt); |
| assert elt.pos < 0xffff_ffff; |
| writer.write_be_u32(elt.pos as u32); |
| write_fn(writer, elt.val); |
| ebml_w.end_tag(); |
| } |
| ebml_w.end_tag(); |
| } |
| ebml_w.end_tag(); |
| ebml_w.start_tag(tag_index_table); |
| for bucket_locs.each |pos| { |
| assert *pos < 0xffff_ffff; |
| writer.write_be_u32(*pos as u32); |
| } |
| ebml_w.end_tag(); |
| ebml_w.end_tag(); |
| } |
| |
| fn write_str(writer: io::Writer, &&s: ~str) { writer.write_str(s); } |
| |
| fn write_int(writer: io::Writer, &&n: int) { |
| assert n < 0x7fff_ffff; |
| writer.write_be_u32(n as u32); |
| } |
| |
| fn encode_meta_item(ebml_w: ebml::Serializer, mi: meta_item) { |
| match mi.node { |
| meta_word(name) => { |
| ebml_w.start_tag(tag_meta_item_word); |
| ebml_w.start_tag(tag_meta_item_name); |
| ebml_w.writer.write(str::to_bytes(name)); |
| ebml_w.end_tag(); |
| ebml_w.end_tag(); |
| } |
| meta_name_value(name, value) => { |
| match value.node { |
| lit_str(value) => { |
| ebml_w.start_tag(tag_meta_item_name_value); |
| ebml_w.start_tag(tag_meta_item_name); |
| ebml_w.writer.write(str::to_bytes(name)); |
| ebml_w.end_tag(); |
| ebml_w.start_tag(tag_meta_item_value); |
| ebml_w.writer.write(str::to_bytes(*value)); |
| ebml_w.end_tag(); |
| ebml_w.end_tag(); |
| } |
| _ => {/* FIXME (#623): encode other variants */ } |
| } |
| } |
| meta_list(name, items) => { |
| ebml_w.start_tag(tag_meta_item_list); |
| ebml_w.start_tag(tag_meta_item_name); |
| ebml_w.writer.write(str::to_bytes(name)); |
| ebml_w.end_tag(); |
| for items.each |inner_item| { |
| encode_meta_item(ebml_w, **inner_item); |
| } |
| ebml_w.end_tag(); |
| } |
| } |
| } |
| |
| fn encode_attributes(ebml_w: ebml::Serializer, attrs: ~[attribute]) { |
| ebml_w.start_tag(tag_attributes); |
| for attrs.each |attr| { |
| ebml_w.start_tag(tag_attribute); |
| encode_meta_item(ebml_w, attr.node.value); |
| ebml_w.end_tag(); |
| } |
| ebml_w.end_tag(); |
| } |
| |
| // So there's a special crate attribute called 'link' which defines the |
| // metadata that Rust cares about for linking crates. This attribute requires |
| // 'name' and 'vers' items, so if the user didn't provide them we will throw |
| // them in anyway with default values. |
| fn synthesize_crate_attrs(ecx: @encode_ctxt, crate: @crate) -> ~[attribute] { |
| |
| fn synthesize_link_attr(ecx: @encode_ctxt, items: ~[@meta_item]) -> |
| attribute { |
| |
| assert (ecx.link_meta.name != ~""); |
| assert (ecx.link_meta.vers != ~""); |
| |
| let name_item = |
| attr::mk_name_value_item_str(~"name", ecx.link_meta.name); |
| let vers_item = |
| attr::mk_name_value_item_str(~"vers", ecx.link_meta.vers); |
| |
| let other_items = |
| { |
| let tmp = attr::remove_meta_items_by_name(items, ~"name"); |
| attr::remove_meta_items_by_name(tmp, ~"vers") |
| }; |
| |
| let meta_items = vec::append(~[name_item, vers_item], other_items); |
| let link_item = attr::mk_list_item(~"link", meta_items); |
| |
| return attr::mk_attr(link_item); |
| } |
| |
| let mut attrs: ~[attribute] = ~[]; |
| let mut found_link_attr = false; |
| for crate.node.attrs.each |attr| { |
| attrs.push( |
| if attr::get_attr_name(*attr) != ~"link" { |
| *attr |
| } else { |
| match attr.node.value.node { |
| meta_list(_, l) => { |
| found_link_attr = true;; |
| synthesize_link_attr(ecx, l) |
| } |
| _ => *attr |
| } |
| }); |
| } |
| |
| if !found_link_attr { attrs.push(synthesize_link_attr(ecx, ~[])); } |
| |
| return attrs; |
| } |
| |
| fn encode_crate_deps(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| cstore: cstore::cstore) { |
| |
| fn get_ordered_deps(ecx: @encode_ctxt, cstore: cstore::cstore) |
| -> ~[decoder::crate_dep] { |
| |
| type hashkv = @{key: crate_num, val: cstore::crate_metadata}; |
| type numdep = decoder::crate_dep; |
| |
| // Pull the cnums and name,vers,hash out of cstore |
| let mut deps: ~[numdep] = ~[]; |
| do cstore::iter_crate_data(cstore) |key, val| { |
| let dep = {cnum: key, name: ecx.tcx.sess.ident_of(val.name), |
| vers: decoder::get_crate_vers(val.data), |
| hash: decoder::get_crate_hash(val.data)}; |
| deps.push(dep); |
| }; |
| |
| // Sort by cnum |
| pure fn lteq(kv1: &numdep, kv2: &numdep) -> bool { |
| kv1.cnum <= kv2.cnum |
| } |
| std::sort::quick_sort(lteq, deps); |
| |
| // Sanity-check the crate numbers |
| let mut expected_cnum = 1; |
| for deps.each |n| { |
| assert (n.cnum == expected_cnum); |
| expected_cnum += 1; |
| } |
| |
| // mut -> immutable hack for vec::map |
| return vec::slice(deps, 0u, vec::len(deps)); |
| } |
| |
| // We're just going to write a list of crate 'name-hash-version's, with |
| // the assumption that they are numbered 1 to n. |
| // FIXME (#2166): This is not nearly enough to support correct versioning |
| // but is enough to get transitive crate dependencies working. |
| ebml_w.start_tag(tag_crate_deps); |
| for get_ordered_deps(ecx, cstore).each |dep| { |
| encode_crate_dep(ecx, ebml_w, *dep); |
| } |
| ebml_w.end_tag(); |
| } |
| |
| fn encode_crate_dep(ecx: @encode_ctxt, ebml_w: ebml::Serializer, |
| dep: decoder::crate_dep) { |
| ebml_w.start_tag(tag_crate_dep); |
| ebml_w.start_tag(tag_crate_dep_name); |
| ebml_w.writer.write(str::to_bytes(ecx.tcx.sess.str_of(dep.name))); |
| ebml_w.end_tag(); |
| ebml_w.start_tag(tag_crate_dep_vers); |
| ebml_w.writer.write(str::to_bytes(dep.vers)); |
| ebml_w.end_tag(); |
| ebml_w.start_tag(tag_crate_dep_hash); |
| ebml_w.writer.write(str::to_bytes(dep.hash)); |
| ebml_w.end_tag(); |
| ebml_w.end_tag(); |
| } |
| |
| fn encode_hash(ebml_w: ebml::Serializer, hash: ~str) { |
| ebml_w.start_tag(tag_crate_hash); |
| ebml_w.writer.write(str::to_bytes(hash)); |
| ebml_w.end_tag(); |
| } |
| |
| // NB: Increment this as you change the metadata encoding version. |
| const metadata_encoding_version : &[u8] = &[0x72, //'r' as u8, |
| 0x75, //'u' as u8, |
| 0x73, //'s' as u8, |
| 0x74, //'t' as u8, |
| 0, 0, 0, 1 ]; |
| |
| fn encode_metadata(parms: encode_parms, crate: @crate) -> ~[u8] { |
| let wr = @io::BytesWriter(); |
| let stats = |
| {mut inline_bytes: 0, |
| mut attr_bytes: 0, |
| mut dep_bytes: 0, |
| mut item_bytes: 0, |
| mut index_bytes: 0, |
| mut zero_bytes: 0, |
| mut total_bytes: 0, |
| mut n_inlines: 0}; |
| let ecx: @encode_ctxt = @encode_ctxt({ |
| diag: parms.diag, |
| tcx: parms.tcx, |
| stats: move stats, |
| reachable: parms.reachable, |
| reexports2: parms.reexports2, |
| item_symbols: parms.item_symbols, |
| discrim_symbols: parms.discrim_symbols, |
| link_meta: parms.link_meta, |
| cstore: parms.cstore, |
| encode_inlined_item: parms.encode_inlined_item, |
| type_abbrevs: ty::new_ty_hash() |
| }); |
| |
| let ebml_w = ebml::Serializer(wr as io::Writer); |
| |
| encode_hash(ebml_w, ecx.link_meta.extras_hash); |
| |
| let mut i = wr.pos; |
| let crate_attrs = synthesize_crate_attrs(ecx, crate); |
| encode_attributes(ebml_w, crate_attrs); |
| ecx.stats.attr_bytes = wr.pos - i; |
| |
| i = wr.pos; |
| encode_crate_deps(ecx, ebml_w, ecx.cstore); |
| ecx.stats.dep_bytes = wr.pos - i; |
| |
| // Encode and index the items. |
| ebml_w.start_tag(tag_items); |
| i = wr.pos; |
| let items_index = encode_info_for_items(ecx, ebml_w, crate); |
| ecx.stats.item_bytes = wr.pos - i; |
| |
| i = wr.pos; |
| let items_buckets = create_index(items_index); |
| encode_index(ebml_w, items_buckets, write_int); |
| ecx.stats.index_bytes = wr.pos - i; |
| ebml_w.end_tag(); |
| |
| ecx.stats.total_bytes = wr.pos; |
| |
| if (parms.tcx.sess.meta_stats()) { |
| |
| do wr.buf.borrow |v| { |
| do v.each |e| { |
| if *e == 0 { |
| ecx.stats.zero_bytes += 1; |
| } |
| true |
| } |
| } |
| |
| io::println("metadata stats:"); |
| io::println(fmt!(" inline bytes: %u", ecx.stats.inline_bytes)); |
| io::println(fmt!(" attribute bytes: %u", ecx.stats.attr_bytes)); |
| io::println(fmt!(" dep bytes: %u", ecx.stats.dep_bytes)); |
| io::println(fmt!(" item bytes: %u", ecx.stats.item_bytes)); |
| io::println(fmt!(" index bytes: %u", ecx.stats.index_bytes)); |
| io::println(fmt!(" zero bytes: %u", ecx.stats.zero_bytes)); |
| io::println(fmt!(" total bytes: %u", ecx.stats.total_bytes)); |
| } |
| |
| // Pad this, since something (LLVM, presumably) is cutting off the |
| // remaining % 4 bytes. |
| wr.write(&[0u8, 0u8, 0u8, 0u8]); |
| |
| // FIXME #3396: weird bug here, for reasons unclear this emits random |
| // looking bytes (mostly 0x1) if we use the version byte-array constant |
| // above; so we use a string constant inline instead. |
| // |
| // Should be: |
| // |
| // vec::from_slice(metadata_encoding_version) + |
| |
| (do str::as_bytes(&~"rust\x00\x00\x00\x01") |bytes| { |
| vec::slice(*bytes, 0, 8) |
| }) + flate::deflate_bytes(wr.buf.check_out(|buf| buf)) |
| } |
| |
| // Get the encoded string for a type |
| fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str { |
| let cx = @{diag: tcx.diag, |
| ds: def_to_str, |
| tcx: tcx, |
| reachable: |_id| false, |
| abbrevs: tyencode::ac_no_abbrevs}; |
| do io::with_str_writer |wr| { |
| tyencode::enc_ty(wr, cx, t); |
| } |
| } |
| |
| |
| // Local Variables: |
| // mode: rust |
| // fill-column: 78; |
| // indent-tabs-mode: nil |
| // c-basic-offset: 4 |
| // buffer-file-coding-system: utf-8-unix |
| // End: |