about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librbml/lib.rs636
-rw-r--r--src/librustc/metadata/common.rs280
-rw-r--r--src/librustc/metadata/encoder.rs280
-rw-r--r--src/librustc/metadata/tyencode.rs68
-rw-r--r--src/librustc/middle/astencode.rs118
5 files changed, 758 insertions, 624 deletions
diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs
index 05cd24de736..844d097bdaf 100644
--- a/src/librbml/lib.rs
+++ b/src/librbml/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,12 +8,108 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Really Bad Markup Language (rbml) is a temporary measure until we migrate
-//! the rust object metadata to a better serialization format. It is not
-//! intended to be used by users.
+//! Really Bad Markup Language (rbml) is an internal serialization format of rustc.
+//! This is not intended to be used by users.
 //!
-//! It is loosely based on the Extensible Binary Markup Language (ebml):
-//!     http://www.matroska.org/technical/specs/rfc/index.html
+//! Originally based on the Extensible Binary Markup Language
+//! (ebml; http://www.matroska.org/technical/specs/rfc/index.html),
+//! it is now a separate format tuned for the rust object metadata.
+//!
+//! # Encoding
+//!
+//! RBML document consists of the tag, length and data.
+//! The encoded data can contain multiple RBML documents concatenated.
+//!
+//! **Tags** are a hint for the following data.
+//! Tags are a number from 0x000 to 0xfff, where 0xf0 through 0xff is reserved.
+//! Tags less than 0xf0 are encoded in one literal byte.
+//! Tags greater than 0xff are encoded in two big-endian bytes,
+//! where the tag number is ORed with 0xf000. (E.g. tag 0x123 = `f1 23`)
+//!
+//! **Lengths** encode the length of the following data.
+//! It is a variable-length unsigned int, and one of the following forms:
+//!
+//! - `80` through `fe` for lengths up to 0x7e;
+//! - `40 ff` through `7f ff` for lengths up to 0x3fff;
+//! - `20 40 00` through `3f ff ff` for lengths up to 0x1fffff;
+//! - `10 20 00 00` through `1f ff ff ff` for lengths up to 0xfffffff.
+//!
+//! The "overlong" form is allowed so that the length can be encoded
+//! without the prior knowledge of the encoded data.
+//! For example, the length 0 can be represented either by `80`, `40 00`,
+//! `20 00 00` or `10 00 00 00`.
+//! The encoder tries to minimize the length if possible.
+//! Also, some predefined tags listed below are so commonly used that
+//! their lengths are omitted ("implicit length").
+//!
+//! **Data** can be either binary bytes or zero or more nested RBML documents.
+//! Nested documents cannot overflow, and should be entirely contained
+//! within a parent document.
+//!
+//! # Predefined Tags
+//!
+//! Most RBML tags are defined by the application.
+//! (For the rust object metadata, see also `rustc::metadata::common`.)
+//! RBML itself does define a set of predefined tags however,
+//! intended for the auto-serialization implementation.
+//!
+//! Predefined tags with an implicit length:
+//!
+//! - `U8`  (`00`): 1-byte unsigned integer.
+//! - `U16` (`01`): 2-byte big endian unsigned integer.
+//! - `U32` (`02`): 4-byte big endian unsigned integer.
+//! - `U64` (`03`): 8-byte big endian unsigned integer.
+//!   Any of `U*` tags can be used to encode primitive unsigned integer types,
+//!   as long as it is no greater than the actual size.
+//!   For example, `u8` can only be represented via the `U8` tag.
+//!
+//! - `I8`  (`04`): 1-byte signed integer.
+//! - `I16` (`05`): 2-byte big endian signed integer.
+//! - `I32` (`06`): 4-byte big endian signed integer.
+//! - `I64` (`07`): 8-byte big endian signed integer.
+//!   Similar to `U*` tags. Always uses two's complement encoding.
+//!
+//! - `Bool` (`08`): 1-byte boolean value, `00` for false and `01` for true.
+//!
+//! - `Char` (`09`): 4-byte big endian Unicode scalar value.
+//!   Surrogate pairs or out-of-bound values are invalid.
+//!
+//! - `F32` (`0a`): 4-byte big endian unsigned integer representing
+//!   IEEE 754 binary32 floating-point format.
+//! - `F64` (`0b`): 8-byte big endian unsigned integer representing
+//!   IEEE 754 binary64 floating-point format.
+//!
+//! - `Sub8`  (`0c`): 1-byte unsigned integer for supplementary information.
+//! - `Sub32` (`0d`): 4-byte unsigned integer for supplementary information.
+//!   Those two tags normally occur as the first subdocument of certain tags,
+//!   namely `Enum`, `Vec` and `Map`, to provide a variant or size information.
+//!   They can be used interchangably.
+//!
+//! Predefined tags with an explicit length:
+//!
+//! - `Str` (`10`): A UTF-8-encoded string.
+//!
+//! - `Enum` (`11`): An enum.
+//!   The first subdocument should be `Sub*` tags with a variant ID.
+//!   Subsequent subdocuments, if any, encode variant arguments.
+//!
+//! - `Vec` (`12`): A vector (sequence).
+//! - `VecElt` (`13`): A vector element.
+//!   The first subdocument should be `Sub*` tags with the number of elements.
+//!   Subsequent subdocuments should be `VecElt` tag per each element.
+//!
+//! - `Map` (`14`): A map (associated array).
+//! - `MapKey` (`15`): A key part of the map entry.
+//! - `MapVal` (`16`): A value part of the map entry.
+//!   The first subdocument should be `Sub*` tags with the number of entries.
+//!   Subsequent subdocuments should be an alternating sequence of
+//!   `MapKey` and `MapVal` tags per each entry.
+//!
+//! - `Opaque` (`17`): An opaque, custom-format tag.
+//!   Used to wrap ordinary custom tags or data in the auto-serialized context.
+//!   Rustc typically uses this to encode type informations.
+//!
+//! First 0x20 tags are reserved by RBML; custom tags start at 0x20.
 
 #![crate_name = "rbml"]
 #![unstable(feature = "rustc_private")]
@@ -64,6 +160,10 @@ impl<'doc> Doc<'doc> {
         reader::get_doc(*self, tag)
     }
 
+    pub fn is_empty(&self) -> bool {
+        self.start == self.end
+    }
+
     pub fn as_str_slice<'a>(&'a self) -> &'a str {
         str::from_utf8(&self.data[self.start..self.end]).unwrap()
     }
@@ -80,41 +180,51 @@ pub struct TaggedDoc<'a> {
 
 #[derive(Copy, Debug)]
 pub enum EbmlEncoderTag {
-    EsUint,     // 0
-    EsU64,      // 1
-    EsU32,      // 2
-    EsU16,      // 3
-    EsU8,       // 4
-    EsInt,      // 5
-    EsI64,      // 6
-    EsI32,      // 7
-    EsI16,      // 8
-    EsI8,       // 9
-    EsBool,     // 10
-    EsChar,     // 11
-    EsStr,      // 12
-    EsF64,      // 13
-    EsF32,      // 14
-    EsFloat,    // 15
-    EsEnum,     // 16
-    EsEnumVid,  // 17
-    EsEnumBody, // 18
-    EsVec,      // 19
-    EsVecLen,   // 20
-    EsVecElt,   // 21
-    EsMap,      // 22
-    EsMapLen,   // 23
-    EsMapKey,   // 24
-    EsMapVal,   // 25
-
-    EsOpaque,
-
-    EsLabel, // Used only when debugging
+    // tags 00..1f are reserved for auto-serialization.
+    // first NUM_IMPLICIT_TAGS tags are implicitly sized and lengths are not encoded.
+
+    EsU8       = 0x00, // + 1 byte
+    EsU16      = 0x01, // + 2 bytes
+    EsU32      = 0x02, // + 4 bytes
+    EsU64      = 0x03, // + 8 bytes
+    EsI8       = 0x04, // + 1 byte
+    EsI16      = 0x05, // + 2 bytes
+    EsI32      = 0x06, // + 4 bytes
+    EsI64      = 0x07, // + 8 bytes
+    EsBool     = 0x08, // + 1 byte
+    EsChar     = 0x09, // + 4 bytes
+    EsF32      = 0x0a, // + 4 bytes
+    EsF64      = 0x0b, // + 8 bytes
+    EsSub8     = 0x0c, // + 1 byte
+    EsSub32    = 0x0d, // + 4 bytes
+    // 0x0e and 0x0f are reserved
+
+    EsStr      = 0x10,
+    EsEnum     = 0x11, // encodes the variant id as the first EsSub*
+    EsVec      = 0x12, // encodes the # of elements as the first EsSub*
+    EsVecElt   = 0x13,
+    EsMap      = 0x14, // encodes the # of pairs as the first EsSub*
+    EsMapKey   = 0x15,
+    EsMapVal   = 0x16,
+    EsOpaque   = 0x17,
 }
 
+const NUM_TAGS: uint = 0x1000;
+const NUM_IMPLICIT_TAGS: uint = 0x0e;
+
+static TAG_IMPLICIT_LEN: [i8; NUM_IMPLICIT_TAGS] = [
+    1, 2, 4, 8, // EsU*
+    1, 2, 4, 8, // ESI*
+    1, // EsBool
+    4, // EsChar
+    4, 8, // EsF*
+    1, 4, // EsSub*
+];
+
 #[derive(Debug)]
 pub enum Error {
     IntTooBig(uint),
+    InvalidTag(uint),
     Expected(String),
     IoError(std::old_io::IoError),
     ApplicationError(String)
@@ -138,11 +248,11 @@ pub mod reader {
 
     use serialize;
 
-    use super::{ ApplicationError, EsVec, EsMap, EsEnum, EsVecLen, EsVecElt,
-        EsMapLen, EsMapKey, EsEnumVid, EsU64, EsU32, EsU16, EsU8, EsInt, EsI64,
+    use super::{ ApplicationError, EsVec, EsMap, EsEnum, EsSub8, EsSub32,
+        EsVecElt, EsMapKey, EsU64, EsU32, EsU16, EsU8, EsI64,
         EsI32, EsI16, EsI8, EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal,
-        EsEnumBody, EsUint, EsOpaque, EsLabel, EbmlEncoderTag, Doc, TaggedDoc,
-        Error, IntTooBig, Expected };
+        EsOpaque, EbmlEncoderTag, Doc, TaggedDoc,
+        Error, IntTooBig, InvalidTag, Expected, NUM_IMPLICIT_TAGS, TAG_IMPLICIT_LEN };
 
     pub type DecodeResult<T> = Result<T, Error>;
     // rbml reading
@@ -165,6 +275,18 @@ pub mod reader {
         pub next: uint
     }
 
+    pub fn tag_at(data: &[u8], start: uint) -> DecodeResult<Res> {
+        let v = data[start] as uint;
+        if v < 0xf0 {
+            Ok(Res { val: v, next: start + 1 })
+        } else if v > 0xf0 {
+            Ok(Res { val: ((v & 0xf) << 8) | data[start + 1] as uint, next: start + 2 })
+        } else {
+            // every tag starting with byte 0xf0 is an overlong form, which is prohibited.
+            Err(InvalidTag(v))
+        }
+    }
+
     #[inline(never)]
     fn vuint_at_slow(data: &[u8], start: uint) -> DecodeResult<Res> {
         let a = data[start];
@@ -237,9 +359,17 @@ pub mod reader {
         }
     }
 
+    pub fn tag_len_at(data: &[u8], tag: Res) -> DecodeResult<Res> {
+        if tag.val < NUM_IMPLICIT_TAGS && TAG_IMPLICIT_LEN[tag.val] >= 0 {
+            Ok(Res { val: TAG_IMPLICIT_LEN[tag.val] as uint, next: tag.next })
+        } else {
+            vuint_at(data, tag.next)
+        }
+    }
+
     pub fn doc_at<'a>(data: &'a [u8], start: uint) -> DecodeResult<TaggedDoc<'a>> {
-        let elt_tag = try!(vuint_at(data, start));
-        let elt_size = try!(vuint_at(data, elt_tag.next));
+        let elt_tag = try!(tag_at(data, start));
+        let elt_size = try!(tag_len_at(data, elt_tag));
         let end = elt_size.next + elt_size.val;
         Ok(TaggedDoc {
             tag: elt_tag.val,
@@ -250,8 +380,8 @@ pub mod reader {
     pub fn maybe_get_doc<'a>(d: Doc<'a>, tg: uint) -> Option<Doc<'a>> {
         let mut pos = d.start;
         while pos < d.end {
-            let elt_tag = try_or!(vuint_at(d.data, pos), None);
-            let elt_size = try_or!(vuint_at(d.data, elt_tag.next), None);
+            let elt_tag = try_or!(tag_at(d.data, pos), None);
+            let elt_size = try_or!(tag_len_at(d.data, elt_tag), None);
             pos = elt_size.next + elt_size.val;
             if elt_tag.val == tg {
                 return Some(Doc { data: d.data, start: elt_size.next,
@@ -276,8 +406,8 @@ pub mod reader {
     {
         let mut pos = d.start;
         while pos < d.end {
-            let elt_tag = try_or!(vuint_at(d.data, pos), false);
-            let elt_size = try_or!(vuint_at(d.data, elt_tag.next), false);
+            let elt_tag = try_or!(tag_at(d.data, pos), false);
+            let elt_size = try_or!(tag_len_at(d.data, elt_tag), false);
             pos = elt_size.next + elt_size.val;
             let doc = Doc { data: d.data, start: elt_size.next, end: pos };
             if !it(elt_tag.val, doc) {
@@ -292,8 +422,8 @@ pub mod reader {
     {
         let mut pos = d.start;
         while pos < d.end {
-            let elt_tag = try_or!(vuint_at(d.data, pos), false);
-            let elt_size = try_or!(vuint_at(d.data, elt_tag.next), false);
+            let elt_tag = try_or!(tag_at(d.data, pos), false);
+            let elt_size = try_or!(tag_len_at(d.data, elt_tag), false);
             pos = elt_size.next + elt_size.val;
             if elt_tag.val == tg {
                 let doc = Doc { data: d.data, start: elt_size.next,
@@ -357,23 +487,6 @@ pub mod reader {
             }
         }
 
-        fn _check_label(&mut self, lbl: &str) -> DecodeResult<()> {
-            if self.pos < self.parent.end {
-                let TaggedDoc { tag: r_tag, doc: r_doc } =
-                    try!(doc_at(self.parent.data, self.pos));
-
-                if r_tag == (EsLabel as uint) {
-                    self.pos = r_doc.end;
-                    let str = r_doc.as_str_slice();
-                    if lbl != str {
-                        return Err(Expected(format!("Expected label {:?} but \
-                                                     found {:?}", lbl, str)));
-                    }
-                }
-            }
-            Ok(())
-        }
-
         fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> DecodeResult<Doc<'doc>> {
             debug!(". next_doc(exp_tag={:?})", exp_tag);
             if self.pos >= self.parent.end {
@@ -416,10 +529,66 @@ pub mod reader {
             Ok(r)
         }
 
-        fn _next_uint(&mut self, exp_tag: EbmlEncoderTag) -> DecodeResult<uint> {
-            let r = doc_as_u32(try!(self.next_doc(exp_tag)));
-            debug!("_next_uint exp_tag={:?} result={:?}", exp_tag, r);
-            Ok(r as uint)
+        fn _next_sub(&mut self) -> DecodeResult<uint> {
+            // empty vector/map optimization
+            if self.parent.is_empty() {
+                return Ok(0);
+            }
+
+            let TaggedDoc { tag: r_tag, doc: r_doc } =
+                try!(doc_at(self.parent.data, self.pos));
+            let r = if r_tag == (EsSub8 as uint) {
+                doc_as_u8(r_doc) as uint
+            } else if r_tag == (EsSub32 as uint) {
+                doc_as_u32(r_doc) as uint
+            } else {
+                return Err(Expected(format!("expected EBML doc with tag {:?} or {:?} but \
+                                             found tag {:?}", EsSub8, EsSub32, r_tag)));
+            };
+            if r_doc.end > self.parent.end {
+                return Err(Expected(format!("invalid EBML, child extends to \
+                                             {:#x}, parent to {:#x}",
+                                            r_doc.end, self.parent.end)));
+            }
+            self.pos = r_doc.end;
+            debug!("_next_sub result={:?}", r);
+            Ok(r)
+        }
+
+        // variable-length unsigned integer with different tags.
+        // `first_tag` should be a tag for u8 or i8.
+        // `last_tag` should be the largest allowed integer tag with the matching signedness.
+        // all tags between them should be valid, in the order of u8, u16, u32 and u64.
+        fn _next_int(&mut self,
+                     first_tag: EbmlEncoderTag,
+                     last_tag: EbmlEncoderTag) -> DecodeResult<u64> {
+            if self.pos >= self.parent.end {
+                return Err(Expected(format!("no more documents in \
+                                             current node!")));
+            }
+
+            let TaggedDoc { tag: r_tag, doc: r_doc } =
+                try!(doc_at(self.parent.data, self.pos));
+            let r = if first_tag as uint <= r_tag && r_tag <= last_tag as uint {
+                match r_tag - first_tag as uint {
+                    0 => doc_as_u8(r_doc) as u64,
+                    1 => doc_as_u16(r_doc) as u64,
+                    2 => doc_as_u32(r_doc) as u64,
+                    3 => doc_as_u64(r_doc) as u64,
+                    _ => unreachable!(),
+                }
+            } else {
+                return Err(Expected(format!("expected EBML doc with tag {:?} through {:?} but \
+                                             found tag {:?}", first_tag, last_tag, r_tag)));
+            };
+            if r_doc.end > self.parent.end {
+                return Err(Expected(format!("invalid EBML, child extends to \
+                                             {:#x}, parent to {:#x}",
+                                            r_doc.end, self.parent.end)));
+            }
+            self.pos = r_doc.end;
+            debug!("_next_int({:?}, {:?}) result={:?}", first_tag, last_tag, r);
+            Ok(r)
         }
 
         pub fn read_opaque<R, F>(&mut self, op: F) -> DecodeResult<R> where
@@ -443,12 +612,12 @@ pub mod reader {
         type Error = Error;
         fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) }
 
-        fn read_u64(&mut self) -> DecodeResult<u64> { Ok(doc_as_u64(try!(self.next_doc(EsU64)))) }
-        fn read_u32(&mut self) -> DecodeResult<u32> { Ok(doc_as_u32(try!(self.next_doc(EsU32)))) }
-        fn read_u16(&mut self) -> DecodeResult<u16> { Ok(doc_as_u16(try!(self.next_doc(EsU16)))) }
-        fn read_u8 (&mut self) -> DecodeResult<u8 > { Ok(doc_as_u8 (try!(self.next_doc(EsU8 )))) }
+        fn read_u64(&mut self) -> DecodeResult<u64> { self._next_int(EsU8, EsU64) }
+        fn read_u32(&mut self) -> DecodeResult<u32> { Ok(try!(self._next_int(EsU8, EsU32)) as u32) }
+        fn read_u16(&mut self) -> DecodeResult<u16> { Ok(try!(self._next_int(EsU8, EsU16)) as u16) }
+        fn read_u8(&mut self) -> DecodeResult<u8> { Ok(doc_as_u8(try!(self.next_doc(EsU8)))) }
         fn read_uint(&mut self) -> DecodeResult<uint> {
-            let v = doc_as_u64(try!(self.next_doc(EsUint)));
+            let v = try!(self._next_int(EsU8, EsU64));
             if v > (::std::usize::MAX as u64) {
                 Err(IntTooBig(v as uint))
             } else {
@@ -456,20 +625,12 @@ pub mod reader {
             }
         }
 
-        fn read_i64(&mut self) -> DecodeResult<i64> {
-            Ok(doc_as_u64(try!(self.next_doc(EsI64))) as i64)
-        }
-        fn read_i32(&mut self) -> DecodeResult<i32> {
-            Ok(doc_as_u32(try!(self.next_doc(EsI32))) as i32)
-        }
-        fn read_i16(&mut self) -> DecodeResult<i16> {
-            Ok(doc_as_u16(try!(self.next_doc(EsI16))) as i16)
-        }
-        fn read_i8 (&mut self) -> DecodeResult<i8> {
-            Ok(doc_as_u8(try!(self.next_doc(EsI8 ))) as i8)
-        }
+        fn read_i64(&mut self) -> DecodeResult<i64> { Ok(try!(self._next_int(EsI8, EsI64)) as i64) }
+        fn read_i32(&mut self) -> DecodeResult<i32> { Ok(try!(self._next_int(EsI8, EsI32)) as i32) }
+        fn read_i16(&mut self) -> DecodeResult<i16> { Ok(try!(self._next_int(EsI8, EsI16)) as i16) }
+        fn read_i8(&mut self) -> DecodeResult<i8> { Ok(doc_as_u8(try!(self.next_doc(EsI8))) as i8) }
         fn read_int(&mut self) -> DecodeResult<int> {
-            let v = doc_as_u64(try!(self.next_doc(EsInt))) as i64;
+            let v = try!(self._next_int(EsI8, EsI64)) as i64;
             if v > (isize::MAX as i64) || v < (isize::MIN as i64) {
                 debug!("FIXME \\#6122: Removing this makes this function miscompile");
                 Err(IntTooBig(v as uint))
@@ -502,7 +663,6 @@ pub mod reader {
             F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
         {
             debug!("read_enum({})", name);
-            try!(self._check_label(name));
 
             let doc = try!(self.next_doc(EsEnum));
 
@@ -522,20 +682,10 @@ pub mod reader {
             where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult<T>,
         {
             debug!("read_enum_variant()");
-            let idx = try!(self._next_uint(EsEnumVid));
+            let idx = try!(self._next_sub());
             debug!("  idx={}", idx);
 
-            let doc = try!(self.next_doc(EsEnumBody));
-
-            let (old_parent, old_pos) = (self.parent, self.pos);
-            self.parent = doc;
-            self.pos = self.parent.start;
-
-            let result = try!(f(self, idx));
-
-            self.parent = old_parent;
-            self.pos = old_pos;
-            Ok(result)
+            f(self, idx)
         }
 
         fn read_enum_variant_arg<T, F>(&mut self, idx: uint, f: F) -> DecodeResult<T> where
@@ -550,20 +700,10 @@ pub mod reader {
             where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult<T>,
         {
             debug!("read_enum_struct_variant()");
-            let idx = try!(self._next_uint(EsEnumVid));
+            let idx = try!(self._next_sub());
             debug!("  idx={}", idx);
 
-            let doc = try!(self.next_doc(EsEnumBody));
-
-            let (old_parent, old_pos) = (self.parent, self.pos);
-            self.parent = doc;
-            self.pos = self.parent.start;
-
-            let result = try!(f(self, idx));
-
-            self.parent = old_parent;
-            self.pos = old_pos;
-            Ok(result)
+            f(self, idx)
         }
 
         fn read_enum_struct_variant_field<T, F>(&mut self,
@@ -588,7 +728,6 @@ pub mod reader {
             F: FnOnce(&mut Decoder<'doc>) -> DecodeResult<T>,
         {
             debug!("read_struct_field(name={}, idx={})", name, idx);
-            try!(self._check_label(name));
             f(self)
         }
 
@@ -652,7 +791,7 @@ pub mod reader {
         {
             debug!("read_seq()");
             self.push_doc(EsVec, move |d| {
-                let len = try!(d._next_uint(EsVecLen));
+                let len = try!(d._next_sub());
                 debug!("  len={}", len);
                 f(d, len)
             })
@@ -670,7 +809,7 @@ pub mod reader {
         {
             debug!("read_map()");
             self.push_doc(EsMap, move |d| {
-                let len = try!(d._next_uint(EsMapLen));
+                let len = try!(d._next_sub());
                 debug!("  len={}", len);
                 f(d, len)
             })
@@ -701,11 +840,14 @@ pub mod writer {
     use std::num::Int;
     use std::old_io::{Writer, Seek};
     use std::old_io;
+    use std::slice::bytes;
+    use std::num::ToPrimitive;
 
-    use super::{ EsVec, EsMap, EsEnum, EsVecLen, EsVecElt, EsMapLen, EsMapKey,
-        EsEnumVid, EsU64, EsU32, EsU16, EsU8, EsInt, EsI64, EsI32, EsI16, EsI8,
-        EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal, EsEnumBody, EsUint,
-        EsOpaque, EsLabel, EbmlEncoderTag };
+    use super::{ EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey,
+        EsU64, EsU32, EsU16, EsU8, EsI64, EsI32, EsI16, EsI8,
+        EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal,
+        EsOpaque, NUM_IMPLICIT_TAGS, NUM_TAGS };
+    use super::io::SeekableMemWriter;
 
     use serialize;
 
@@ -713,9 +855,24 @@ pub mod writer {
     pub type EncodeResult = old_io::IoResult<()>;
 
     // rbml writing
-    pub struct Encoder<'a, W:'a> {
-        pub writer: &'a mut W,
+    pub struct Encoder<'a> {
+        pub writer: &'a mut SeekableMemWriter,
         size_positions: Vec<uint>,
+        relax_limit: u64, // do not move encoded bytes before this position
+    }
+
+    fn write_tag<W: Writer>(w: &mut W, n: uint) -> EncodeResult {
+        if n < 0xf0 {
+            w.write_all(&[n as u8])
+        } else if 0x100 <= n && n < NUM_TAGS {
+            w.write_all(&[0xf0 | (n >> 8) as u8, n as u8])
+        } else {
+            Err(old_io::IoError {
+                kind: old_io::OtherIoError,
+                desc: "invalid tag",
+                detail: Some(format!("{}", n))
+            })
+        }
     }
 
     fn write_sized_vuint<W: Writer>(w: &mut W, n: uint, size: uint) -> EncodeResult {
@@ -746,27 +903,30 @@ pub mod writer {
         })
     }
 
-    impl<'a, W: Writer + Seek> Encoder<'a, W> {
-        pub fn new(w: &'a mut W) -> Encoder<'a, W> {
+    impl<'a> Encoder<'a> {
+        pub fn new(w: &'a mut SeekableMemWriter) -> Encoder<'a> {
             Encoder {
                 writer: w,
                 size_positions: vec!(),
+                relax_limit: 0,
             }
         }
 
         /// FIXME(pcwalton): Workaround for badness in trans. DO NOT USE ME.
-        pub unsafe fn unsafe_clone(&self) -> Encoder<'a, W> {
+        pub unsafe fn unsafe_clone(&self) -> Encoder<'a> {
             Encoder {
                 writer: mem::transmute_copy(&self.writer),
                 size_positions: self.size_positions.clone(),
+                relax_limit: self.relax_limit,
             }
         }
 
         pub fn start_tag(&mut self, tag_id: uint) -> EncodeResult {
             debug!("Start tag {:?}", tag_id);
+            assert!(tag_id >= NUM_IMPLICIT_TAGS);
 
             // Write the enum ID:
-            try!(write_vuint(self.writer, tag_id));
+            try!(write_tag(self.writer, tag_id));
 
             // Write a placeholder four-byte size.
             self.size_positions.push(try!(self.writer.tell()) as uint);
@@ -779,11 +939,29 @@ pub mod writer {
             let cur_pos = try!(self.writer.tell());
             try!(self.writer.seek(last_size_pos as i64, old_io::SeekSet));
             let size = cur_pos as uint - last_size_pos - 4;
-            try!(write_sized_vuint(self.writer, size, 4));
-            let r = try!(self.writer.seek(cur_pos as i64, old_io::SeekSet));
+
+            // relax the size encoding for small tags (bigger tags are costly to move).
+            // we should never try to move the stable positions, however.
+            const RELAX_MAX_SIZE: uint = 0x100;
+            if size <= RELAX_MAX_SIZE && last_size_pos >= self.relax_limit as uint {
+                // we can't alter the buffer in place, so have a temporary buffer
+                let mut buf = [0u8; RELAX_MAX_SIZE];
+                {
+                    let data = &self.writer.get_ref()[last_size_pos+4..cur_pos as uint];
+                    bytes::copy_memory(&mut buf, data);
+                }
+
+                // overwrite the size and data and continue
+                try!(write_vuint(self.writer, size));
+                try!(self.writer.write_all(&buf[..size]));
+            } else {
+                // overwrite the size with an overlong encoding and skip past the data
+                try!(write_sized_vuint(self.writer, size, 4));
+                try!(self.writer.seek(cur_pos as i64, old_io::SeekSet));
+            }
 
             debug!("End tag (size = {:?})", size);
-            Ok(r)
+            Ok(())
         }
 
         pub fn wr_tag<F>(&mut self, tag_id: uint, blk: F) -> EncodeResult where
@@ -795,7 +973,8 @@ pub mod writer {
         }
 
         pub fn wr_tagged_bytes(&mut self, tag_id: uint, b: &[u8]) -> EncodeResult {
-            try!(write_vuint(self.writer, tag_id));
+            assert!(tag_id >= NUM_IMPLICIT_TAGS);
+            try!(write_tag(self.writer, tag_id));
             try!(write_vuint(self.writer, b.len()));
             self.writer.write_all(b)
         }
@@ -839,6 +1018,47 @@ pub mod writer {
             self.wr_tagged_bytes(tag_id, v.as_bytes())
         }
 
+        // for auto-serialization
+        fn wr_tagged_raw_bytes(&mut self, tag_id: uint, b: &[u8]) -> EncodeResult {
+            try!(write_tag(self.writer, tag_id));
+            self.writer.write_all(b)
+        }
+
+        fn wr_tagged_raw_u64(&mut self, tag_id: uint, v: u64) -> EncodeResult {
+            let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) };
+            self.wr_tagged_raw_bytes(tag_id, &bytes)
+        }
+
+        fn wr_tagged_raw_u32(&mut self, tag_id: uint, v: u32)  -> EncodeResult{
+            let bytes: [u8; 4] = unsafe { mem::transmute(v.to_be()) };
+            self.wr_tagged_raw_bytes(tag_id, &bytes)
+        }
+
+        fn wr_tagged_raw_u16(&mut self, tag_id: uint, v: u16) -> EncodeResult {
+            let bytes: [u8; 2] = unsafe { mem::transmute(v.to_be()) };
+            self.wr_tagged_raw_bytes(tag_id, &bytes)
+        }
+
+        fn wr_tagged_raw_u8(&mut self, tag_id: uint, v: u8) -> EncodeResult {
+            self.wr_tagged_raw_bytes(tag_id, &[v])
+        }
+
+        fn wr_tagged_raw_i64(&mut self, tag_id: uint, v: i64) -> EncodeResult {
+            self.wr_tagged_raw_u64(tag_id, v as u64)
+        }
+
+        fn wr_tagged_raw_i32(&mut self, tag_id: uint, v: i32) -> EncodeResult {
+            self.wr_tagged_raw_u32(tag_id, v as u32)
+        }
+
+        fn wr_tagged_raw_i16(&mut self, tag_id: uint, v: i16) -> EncodeResult {
+            self.wr_tagged_raw_u16(tag_id, v as u16)
+        }
+
+        fn wr_tagged_raw_i8(&mut self, tag_id: uint, v: i8) -> EncodeResult {
+            self.wr_tagged_raw_bytes(tag_id, &[v as u8])
+        }
+
         pub fn wr_bytes(&mut self, b: &[u8]) -> EncodeResult {
             debug!("Write {:?} bytes", b.len());
             self.writer.write_all(b)
@@ -848,38 +1068,36 @@ pub mod writer {
             debug!("Write str: {:?}", s);
             self.writer.write_all(s.as_bytes())
         }
-    }
-
-    // FIXME (#2743): optionally perform "relaxations" on end_tag to more
-    // efficiently encode sizes; this is a fixed point iteration
-
-    // Set to true to generate more debugging in EBML code.
-    // Totally lame approach.
-    #[cfg(not(ndebug))]
-    static DEBUG: bool = true;
-    #[cfg(ndebug)]
-    static DEBUG: bool = false;
 
-    impl<'a, W: Writer + Seek> Encoder<'a, W> {
-        // used internally to emit things like the vector length and so on
-        fn _emit_tagged_uint(&mut self, t: EbmlEncoderTag, v: uint) -> EncodeResult {
-            assert!(v <= 0xFFFF_FFFF);
-            self.wr_tagged_u32(t as uint, v as u32)
+        /// Returns the current position while marking it stable, i.e.
+        /// generated bytes so far woundn't be affected by relaxation.
+        pub fn mark_stable_position(&mut self) -> u64 {
+            let pos = self.writer.tell().unwrap();
+            if self.relax_limit < pos {
+                self.relax_limit = pos;
+            }
+            pos
         }
+    }
 
-        fn _emit_label(&mut self, label: &str) -> EncodeResult {
-            // There are various strings that we have access to, such as
-            // the name of a record field, which do not actually appear in
-            // the encoded EBML (normally).  This is just for
-            // efficiency.  When debugging, though, we can emit such
-            // labels and then they will be checked by decoder to
-            // try and check panics more quickly.
-            if DEBUG { self.wr_tagged_str(EsLabel as uint, label) }
-            else { Ok(()) }
+    impl<'a> Encoder<'a> {
+        // used internally to emit things like the vector length and so on
+        fn _emit_tagged_sub(&mut self, v: uint) -> EncodeResult {
+            if let Some(v) = v.to_u8() {
+                self.wr_tagged_raw_u8(EsSub8 as uint, v)
+            } else if let Some(v) = v.to_u32() {
+                self.wr_tagged_raw_u32(EsSub32 as uint, v)
+            } else {
+                Err(old_io::IoError {
+                    kind: old_io::OtherIoError,
+                    desc: "length or variant id too big",
+                    detail: Some(format!("{}", v))
+                })
+            }
         }
 
         pub fn emit_opaque<F>(&mut self, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder) -> EncodeResult,
         {
             try!(self.start_tag(EsOpaque as uint));
             try!(f(self));
@@ -887,7 +1105,7 @@ pub mod writer {
         }
     }
 
-    impl<'a, W: Writer + Seek> serialize::Encoder for Encoder<'a, W> {
+    impl<'a> serialize::Encoder for Encoder<'a> {
         type Error = old_io::IoError;
 
         fn emit_nil(&mut self) -> EncodeResult {
@@ -895,61 +1113,78 @@ pub mod writer {
         }
 
         fn emit_uint(&mut self, v: uint) -> EncodeResult {
-            self.wr_tagged_u64(EsUint as uint, v as u64)
+            self.emit_u64(v as u64)
         }
         fn emit_u64(&mut self, v: u64) -> EncodeResult {
-            self.wr_tagged_u64(EsU64 as uint, v)
+            match v.to_u32() {
+                Some(v) => self.emit_u32(v),
+                None => self.wr_tagged_raw_u64(EsU64 as uint, v)
+            }
         }
         fn emit_u32(&mut self, v: u32) -> EncodeResult {
-            self.wr_tagged_u32(EsU32 as uint, v)
+            match v.to_u16() {
+                Some(v) => self.emit_u16(v),
+                None => self.wr_tagged_raw_u32(EsU32 as uint, v)
+            }
         }
         fn emit_u16(&mut self, v: u16) -> EncodeResult {
-            self.wr_tagged_u16(EsU16 as uint, v)
+            match v.to_u8() {
+                Some(v) => self.emit_u8(v),
+                None => self.wr_tagged_raw_u16(EsU16 as uint, v)
+            }
         }
         fn emit_u8(&mut self, v: u8) -> EncodeResult {
-            self.wr_tagged_u8(EsU8 as uint, v)
+            self.wr_tagged_raw_u8(EsU8 as uint, v)
         }
 
         fn emit_int(&mut self, v: int) -> EncodeResult {
-            self.wr_tagged_i64(EsInt as uint, v as i64)
+            self.emit_i64(v as i64)
         }
         fn emit_i64(&mut self, v: i64) -> EncodeResult {
-            self.wr_tagged_i64(EsI64 as uint, v)
+            match v.to_i32() {
+                Some(v) => self.emit_i32(v),
+                None => self.wr_tagged_raw_i64(EsI64 as uint, v)
+            }
         }
         fn emit_i32(&mut self, v: i32) -> EncodeResult {
-            self.wr_tagged_i32(EsI32 as uint, v)
+            match v.to_i16() {
+                Some(v) => self.emit_i16(v),
+                None => self.wr_tagged_raw_i32(EsI32 as uint, v)
+            }
         }
         fn emit_i16(&mut self, v: i16) -> EncodeResult {
-            self.wr_tagged_i16(EsI16 as uint, v)
+            match v.to_i8() {
+                Some(v) => self.emit_i8(v),
+                None => self.wr_tagged_raw_i16(EsI16 as uint, v)
+            }
         }
         fn emit_i8(&mut self, v: i8) -> EncodeResult {
-            self.wr_tagged_i8(EsI8 as uint, v)
+            self.wr_tagged_raw_i8(EsI8 as uint, v)
         }
 
         fn emit_bool(&mut self, v: bool) -> EncodeResult {
-            self.wr_tagged_u8(EsBool as uint, v as u8)
+            self.wr_tagged_raw_u8(EsBool as uint, v as u8)
         }
 
         fn emit_f64(&mut self, v: f64) -> EncodeResult {
             let bits = unsafe { mem::transmute(v) };
-            self.wr_tagged_u64(EsF64 as uint, bits)
+            self.wr_tagged_raw_u64(EsF64 as uint, bits)
         }
         fn emit_f32(&mut self, v: f32) -> EncodeResult {
             let bits = unsafe { mem::transmute(v) };
-            self.wr_tagged_u32(EsF32 as uint, bits)
+            self.wr_tagged_raw_u32(EsF32 as uint, bits)
         }
         fn emit_char(&mut self, v: char) -> EncodeResult {
-            self.wr_tagged_u32(EsChar as uint, v as u32)
+            self.wr_tagged_raw_u32(EsChar as uint, v as u32)
         }
 
         fn emit_str(&mut self, v: &str) -> EncodeResult {
             self.wr_tagged_str(EsStr as uint, v)
         }
 
-        fn emit_enum<F>(&mut self, name: &str, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+        fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
-            try!(self._emit_label(name));
             try!(self.start_tag(EsEnum as uint));
             try!(f(self));
             self.end_tag()
@@ -960,16 +1195,14 @@ pub mod writer {
                                 v_id: uint,
                                 _: uint,
                                 f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
-            try!(self._emit_tagged_uint(EsEnumVid, v_id));
-            try!(self.start_tag(EsEnumBody as uint));
-            try!(f(self));
-            self.end_tag()
+            try!(self._emit_tagged_sub(v_id));
+            f(self)
         }
 
         fn emit_enum_variant_arg<F>(&mut self, _: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
             f(self)
         }
@@ -979,7 +1212,7 @@ pub mod writer {
                                        v_id: uint,
                                        cnt: uint,
                                        f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
             self.emit_enum_variant(v_name, v_id, cnt, f)
         }
@@ -988,48 +1221,47 @@ pub mod writer {
                                              _: &str,
                                              idx: uint,
                                              f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
             self.emit_enum_variant_arg(idx, f)
         }
 
         fn emit_struct<F>(&mut self, _: &str, _len: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
             f(self)
         }
 
-        fn emit_struct_field<F>(&mut self, name: &str, _: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+        fn emit_struct_field<F>(&mut self, _name: &str, _: uint, f: F) -> EncodeResult where
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
-            try!(self._emit_label(name));
             f(self)
         }
 
         fn emit_tuple<F>(&mut self, len: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
             self.emit_seq(len, f)
         }
         fn emit_tuple_arg<F>(&mut self, idx: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
             self.emit_seq_elt(idx, f)
         }
 
         fn emit_tuple_struct<F>(&mut self, _: &str, len: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
             self.emit_seq(len, f)
         }
         fn emit_tuple_struct_arg<F>(&mut self, idx: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
             self.emit_seq_elt(idx, f)
         }
 
         fn emit_option<F>(&mut self, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
             self.emit_enum("Option", f)
         }
@@ -1037,24 +1269,28 @@ pub mod writer {
             self.emit_enum_variant("None", 0, 0, |_| Ok(()))
         }
         fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
 
             self.emit_enum_variant("Some", 1, 1, f)
         }
 
         fn emit_seq<F>(&mut self, len: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
+            if len == 0 {
+                // empty vector optimization
+                return self.wr_tagged_bytes(EsVec as uint, &[]);
+            }
 
             try!(self.start_tag(EsVec as uint));
-            try!(self._emit_tagged_uint(EsVecLen, len));
+            try!(self._emit_tagged_sub(len));
             try!(f(self));
             self.end_tag()
         }
 
         fn emit_seq_elt<F>(&mut self, _idx: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
 
             try!(self.start_tag(EsVecElt as uint));
@@ -1063,17 +1299,21 @@ pub mod writer {
         }
 
         fn emit_map<F>(&mut self, len: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
+            if len == 0 {
+                // empty map optimization
+                return self.wr_tagged_bytes(EsMap as uint, &[]);
+            }
 
             try!(self.start_tag(EsMap as uint));
-            try!(self._emit_tagged_uint(EsMapLen, len));
+            try!(self._emit_tagged_sub(len));
             try!(f(self));
             self.end_tag()
         }
 
         fn emit_map_elt_key<F>(&mut self, _idx: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
 
             try!(self.start_tag(EsMapKey as uint));
@@ -1082,7 +1322,7 @@ pub mod writer {
         }
 
         fn emit_map_elt_val<F>(&mut self, _idx: uint, f: F) -> EncodeResult where
-            F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult,
+            F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
         {
             try!(self.start_tag(EsMapVal as uint));
             try!(f(self));
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index 4930eddb35a..a58ef53de9a 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -14,85 +14,90 @@ pub use self::astencode_tag::*;
 
 use back::svh::Svh;
 
-// EBML enum definitions and utils shared by the encoder and decoder
+// RBML enum definitions and utils shared by the encoder and decoder
+//
+// 0x00..0x1f: reserved for RBML generic type tags
+// 0x20..0xef: free for use, preferred for frequent tags
+// 0xf0..0xff: internally used by RBML to encode 0x100..0xfff in two bytes
+// 0x100..0xfff: free for use, preferred for infrequent tags
 
-pub const tag_items: uint = 0x00;
+pub const tag_items: uint = 0x100; // top-level only
 
-pub const tag_paths_data_name: uint = 0x01;
+pub const tag_paths_data_name: uint = 0x20;
 
-pub const tag_def_id: uint = 0x02;
+pub const tag_def_id: uint = 0x21;
 
-pub const tag_items_data: uint = 0x03;
+pub const tag_items_data: uint = 0x22;
 
-pub const tag_items_data_item: uint = 0x04;
+pub const tag_items_data_item: uint = 0x23;
 
-pub const tag_items_data_item_family: uint = 0x05;
+pub const tag_items_data_item_family: uint = 0x24;
 
-pub const tag_items_data_item_type: uint = 0x07;
+pub const tag_items_data_item_type: uint = 0x25;
 
-pub const tag_items_data_item_symbol: uint = 0x08;
+pub const tag_items_data_item_symbol: uint = 0x26;
 
-pub const tag_items_data_item_variant: uint = 0x09;
+pub const tag_items_data_item_variant: uint = 0x27;
 
-pub const tag_items_data_parent_item: uint = 0x0a;
+pub const tag_items_data_parent_item: uint = 0x28;
 
-pub const tag_items_data_item_is_tuple_struct_ctor: uint = 0x0b;
+pub const tag_items_data_item_is_tuple_struct_ctor: uint = 0x29;
 
-pub const tag_index: uint = 0x0c;
+pub const tag_index: uint = 0x2a;
 
-pub const tag_index_buckets: uint = 0x0d;
+pub const tag_index_buckets: uint = 0x2b;
 
-pub const tag_index_buckets_bucket: uint = 0x0e;
+pub const tag_index_buckets_bucket: uint = 0x2c;
 
-pub const tag_index_buckets_bucket_elt: uint = 0x0f;
+pub const tag_index_buckets_bucket_elt: uint = 0x2d;
 
-pub const tag_index_table: uint = 0x10;
+pub const tag_index_table: uint = 0x2e;
 
-pub const tag_meta_item_name_value: uint = 0x11;
+pub const tag_meta_item_name_value: uint = 0x2f;
 
-pub const tag_meta_item_name: uint = 0x12;
+pub const tag_meta_item_name: uint = 0x30;
 
-pub const tag_meta_item_value: uint = 0x13;
+pub const tag_meta_item_value: uint = 0x31;
 
-pub const tag_attributes: uint = 0x14;
+pub const tag_attributes: uint = 0x101; // top-level only
 
-pub const tag_attribute: uint = 0x15;
+pub const tag_attribute: uint = 0x32;
 
-pub const tag_meta_item_word: uint = 0x16;
+pub const tag_meta_item_word: uint = 0x33;
 
-pub const tag_meta_item_list: uint = 0x17;
+pub const tag_meta_item_list: uint = 0x34;
 
 // The list of crates that this crate depends on
-pub const tag_crate_deps: uint = 0x18;
+pub const tag_crate_deps: uint = 0x102; // top-level only
 
 // A single crate dependency
-pub const tag_crate_dep: uint = 0x19;
+pub const tag_crate_dep: uint = 0x35;
 
-pub const tag_crate_hash: uint = 0x1a;
-pub const tag_crate_crate_name: uint = 0x1b;
+pub const tag_crate_hash: uint = 0x103; // top-level only
+pub const tag_crate_crate_name: uint = 0x104; // top-level only
 
-pub const tag_crate_dep_crate_name: uint = 0x1d;
-pub const tag_crate_dep_hash: uint = 0x1e;
+pub const tag_crate_dep_crate_name: uint = 0x36;
+pub const tag_crate_dep_hash: uint = 0x37;
 
-pub const tag_mod_impl: uint = 0x1f;
+pub const tag_mod_impl: uint = 0x38;
 
-pub const tag_item_trait_item: uint = 0x20;
+pub const tag_item_trait_item: uint = 0x39;
 
-pub const tag_item_trait_ref: uint = 0x21;
-pub const tag_item_super_trait_ref: uint = 0x22;
+pub const tag_item_trait_ref: uint = 0x3a;
+pub const tag_item_super_trait_ref: uint = 0x3b;
 
 // discriminator value for variants
-pub const tag_disr_val: uint = 0x23;
+pub const tag_disr_val: uint = 0x3c;
 
 // used to encode ast_map::PathElem
-pub const tag_path: uint = 0x24;
-pub const tag_path_len: uint = 0x25;
-pub const tag_path_elem_mod: uint = 0x26;
-pub const tag_path_elem_name: uint = 0x27;
-pub const tag_item_field: uint = 0x28;
-pub const tag_item_field_origin: uint = 0x29;
-
-pub const tag_item_variances: uint = 0x2a;
+pub const tag_path: uint = 0x3d;
+pub const tag_path_len: uint = 0x3e;
+pub const tag_path_elem_mod: uint = 0x3f;
+pub const tag_path_elem_name: uint = 0x40;
+pub const tag_item_field: uint = 0x41;
+pub const tag_item_field_origin: uint = 0x42;
+
+pub const tag_item_variances: uint = 0x43;
 /*
   trait items contain tag_item_trait_item elements,
   impl items contain tag_item_impl_item elements, and classes
@@ -101,60 +106,59 @@ pub const tag_item_variances: uint = 0x2a;
   both, tag_item_trait_item and tag_item_impl_item have to be two
   different tags.
  */
-pub const tag_item_impl_item: uint = 0x30;
-pub const tag_item_trait_method_explicit_self: uint = 0x31;
+pub const tag_item_impl_item: uint = 0x44;
+pub const tag_item_trait_method_explicit_self: uint = 0x45;
 
 
 // Reexports are found within module tags. Each reexport contains def_ids
 // and names.
-pub const tag_items_data_item_reexport: uint = 0x38;
-pub const tag_items_data_item_reexport_def_id: uint = 0x39;
-pub const tag_items_data_item_reexport_name: uint = 0x3a;
+pub const tag_items_data_item_reexport: uint = 0x46;
+pub const tag_items_data_item_reexport_def_id: uint = 0x47;
+pub const tag_items_data_item_reexport_name: uint = 0x48;
 
 // used to encode crate_ctxt side tables
 #[derive(Copy, PartialEq, FromPrimitive)]
 #[repr(uint)]
-pub enum astencode_tag { // Reserves 0x40 -- 0x5f
-    tag_ast = 0x40,
-
-    tag_tree = 0x41,
-
-    tag_id_range = 0x42,
-
-    tag_table = 0x43,
-    tag_table_id = 0x44,
-    tag_table_val = 0x45,
-    tag_table_def = 0x46,
-    tag_table_node_type = 0x47,
-    tag_table_item_subst = 0x48,
-    tag_table_freevars = 0x49,
-    tag_table_tcache = 0x4a,
-    tag_table_param_defs = 0x4b,
-    tag_table_mutbl = 0x4c,
-    tag_table_last_use = 0x4d,
-    tag_table_spill = 0x4e,
-    tag_table_method_map = 0x4f,
-    tag_table_vtable_map = 0x50,
-    tag_table_adjustments = 0x51,
-    tag_table_moves_map = 0x52,
-    tag_table_capture_map = 0x53,
-    tag_table_closure_tys = 0x54,
-    tag_table_closure_kinds = 0x55,
-    tag_table_upvar_capture_map = 0x56,
-    tag_table_capture_modes = 0x57,
-    tag_table_object_cast_map = 0x58,
-    tag_table_const_qualif = 0x59,
+pub enum astencode_tag { // Reserves 0x50 -- 0x6f
+    tag_ast = 0x50,
+
+    tag_tree = 0x51,
+
+    tag_id_range = 0x52,
+
+    tag_table = 0x53,
+    // GAP 0x54, 0x55
+    tag_table_def = 0x56,
+    tag_table_node_type = 0x57,
+    tag_table_item_subst = 0x58,
+    tag_table_freevars = 0x59,
+    tag_table_tcache = 0x5a,
+    tag_table_param_defs = 0x5b,
+    tag_table_mutbl = 0x5c,
+    tag_table_last_use = 0x5d,
+    tag_table_spill = 0x5e,
+    tag_table_method_map = 0x5f,
+    tag_table_vtable_map = 0x60,
+    tag_table_adjustments = 0x61,
+    tag_table_moves_map = 0x62,
+    tag_table_capture_map = 0x63,
+    tag_table_closure_tys = 0x64,
+    tag_table_closure_kinds = 0x65,
+    tag_table_upvar_capture_map = 0x66,
+    tag_table_capture_modes = 0x67,
+    tag_table_object_cast_map = 0x68,
+    tag_table_const_qualif = 0x69,
 }
 
-pub const tag_item_trait_item_sort: uint = 0x60;
+pub const tag_item_trait_item_sort: uint = 0x70;
 
-pub const tag_item_trait_parent_sort: uint = 0x61;
+pub const tag_item_trait_parent_sort: uint = 0x71;
 
-pub const tag_item_impl_type_basename: uint = 0x62;
+pub const tag_item_impl_type_basename: uint = 0x72;
 
-pub const tag_crate_triple: uint = 0x66;
+pub const tag_crate_triple: uint = 0x105; // top-level only
 
-pub const tag_dylib_dependency_formats: uint = 0x67;
+pub const tag_dylib_dependency_formats: uint = 0x106; // top-level only
 
 // Language items are a top-level directory (for speed). Hierarchy:
 //
@@ -163,51 +167,47 @@ pub const tag_dylib_dependency_formats: uint = 0x67;
 //   - tag_lang_items_item_id: u32
 //   - tag_lang_items_item_node_id: u32
 
-pub const tag_lang_items: uint = 0x70;
-pub const tag_lang_items_item: uint = 0x71;
-pub const tag_lang_items_item_id: uint = 0x72;
-pub const tag_lang_items_item_node_id: uint = 0x73;
-pub const tag_lang_items_missing: uint = 0x74;
+pub const tag_lang_items: uint = 0x107; // top-level only
+pub const tag_lang_items_item: uint = 0x73;
+pub const tag_lang_items_item_id: uint = 0x74;
+pub const tag_lang_items_item_node_id: uint = 0x75;
+pub const tag_lang_items_missing: uint = 0x76;
 
-pub const tag_item_unnamed_field: uint = 0x75;
-pub const tag_items_data_item_visibility: uint = 0x76;
+pub const tag_item_unnamed_field: uint = 0x77;
+pub const tag_items_data_item_visibility: uint = 0x78;
 
 pub const tag_item_method_tps: uint = 0x79;
 pub const tag_item_method_fty: uint = 0x7a;
 
 pub const tag_mod_child: uint = 0x7b;
-pub const tag_misc_info: uint = 0x7c;
-pub const tag_misc_info_crate_items: uint = 0x7d;
-
-pub const tag_item_method_provided_source: uint = 0x7e;
-pub const tag_item_impl_vtables: uint = 0x7f;
+pub const tag_misc_info: uint = 0x108; // top-level only
+pub const tag_misc_info_crate_items: uint = 0x7c;
 
-pub const tag_impls: uint = 0x80;
-pub const tag_impls_impl: uint = 0x81;
+pub const tag_item_method_provided_source: uint = 0x7d;
+pub const tag_item_impl_vtables: uint = 0x7e;
 
-pub const tag_items_data_item_inherent_impl: uint = 0x82;
-pub const tag_items_data_item_extension_impl: uint = 0x83;
+pub const tag_impls: uint = 0x109; // top-level only
+pub const tag_impls_impl: uint = 0x7f;
 
-// GAP 0x84, 0x85, 0x86
+pub const tag_items_data_item_inherent_impl: uint = 0x80;
+pub const tag_items_data_item_extension_impl: uint = 0x81;
 
-pub const tag_native_libraries: uint = 0x87;
-pub const tag_native_libraries_lib: uint = 0x88;
-pub const tag_native_libraries_name: uint = 0x89;
-pub const tag_native_libraries_kind: uint = 0x8a;
+pub const tag_native_libraries: uint = 0x10a; // top-level only
+pub const tag_native_libraries_lib: uint = 0x82;
+pub const tag_native_libraries_name: uint = 0x83;
+pub const tag_native_libraries_kind: uint = 0x84;
 
-pub const tag_plugin_registrar_fn: uint = 0x8b;
+pub const tag_plugin_registrar_fn: uint = 0x10b; // top-level only
 
-// GAP 0x8c, 0x8d
+pub const tag_method_argument_names: uint = 0x85;
+pub const tag_method_argument_name: uint = 0x86;
 
-pub const tag_method_argument_names: uint = 0x8e;
-pub const tag_method_argument_name: uint = 0x8f;
+pub const tag_reachable_extern_fns: uint = 0x10c; // top-level only
+pub const tag_reachable_extern_fn_id: uint = 0x87;
 
-pub const tag_reachable_extern_fns: uint = 0x90;
-pub const tag_reachable_extern_fn_id: uint = 0x91;
+pub const tag_items_data_item_stability: uint = 0x88;
 
-pub const tag_items_data_item_stability: uint = 0x92;
-
-pub const tag_items_data_item_repr: uint = 0x93;
+pub const tag_items_data_item_repr: uint = 0x89;
 
 #[derive(Clone, Debug)]
 pub struct LinkMeta {
@@ -215,42 +215,40 @@ pub struct LinkMeta {
     pub crate_hash: Svh,
 }
 
-// GAP 0x94...0x98
-
-pub const tag_struct_fields: uint = 0x99;
-pub const tag_struct_field: uint = 0x9a;
-pub const tag_struct_field_id: uint = 0x9b;
+pub const tag_struct_fields: uint = 0x10d; // top-level only
+pub const tag_struct_field: uint = 0x8a;
+pub const tag_struct_field_id: uint = 0x8b;
 
-pub const tag_attribute_is_sugared_doc: uint = 0x9c;
+pub const tag_attribute_is_sugared_doc: uint = 0x8c;
 
-pub const tag_trait_def_bounds: uint = 0x9d;
+pub const tag_trait_def_bounds: uint = 0x8d;
 
-pub const tag_items_data_region: uint = 0x9e;
+pub const tag_items_data_region: uint = 0x8e;
 
-pub const tag_region_param_def: uint = 0xa0;
-pub const tag_region_param_def_ident: uint = 0xa1;
-pub const tag_region_param_def_def_id: uint = 0xa2;
-pub const tag_region_param_def_space: uint = 0xa3;
-pub const tag_region_param_def_index: uint = 0xa4;
+pub const tag_region_param_def: uint = 0x8f;
+pub const tag_region_param_def_ident: uint = 0x90;
+pub const tag_region_param_def_def_id: uint = 0x91;
+pub const tag_region_param_def_space: uint = 0x92;
+pub const tag_region_param_def_index: uint = 0x93;
 
-pub const tag_type_param_def: uint = 0xa5;
+pub const tag_type_param_def: uint = 0x94;
 
-pub const tag_item_generics: uint = 0xa6;
-pub const tag_method_ty_generics: uint = 0xa7;
+pub const tag_item_generics: uint = 0x95;
+pub const tag_method_ty_generics: uint = 0x96;
 
-pub const tag_predicate: uint = 0xa8;
-pub const tag_predicate_space: uint = 0xa9;
-pub const tag_predicate_data: uint = 0xb0;
+pub const tag_predicate: uint = 0x97;
+pub const tag_predicate_space: uint = 0x98;
+pub const tag_predicate_data: uint = 0x99;
 
-pub const tag_unsafety: uint = 0xb1;
+pub const tag_unsafety: uint = 0x9a;
 
-pub const tag_associated_type_names: uint = 0xb2;
-pub const tag_associated_type_name: uint = 0xb3;
+pub const tag_associated_type_names: uint = 0x9b;
+pub const tag_associated_type_name: uint = 0x9c;
 
-pub const tag_polarity: uint = 0xb4;
+pub const tag_polarity: uint = 0x9d;
 
-pub const tag_macro_defs: uint = 0xb5;
-pub const tag_macro_def: uint = 0xb6;
-pub const tag_macro_def_body: uint = 0xb7;
+pub const tag_macro_defs: uint = 0x10e; // top-level only
+pub const tag_macro_def: uint = 0x9e;
+pub const tag_macro_def_body: uint = 0x9f;
 
-pub const tag_paren_sugar: uint = 0xb8;
+pub const tag_paren_sugar: uint = 0xa0;
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index ee2745ca66b..131a299cc50 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -46,7 +46,7 @@ use syntax::ptr::P;
 use syntax::visit::Visitor;
 use syntax::visit;
 use syntax;
-use rbml::writer;
+use rbml::writer::Encoder;
 use rbml::io::SeekableMemWriter;
 
 /// A borrowed version of `ast::InlinedItem`.
@@ -57,8 +57,6 @@ pub enum InlinedItemRef<'a> {
     IIForeignRef(&'a ast::ForeignItem)
 }
 
-pub type Encoder<'a> = writer::Encoder<'a, SeekableMemWriter>;
-
 pub type EncodeInlinedItem<'a> =
     Box<FnMut(&EncodeContext, &mut Encoder, InlinedItemRef) + 'a>;
 
@@ -115,15 +113,13 @@ fn encode_trait_ref<'a, 'tcx>(rbml_w: &mut Encoder,
     };
 
     rbml_w.start_tag(tag);
-    tyencode::enc_trait_ref(rbml_w.writer, ty_str_ctxt, trait_ref);
+    tyencode::enc_trait_ref(rbml_w, ty_str_ctxt, trait_ref);
     rbml_w.end_tag();
 }
 
 // Item info table encoding
 fn encode_family(rbml_w: &mut Encoder, c: char) {
-    rbml_w.start_tag(tag_items_data_item_family);
-    rbml_w.writer.write_all(&[c as u8]);
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_u8(tag_items_data_item_family, c as u8);
 }
 
 pub fn def_to_string(did: DefId) -> String {
@@ -157,14 +153,9 @@ fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
 }
 
 fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) {
-    rbml_w.start_tag(tag_items_data_item_variant);
     let s = def_to_string(vid);
-    rbml_w.writer.write_all(s.as_bytes());
-    rbml_w.end_tag();
-
-    rbml_w.start_tag(tag_mod_child);
-    rbml_w.wr_str(&s[..]);
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_str(tag_items_data_item_variant, &s[..]);
+    rbml_w.wr_tagged_str(tag_mod_child, &s[..]);
 }
 
 pub fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
@@ -176,7 +167,7 @@ pub fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         tcx: ecx.tcx,
         abbrevs: &ecx.type_abbrevs
     };
-    tyencode::enc_closure_ty(rbml_w.writer, ty_str_ctxt, closure_type);
+    tyencode::enc_closure_ty(rbml_w, ty_str_ctxt, closure_type);
 }
 
 pub fn write_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
@@ -188,7 +179,7 @@ pub fn write_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         tcx: ecx.tcx,
         abbrevs: &ecx.type_abbrevs
     };
-    tyencode::enc_ty(rbml_w.writer, ty_str_ctxt, typ);
+    tyencode::enc_ty(rbml_w, ty_str_ctxt, typ);
 }
 
 pub fn write_trait_ref<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
@@ -200,7 +191,7 @@ pub fn write_trait_ref<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         tcx: ecx.tcx,
         abbrevs: &ecx.type_abbrevs
     };
-    tyencode::enc_trait_ref(rbml_w.writer, ty_str_ctxt, trait_ref);
+    tyencode::enc_trait_ref(rbml_w, ty_str_ctxt, trait_ref);
 }
 
 pub fn write_region(ecx: &EncodeContext,
@@ -212,7 +203,7 @@ pub fn write_region(ecx: &EncodeContext,
         tcx: ecx.tcx,
         abbrevs: &ecx.type_abbrevs
     };
-    tyencode::enc_region(rbml_w.writer, ty_str_ctxt, r);
+    tyencode::enc_region(rbml_w, ty_str_ctxt, r);
 }
 
 fn encode_bounds<'a, 'tcx>(rbml_w: &mut Encoder,
@@ -225,7 +216,7 @@ fn encode_bounds<'a, 'tcx>(rbml_w: &mut Encoder,
                                         ds: def_to_string,
                                         tcx: ecx.tcx,
                                         abbrevs: &ecx.type_abbrevs };
-    tyencode::enc_bounds(rbml_w.writer, ty_str_ctxt, bounds);
+    tyencode::enc_bounds(rbml_w, ty_str_ctxt, bounds);
 
     rbml_w.end_tag();
 }
@@ -257,7 +248,7 @@ fn encode_method_fty<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         tcx: ecx.tcx,
         abbrevs: &ecx.type_abbrevs
     };
-    tyencode::enc_bare_fn_ty(rbml_w.writer, ty_str_ctxt, typ);
+    tyencode::enc_bare_fn_ty(rbml_w, ty_str_ctxt, typ);
 
     rbml_w.end_tag();
 }
@@ -265,34 +256,26 @@ fn encode_method_fty<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 fn encode_symbol(ecx: &EncodeContext,
                  rbml_w: &mut Encoder,
                  id: NodeId) {
-    rbml_w.start_tag(tag_items_data_item_symbol);
     match ecx.item_symbols.borrow().get(&id) {
         Some(x) => {
             debug!("encode_symbol(id={}, str={})", id, *x);
-            rbml_w.writer.write_all(x.as_bytes());
+            rbml_w.wr_tagged_str(tag_items_data_item_symbol, x);
         }
         None => {
             ecx.diag.handler().bug(
                 &format!("encode_symbol: id not found {}", id));
         }
     }
-    rbml_w.end_tag();
 }
 
 fn encode_disr_val(_: &EncodeContext,
                    rbml_w: &mut Encoder,
                    disr_val: ty::Disr) {
-    rbml_w.start_tag(tag_disr_val);
-    let s = disr_val.to_string();
-    rbml_w.writer.write_all(s.as_bytes());
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_string());
 }
 
 fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) {
-    rbml_w.start_tag(tag_items_data_parent_item);
-    let s = def_to_string(id);
-    rbml_w.writer.write_all(s.as_bytes());
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_str(tag_items_data_parent_item, &def_to_string(id));
 }
 
 fn encode_struct_fields(rbml_w: &mut Encoder,
@@ -307,10 +290,7 @@ fn encode_struct_fields(rbml_w: &mut Encoder,
         }
         encode_struct_field_family(rbml_w, f.vis);
         encode_def_id(rbml_w, f.id);
-        rbml_w.start_tag(tag_item_field_origin);
-        let s = def_to_string(origin);
-        rbml_w.writer.write_all(s.as_bytes());
-        rbml_w.end_tag();
+        rbml_w.wr_tagged_str(tag_item_field_origin, &def_to_string(origin));
         rbml_w.end_tag();
     }
 }
@@ -330,7 +310,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
         let def_id = local_def(variant.node.id);
         index.push(entry {
             val: variant.node.id as i64,
-            pos: rbml_w.writer.tell().unwrap(),
+            pos: rbml_w.mark_stable_position(),
         });
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id(rbml_w, def_id);
@@ -393,14 +373,11 @@ fn encode_reexported_static_method(rbml_w: &mut Encoder,
     debug!("(encode reexported static method) {}::{}",
             exp.name, token::get_name(method_name));
     rbml_w.start_tag(tag_items_data_item_reexport);
-    rbml_w.start_tag(tag_items_data_item_reexport_def_id);
-    rbml_w.wr_str(&def_to_string(method_def_id));
-    rbml_w.end_tag();
-    rbml_w.start_tag(tag_items_data_item_reexport_name);
-    rbml_w.wr_str(&format!("{}::{}",
-                          exp.name,
-                          token::get_name(method_name)));
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_str(tag_items_data_item_reexport_def_id,
+                         &def_to_string(method_def_id));
+    rbml_w.wr_tagged_str(tag_items_data_item_reexport_name,
+                         &format!("{}::{}", exp.name,
+                                            token::get_name(method_name)));
     rbml_w.end_tag();
 }
 
@@ -536,12 +513,10 @@ fn encode_reexports(ecx: &EncodeContext,
                        exp.def_id.node,
                        id);
                 rbml_w.start_tag(tag_items_data_item_reexport);
-                rbml_w.start_tag(tag_items_data_item_reexport_def_id);
-                rbml_w.wr_str(&def_to_string(exp.def_id));
-                rbml_w.end_tag();
-                rbml_w.start_tag(tag_items_data_item_reexport_name);
-                rbml_w.wr_str(exp.name.as_str());
-                rbml_w.end_tag();
+                rbml_w.wr_tagged_str(tag_items_data_item_reexport_def_id,
+                                     &def_to_string(exp.def_id));
+                rbml_w.wr_tagged_str(tag_items_data_item_reexport_name,
+                                     exp.name.as_str());
                 rbml_w.end_tag();
                 encode_reexported_static_methods(ecx, rbml_w, path.clone(), exp);
             }
@@ -569,15 +544,12 @@ fn encode_info_for_mod(ecx: &EncodeContext,
 
     // Encode info about all the module children.
     for item in &md.items {
-        rbml_w.start_tag(tag_mod_child);
-        rbml_w.wr_str(&def_to_string(local_def(item.id)));
-        rbml_w.end_tag();
+        rbml_w.wr_tagged_str(tag_mod_child,
+                             &def_to_string(local_def(item.id)));
 
         each_auxiliary_node_id(&**item, |auxiliary_node_id| {
-            rbml_w.start_tag(tag_mod_child);
-            rbml_w.wr_str(&def_to_string(local_def(
-                        auxiliary_node_id)));
-            rbml_w.end_tag();
+            rbml_w.wr_tagged_str(tag_mod_child,
+                                 &def_to_string(local_def(auxiliary_node_id)));
             true
         });
 
@@ -587,9 +559,8 @@ fn encode_info_for_mod(ecx: &EncodeContext,
                    token::get_ident(ident),
                    did, ecx.tcx.map.node_to_string(did));
 
-            rbml_w.start_tag(tag_mod_impl);
-            rbml_w.wr_str(&def_to_string(local_def(did)));
-            rbml_w.end_tag();
+            rbml_w.wr_tagged_str(tag_mod_impl,
+                                 &def_to_string(local_def(did)));
         }
     }
 
@@ -618,67 +589,56 @@ fn encode_struct_field_family(rbml_w: &mut Encoder,
 }
 
 fn encode_visibility(rbml_w: &mut Encoder, visibility: ast::Visibility) {
-    rbml_w.start_tag(tag_items_data_item_visibility);
     let ch = match visibility {
         ast::Public => 'y',
         ast::Inherited => 'i',
     };
-    rbml_w.wr_str(&ch.to_string());
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8);
 }
 
 fn encode_explicit_self(rbml_w: &mut Encoder,
                         explicit_self: &ty::ExplicitSelfCategory) {
-    rbml_w.start_tag(tag_item_trait_method_explicit_self);
+    let tag = tag_item_trait_method_explicit_self;
 
     // Encode the base self type.
     match *explicit_self {
         ty::StaticExplicitSelfCategory => {
-            rbml_w.writer.write_all(&[ 's' as u8 ]);
+            rbml_w.wr_tagged_bytes(tag, &['s' as u8]);
         }
         ty::ByValueExplicitSelfCategory => {
-            rbml_w.writer.write_all(&[ 'v' as u8 ]);
+            rbml_w.wr_tagged_bytes(tag, &['v' as u8]);
         }
         ty::ByBoxExplicitSelfCategory => {
-            rbml_w.writer.write_all(&[ '~' as u8 ]);
+            rbml_w.wr_tagged_bytes(tag, &['~' as u8]);
         }
         ty::ByReferenceExplicitSelfCategory(_, m) => {
             // FIXME(#4846) encode custom lifetime
-            rbml_w.writer.write_all(&['&' as u8]);
-            encode_mutability(rbml_w, m);
+            let ch = encode_mutability(m);
+            rbml_w.wr_tagged_bytes(tag, &['&' as u8, ch]);
         }
     }
 
-    rbml_w.end_tag();
-
-    fn encode_mutability(rbml_w: &mut Encoder,
-                         m: ast::Mutability) {
+    fn encode_mutability(m: ast::Mutability) -> u8 {
         match m {
-            ast::MutImmutable => { rbml_w.writer.write_all(&[ 'i' as u8 ]); }
-            ast::MutMutable => { rbml_w.writer.write_all(&[ 'm' as u8 ]); }
+            ast::MutImmutable => 'i' as u8,
+            ast::MutMutable => 'm' as u8,
         }
     }
 }
 
 fn encode_item_sort(rbml_w: &mut Encoder, sort: char) {
-    rbml_w.start_tag(tag_item_trait_item_sort);
-    rbml_w.writer.write_all(&[ sort as u8 ]);
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8);
 }
 
 fn encode_parent_sort(rbml_w: &mut Encoder, sort: char) {
-    rbml_w.start_tag(tag_item_trait_parent_sort);
-    rbml_w.writer.write_all(&[ sort as u8 ]);
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_u8(tag_item_trait_parent_sort, sort as u8);
 }
 
 fn encode_provided_source(rbml_w: &mut Encoder,
                           source_opt: Option<DefId>) {
     if let Some(source) = source_opt {
-        rbml_w.start_tag(tag_item_method_provided_source);
-        let s = def_to_string(source);
-        rbml_w.writer.write_all(s.as_bytes());
-        rbml_w.end_tag();
+        rbml_w.wr_tagged_str(tag_item_method_provided_source,
+                             &def_to_string(source));
     }
 }
 
@@ -697,10 +657,11 @@ fn encode_info_for_struct(ecx: &EncodeContext,
         let nm = field.name;
         let id = field.id.node;
 
-        index.push(entry {val: id as i64, pos: rbml_w.writer.tell().unwrap()});
+        let pos = rbml_w.mark_stable_position();
+        index.push(entry {val: id as i64, pos: pos});
         global_index.push(entry {
             val: id as i64,
-            pos: rbml_w.writer.tell().unwrap(),
+            pos: pos,
         });
         rbml_w.start_tag(tag_items_data_item);
         debug!("encode_info_for_struct: doing {} {}",
@@ -726,7 +687,7 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
                                struct_id: NodeId) {
     index.push(entry {
         val: ctor_id as i64,
-        pos: rbml_w.writer.tell().unwrap(),
+        pos: rbml_w.mark_stable_position(),
     });
 
     rbml_w.start_tag(tag_items_data_item);
@@ -747,8 +708,7 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
     // indicate that this is a tuple struct ctor, because downstream users will normally want
     // the tuple struct definition, but without this there is no way for them to tell that
     // they actually have a ctor rather than a normal function
-    rbml_w.start_tag(tag_items_data_item_is_tuple_struct_ctor);
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]);
 
     rbml_w.end_tag();
 }
@@ -770,7 +730,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
     };
     for param in generics.types.iter() {
         rbml_w.start_tag(tag_type_param_def);
-        tyencode::enc_type_param_def(rbml_w.writer, ty_str_ctxt, param);
+        tyencode::enc_type_param_def(rbml_w, ty_str_ctxt, param);
         rbml_w.end_tag();
     }
 
@@ -804,7 +764,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
         rbml_w.wr_tagged_u8(tag_predicate_space, space as u8);
 
         rbml_w.start_tag(tag_predicate_data);
-        tyencode::enc_predicate(rbml_w.writer, ty_str_ctxt, predicate);
+        tyencode::enc_predicate(rbml_w, ty_str_ctxt, predicate);
         rbml_w.end_tag();
 
         rbml_w.end_tag();
@@ -919,12 +879,13 @@ fn encode_method_argument_names(rbml_w: &mut Encoder,
                                 decl: &ast::FnDecl) {
     rbml_w.start_tag(tag_method_argument_names);
     for arg in &decl.inputs {
-        rbml_w.start_tag(tag_method_argument_name);
+        let tag = tag_method_argument_name;
         if let ast::PatIdent(_, ref path1, _) = arg.pat.node {
             let name = token::get_ident(path1.node);
-            rbml_w.writer.write_all(name.as_bytes());
+            rbml_w.wr_tagged_bytes(tag, name.as_bytes());
+        } else {
+            rbml_w.wr_tagged_bytes(tag, &[]);
         }
-        rbml_w.end_tag();
     }
     rbml_w.end_tag();
 }
@@ -1002,11 +963,11 @@ fn encode_info_for_item(ecx: &EncodeContext,
                         vis: ast::Visibility) {
     let tcx = ecx.tcx;
 
-    fn add_to_index(item: &ast::Item, rbml_w: &Encoder,
+    fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder,
                     index: &mut Vec<entry<i64>>) {
         index.push(entry {
             val: item.id as i64,
-            pos: rbml_w.writer.tell().unwrap(),
+            pos: rbml_w.mark_stable_position(),
         });
     }
 
@@ -1091,9 +1052,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
 
         // Encode all the items in this module.
         for foreign_item in &fm.items {
-            rbml_w.start_tag(tag_mod_child);
-            rbml_w.wr_str(&def_to_string(local_def(foreign_item.id)));
-            rbml_w.end_tag();
+            rbml_w.wr_tagged_str(tag_mod_child,
+                                 &def_to_string(local_def(foreign_item.id)));
         }
         encode_visibility(rbml_w, vis);
         encode_stability(rbml_w, stab);
@@ -1263,7 +1223,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
 
             index.push(entry {
                 val: trait_item_def_id.def_id().node as i64,
-                pos: rbml_w.writer.tell().unwrap(),
+                pos: rbml_w.mark_stable_position(),
             });
 
             let trait_item_type =
@@ -1339,9 +1299,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
             }
             rbml_w.end_tag();
 
-            rbml_w.start_tag(tag_mod_child);
-            rbml_w.wr_str(&def_to_string(method_def_id.def_id()));
-            rbml_w.end_tag();
+            rbml_w.wr_tagged_str(tag_mod_child,
+                                 &def_to_string(method_def_id.def_id()));
         }
         encode_path(rbml_w, path.clone());
 
@@ -1362,7 +1321,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
 
             index.push(entry {
                 val: item_def_id.def_id().node as i64,
-                pos: rbml_w.writer.tell().unwrap(),
+                pos: rbml_w.mark_stable_position(),
             });
 
             rbml_w.start_tag(tag_items_data_item);
@@ -1467,7 +1426,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
                                 abi: abi::Abi) {
     index.push(entry {
         val: nitem.id as i64,
-        pos: rbml_w.writer.tell().unwrap(),
+        pos: rbml_w.mark_stable_position(),
     });
 
     rbml_w.start_tag(tag_items_data_item);
@@ -1567,7 +1526,7 @@ fn encode_info_for_items(ecx: &EncodeContext,
     rbml_w.start_tag(tag_items_data);
     index.push(entry {
         val: ast::CRATE_NODE_ID as i64,
-        pos: rbml_w.writer.tell().unwrap(),
+        pos: rbml_w.mark_stable_position(),
     });
     encode_info_for_mod(ecx,
                         rbml_w,
@@ -1607,7 +1566,7 @@ fn encode_index<T, F>(rbml_w: &mut Encoder, index: Vec<entry<T>>, mut write_fn:
     let mut bucket_locs = Vec::new();
     rbml_w.start_tag(tag_index_buckets);
     for bucket in &buckets {
-        bucket_locs.push(rbml_w.writer.tell().unwrap());
+        bucket_locs.push(rbml_w.mark_stable_position());
         rbml_w.start_tag(tag_index_buckets_bucket);
         for elt in bucket {
             rbml_w.start_tag(tag_index_buckets_bucket_elt);
@@ -1642,21 +1601,15 @@ fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) {
     match mi.node {
       ast::MetaWord(ref name) => {
         rbml_w.start_tag(tag_meta_item_word);
-        rbml_w.start_tag(tag_meta_item_name);
-        rbml_w.writer.write_all(name.as_bytes());
-        rbml_w.end_tag();
+        rbml_w.wr_tagged_str(tag_meta_item_name, name);
         rbml_w.end_tag();
       }
       ast::MetaNameValue(ref name, ref value) => {
         match value.node {
           ast::LitStr(ref value, _) => {
             rbml_w.start_tag(tag_meta_item_name_value);
-            rbml_w.start_tag(tag_meta_item_name);
-            rbml_w.writer.write_all(name.as_bytes());
-            rbml_w.end_tag();
-            rbml_w.start_tag(tag_meta_item_value);
-            rbml_w.writer.write_all(value.as_bytes());
-            rbml_w.end_tag();
+            rbml_w.wr_tagged_str(tag_meta_item_name, name);
+            rbml_w.wr_tagged_str(tag_meta_item_value, value);
             rbml_w.end_tag();
           }
           _ => {/* FIXME (#623): encode other variants */ }
@@ -1664,9 +1617,7 @@ fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) {
       }
       ast::MetaList(ref name, ref items) => {
         rbml_w.start_tag(tag_meta_item_list);
-        rbml_w.start_tag(tag_meta_item_name);
-        rbml_w.writer.write_all(name.as_bytes());
-        rbml_w.end_tag();
+        rbml_w.wr_tagged_str(tag_meta_item_name, name);
         for inner_item in items {
             encode_meta_item(rbml_w, &**inner_item);
         }
@@ -1760,22 +1711,9 @@ fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) {
         if let Some(id) = def_id {
             if id.krate == ast::LOCAL_CRATE {
                 rbml_w.start_tag(tag_lang_items_item);
-
-                rbml_w.start_tag(tag_lang_items_item_id);
-                {
-                    let wr: &mut SeekableMemWriter = rbml_w.writer;
-                    wr.write_be_u32(i as u32);
-                }
-                rbml_w.end_tag();   // tag_lang_items_item_id
-
-                rbml_w.start_tag(tag_lang_items_item_node_id);
-                {
-                    let wr: &mut SeekableMemWriter = rbml_w.writer;
-                    wr.write_be_u32(id.node as u32);
-                }
-                rbml_w.end_tag();   // tag_lang_items_item_node_id
-
-                rbml_w.end_tag();   // tag_lang_items_item
+                rbml_w.wr_tagged_u32(tag_lang_items_item_id, i as u32);
+                rbml_w.wr_tagged_u32(tag_lang_items_item_node_id, id.node as u32);
+                rbml_w.end_tag();
             }
         }
     }
@@ -1796,15 +1734,8 @@ fn encode_native_libraries(ecx: &EncodeContext, rbml_w: &mut Encoder) {
             cstore::NativeStatic => {} // these libraries are not propagated
             cstore::NativeFramework | cstore::NativeUnknown => {
                 rbml_w.start_tag(tag_native_libraries_lib);
-
-                rbml_w.start_tag(tag_native_libraries_kind);
-                rbml_w.writer.write_be_u32(kind as u32);
-                rbml_w.end_tag();
-
-                rbml_w.start_tag(tag_native_libraries_name);
-                rbml_w.writer.write_all(lib.as_bytes());
-                rbml_w.end_tag();
-
+                rbml_w.wr_tagged_u32(tag_native_libraries_kind, kind as u32);
+                rbml_w.wr_tagged_str(tag_native_libraries_name, lib);
                 rbml_w.end_tag();
             }
         }
@@ -1830,9 +1761,8 @@ fn encode_macro_defs(rbml_w: &mut Encoder,
         encode_name(rbml_w, def.ident.name);
         encode_attributes(rbml_w, &def.attrs);
 
-        rbml_w.start_tag(tag_macro_def_body);
-        rbml_w.wr_str(&pprust::tts_to_string(&def.body));
-        rbml_w.end_tag();
+        rbml_w.wr_tagged_str(tag_macro_def_body,
+                             &pprust::tts_to_string(&def.body));
 
         rbml_w.end_tag();
     }
@@ -1917,15 +1847,12 @@ fn encode_misc_info(ecx: &EncodeContext,
     rbml_w.start_tag(tag_misc_info);
     rbml_w.start_tag(tag_misc_info_crate_items);
     for item in &krate.module.items {
-        rbml_w.start_tag(tag_mod_child);
-        rbml_w.wr_str(&def_to_string(local_def(item.id)));
-        rbml_w.end_tag();
+        rbml_w.wr_tagged_str(tag_mod_child,
+                             &def_to_string(local_def(item.id)));
 
         each_auxiliary_node_id(&**item, |auxiliary_node_id| {
-            rbml_w.start_tag(tag_mod_child);
-            rbml_w.wr_str(&def_to_string(local_def(
-                        auxiliary_node_id)));
-            rbml_w.end_tag();
+            rbml_w.wr_tagged_str(tag_mod_child,
+                                 &def_to_string(local_def(auxiliary_node_id)));
             true
         });
     }
@@ -1956,35 +1883,25 @@ fn encode_reachable_extern_fns(ecx: &EncodeContext, rbml_w: &mut Encoder) {
 fn encode_crate_dep(rbml_w: &mut Encoder,
                     dep: decoder::CrateDep) {
     rbml_w.start_tag(tag_crate_dep);
-    rbml_w.start_tag(tag_crate_dep_crate_name);
-    rbml_w.writer.write_all(dep.name.as_bytes());
-    rbml_w.end_tag();
-    rbml_w.start_tag(tag_crate_dep_hash);
-    rbml_w.writer.write_all(dep.hash.as_str().as_bytes());
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name);
+    rbml_w.wr_tagged_str(tag_crate_dep_hash, dep.hash.as_str());
     rbml_w.end_tag();
 }
 
 fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) {
-    rbml_w.start_tag(tag_crate_hash);
-    rbml_w.writer.write_all(hash.as_str().as_bytes());
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_str(tag_crate_hash, hash.as_str());
 }
 
 fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) {
-    rbml_w.start_tag(tag_crate_crate_name);
-    rbml_w.writer.write_all(crate_name.as_bytes());
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name);
 }
 
 fn encode_crate_triple(rbml_w: &mut Encoder, triple: &str) {
-    rbml_w.start_tag(tag_crate_triple);
-    rbml_w.writer.write_all(triple.as_bytes());
-    rbml_w.end_tag();
+    rbml_w.wr_tagged_str(tag_crate_triple, triple);
 }
 
 fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) {
-    rbml_w.start_tag(tag_dylib_dependency_formats);
+    let tag = tag_dylib_dependency_formats;
     match ecx.tcx.dependency_formats.borrow().get(&config::CrateTypeDylib) {
         Some(arr) => {
             let s = arr.iter().enumerate().filter_map(|(i, slot)| {
@@ -1993,21 +1910,28 @@ fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) {
                     cstore::RequireStatic => "s",
                 })).to_string())
             }).collect::<Vec<String>>();
-            rbml_w.writer.write_all(s.connect(",").as_bytes());
+            rbml_w.wr_tagged_str(tag, &s.connect(","));
+        }
+        None => {
+            rbml_w.wr_tagged_str(tag, "");
         }
-        None => {}
     }
-    rbml_w.end_tag();
 }
 
 // NB: Increment this as you change the metadata encoding version.
 #[allow(non_upper_case_globals)]
-pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 1 ];
+pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ];
 
 pub fn encode_metadata(parms: EncodeParams, krate: &ast::Crate) -> Vec<u8> {
     let mut wr = SeekableMemWriter::new();
     encode_metadata_inner(&mut wr, parms, krate);
+
+    // RBML compacts the encoded bytes whenever appropriate,
+    // so there are some garbages left after the end of the data.
+    let metalen = wr.tell().unwrap() as uint;
     let mut v = wr.unwrap();
+    v.truncate(metalen);
+    assert_eq!(v.len(), metalen);
 
     // And here we run into yet another obscure archive bug: in which metadata
     // loaded from archives may have trailing garbage bytes. Awhile back one of
@@ -2089,7 +2013,7 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter,
         reachable: reachable,
      };
 
-    let mut rbml_w = writer::Encoder::new(wr);
+    let mut rbml_w = Encoder::new(wr);
 
     encode_crate_name(&mut rbml_w, &ecx.link_meta.crate_name);
     encode_crate_triple(&mut rbml_w,
@@ -2180,7 +2104,7 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter,
 // Get the encoded string for a type
 pub fn encoded_ty<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> String {
     let mut wr = SeekableMemWriter::new();
-    tyencode::enc_ty(&mut wr, &tyencode::ctxt {
+    tyencode::enc_ty(&mut Encoder::new(&mut wr), &tyencode::ctxt {
         diag: tcx.sess.diagnostic(),
         ds: def_to_string,
         tcx: tcx,
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index ebb4153e32b..86f1605b8bf 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -27,9 +27,9 @@ use syntax::ast;
 use syntax::diagnostic::SpanHandler;
 use syntax::parse::token;
 
-use rbml::io::SeekableMemWriter;
+use rbml::writer::Encoder;
 
-macro_rules! mywrite { ($($arg:tt)*) => ({ write!($($arg)*); }) }
+macro_rules! mywrite { ($w:expr, $($arg:tt)*) => ({ write!($w.writer, $($arg)*); }) }
 
 pub struct ctxt<'a, 'tcx: 'a> {
     pub diag: &'a SpanHandler,
@@ -49,12 +49,14 @@ pub struct ty_abbrev {
 
 pub type abbrev_map<'tcx> = RefCell<FnvHashMap<Ty<'tcx>, ty_abbrev>>;
 
-pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) {
+pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) {
     match cx.abbrevs.borrow_mut().get(&t) {
-        Some(a) => { w.write_all(a.s.as_bytes()); return; }
+        Some(a) => { w.writer.write_all(a.s.as_bytes()); return; }
         None => {}
     }
-    let pos = w.tell().unwrap();
+
+    // type abbreviations needs a stable position
+    let pos = w.mark_stable_position();
 
     match t.sty {
         ty::ty_bool => mywrite!(w, "b"),
@@ -154,7 +156,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t
         }
     }
 
-    let end = w.tell().unwrap();
+    let end = w.mark_stable_position();
     let len = end - pos;
     fn estimate_sz(u: u64) -> u64 {
         let mut n = u;
@@ -171,21 +173,21 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t
     }
 }
 
-fn enc_mutability(w: &mut SeekableMemWriter, mt: ast::Mutability) {
+fn enc_mutability(w: &mut Encoder, mt: ast::Mutability) {
     match mt {
         ast::MutImmutable => (),
         ast::MutMutable => mywrite!(w, "m"),
     }
 }
 
-fn enc_mt<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
+fn enc_mt<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
                     mt: ty::mt<'tcx>) {
     enc_mutability(w, mt.mutbl);
     enc_ty(w, cx, mt.ty);
 }
 
-fn enc_opt<T, F>(w: &mut SeekableMemWriter, t: Option<T>, enc_f: F) where
-    F: FnOnce(&mut SeekableMemWriter, T),
+fn enc_opt<T, F>(w: &mut Encoder, t: Option<T>, enc_f: F) where
+    F: FnOnce(&mut Encoder, T),
 {
     match t {
         None => mywrite!(w, "n"),
@@ -196,11 +198,11 @@ fn enc_opt<T, F>(w: &mut SeekableMemWriter, t: Option<T>, enc_f: F) where
     }
 }
 
-fn enc_vec_per_param_space<'a, 'tcx, T, F>(w: &mut SeekableMemWriter,
+fn enc_vec_per_param_space<'a, 'tcx, T, F>(w: &mut Encoder,
                                            cx: &ctxt<'a, 'tcx>,
                                            v: &VecPerParamSpace<T>,
                                            mut op: F) where
-    F: FnMut(&mut SeekableMemWriter, &ctxt<'a, 'tcx>, &T),
+    F: FnMut(&mut Encoder, &ctxt<'a, 'tcx>, &T),
 {
     for &space in &subst::ParamSpace::all() {
         mywrite!(w, "[");
@@ -211,14 +213,14 @@ fn enc_vec_per_param_space<'a, 'tcx, T, F>(w: &mut SeekableMemWriter,
     }
 }
 
-pub fn enc_substs<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
+pub fn enc_substs<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
                             substs: &subst::Substs<'tcx>) {
     enc_region_substs(w, cx, &substs.regions);
     enc_vec_per_param_space(w, cx, &substs.types,
                             |w, cx, &ty| enc_ty(w, cx, ty));
 }
 
-fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::RegionSubsts) {
+fn enc_region_substs(w: &mut Encoder, cx: &ctxt, substs: &subst::RegionSubsts) {
     match *substs {
         subst::ErasedRegions => {
             mywrite!(w, "e");
@@ -231,7 +233,7 @@ fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::Regio
     }
 }
 
-pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
+pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) {
     match r {
         ty::ReLateBound(id, br) => {
             mywrite!(w, "b[{}|", id.depth);
@@ -270,7 +272,7 @@ pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
     }
 }
 
-fn enc_scope(w: &mut SeekableMemWriter, _cx: &ctxt, scope: region::CodeExtent) {
+fn enc_scope(w: &mut Encoder, _cx: &ctxt, scope: region::CodeExtent) {
     match scope {
         region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id),
         region::CodeExtent::Remainder(region::BlockRemainder {
@@ -279,12 +281,12 @@ fn enc_scope(w: &mut SeekableMemWriter, _cx: &ctxt, scope: region::CodeExtent) {
     }
 }
 
-fn enc_destruction_scope_data(w: &mut SeekableMemWriter,
+fn enc_destruction_scope_data(w: &mut Encoder,
                               d: region::DestructionScopeData) {
     mywrite!(w, "{}", d.node_id);
 }
 
-fn enc_bound_region(w: &mut SeekableMemWriter, cx: &ctxt, br: ty::BoundRegion) {
+fn enc_bound_region(w: &mut Encoder, cx: &ctxt, br: ty::BoundRegion) {
     match br {
         ty::BrAnon(idx) => {
             mywrite!(w, "a{}|", idx);
@@ -303,40 +305,40 @@ fn enc_bound_region(w: &mut SeekableMemWriter, cx: &ctxt, br: ty::BoundRegion) {
     }
 }
 
-pub fn enc_trait_ref<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
+pub fn enc_trait_ref<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
                                s: &ty::TraitRef<'tcx>) {
     mywrite!(w, "{}|", (cx.ds)(s.def_id));
     enc_substs(w, cx, s.substs);
 }
 
-fn enc_unsafety(w: &mut SeekableMemWriter, p: ast::Unsafety) {
+fn enc_unsafety(w: &mut Encoder, p: ast::Unsafety) {
     match p {
         ast::Unsafety::Normal => mywrite!(w, "n"),
         ast::Unsafety::Unsafe => mywrite!(w, "u"),
     }
 }
 
-fn enc_abi(w: &mut SeekableMemWriter, abi: Abi) {
+fn enc_abi(w: &mut Encoder, abi: Abi) {
     mywrite!(w, "[");
     mywrite!(w, "{}", abi.name());
     mywrite!(w, "]")
 }
 
-pub fn enc_bare_fn_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
+pub fn enc_bare_fn_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
                                 ft: &ty::BareFnTy<'tcx>) {
     enc_unsafety(w, ft.unsafety);
     enc_abi(w, ft.abi);
     enc_fn_sig(w, cx, &ft.sig);
 }
 
-pub fn enc_closure_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
+pub fn enc_closure_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
                                 ft: &ty::ClosureTy<'tcx>) {
     enc_unsafety(w, ft.unsafety);
     enc_fn_sig(w, cx, &ft.sig);
     enc_abi(w, ft.abi);
 }
 
-fn enc_fn_sig<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
+fn enc_fn_sig<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
                         fsig: &ty::PolyFnSig<'tcx>) {
     mywrite!(w, "[");
     for ty in &fsig.0.inputs {
@@ -358,7 +360,7 @@ fn enc_fn_sig<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
     }
 }
 
-pub fn enc_builtin_bounds(w: &mut SeekableMemWriter, _cx: &ctxt, bs: &ty::BuiltinBounds) {
+pub fn enc_builtin_bounds(w: &mut Encoder, _cx: &ctxt, bs: &ty::BuiltinBounds) {
     for bound in bs {
         match bound {
             ty::BoundSend => mywrite!(w, "S"),
@@ -371,7 +373,7 @@ pub fn enc_builtin_bounds(w: &mut SeekableMemWriter, _cx: &ctxt, bs: &ty::Builti
     mywrite!(w, ".");
 }
 
-pub fn enc_existential_bounds<'a,'tcx>(w: &mut SeekableMemWriter,
+pub fn enc_existential_bounds<'a,'tcx>(w: &mut Encoder,
                                        cx: &ctxt<'a,'tcx>,
                                        bs: &ty::ExistentialBounds<'tcx>) {
     let param_bounds = ty::ParamBounds { trait_bounds: vec!(),
@@ -381,7 +383,7 @@ pub fn enc_existential_bounds<'a,'tcx>(w: &mut SeekableMemWriter,
     enc_bounds(w, cx, &param_bounds);
 }
 
-pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
+pub fn enc_bounds<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
                             bs: &ty::ParamBounds<'tcx>) {
     enc_builtin_bounds(w, cx, &bs.builtin_bounds);
 
@@ -400,7 +402,7 @@ pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
     mywrite!(w, ".");
 }
 
-pub fn enc_region_bounds<'a, 'tcx>(w: &mut SeekableMemWriter,
+pub fn enc_region_bounds<'a, 'tcx>(w: &mut Encoder,
                             cx: &ctxt<'a, 'tcx>,
                             rs: &[ty::Region]) {
     for &r in rs {
@@ -411,7 +413,7 @@ pub fn enc_region_bounds<'a, 'tcx>(w: &mut SeekableMemWriter,
     mywrite!(w, ".");
 }
 
-pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
+pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
                                     v: &ty::TypeParameterDef<'tcx>) {
     mywrite!(w, "{}:{}|{}|{}|",
              token::get_name(v.name), (cx.ds)(v.def_id),
@@ -420,7 +422,7 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tc
     enc_object_lifetime_default(w, cx, v.object_lifetime_default);
 }
 
-fn enc_object_lifetime_default<'a, 'tcx>(w: &mut SeekableMemWriter,
+fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Encoder,
                                          cx: &ctxt<'a, 'tcx>,
                                          default: Option<ty::ObjectLifetimeDefault>)
 {
@@ -434,7 +436,7 @@ fn enc_object_lifetime_default<'a, 'tcx>(w: &mut SeekableMemWriter,
     }
 }
 
-pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
+pub fn enc_predicate<'a, 'tcx>(w: &mut Encoder,
                                cx: &ctxt<'a, 'tcx>,
                                p: &ty::Predicate<'tcx>)
 {
@@ -465,7 +467,7 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
     }
 }
 
-fn enc_projection_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
+fn enc_projection_predicate<'a, 'tcx>(w: &mut Encoder,
                                       cx: &ctxt<'a, 'tcx>,
                                       data: &ty::ProjectionPredicate<'tcx>) {
     enc_trait_ref(w, cx, &*data.projection_ty.trait_ref);
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 9f18a0e88e7..599dde4b701 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -43,13 +43,14 @@ use std::old_io::Seek;
 use std::num::FromPrimitive;
 use std::rc::Rc;
 
-use rbml::io::SeekableMemWriter;
-use rbml::{reader, writer};
+use rbml::reader;
+use rbml::writer::Encoder;
 use rbml;
 use serialize;
 use serialize::{Decodable, Decoder, DecoderHelpers, Encodable};
 use serialize::{EncoderHelpers};
 
+#[cfg(test)] use rbml::io::SeekableMemWriter;
 #[cfg(test)] use syntax::parse;
 #[cfg(test)] use syntax::print::pprust;
 
@@ -68,8 +69,6 @@ trait tr_intern {
     fn tr_intern(&self, dcx: &DecodeContext) -> ast::DefId;
 }
 
-pub type Encoder<'a> = writer::Encoder<'a, SeekableMemWriter>;
-
 // ______________________________________________________________________
 // Top-level methods.
 
@@ -414,9 +413,8 @@ fn decode_ast(par_doc: rbml::Doc) -> ast::InlinedItem {
 // ______________________________________________________________________
 // Encoding and decoding of ast::def
 
-fn decode_def(dcx: &DecodeContext, doc: rbml::Doc) -> def::Def {
-    let mut dsr = reader::Decoder::new(doc);
-    let def: def::Def = Decodable::decode(&mut dsr).unwrap();
+fn decode_def(dcx: &DecodeContext, dsr: &mut reader::Decoder) -> def::Def {
+    let def: def::Def = Decodable::decode(dsr).unwrap();
     def.tr(dcx)
 }
 
@@ -911,7 +909,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
     fn emit_type_param_def<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
                                type_param_def: &ty::TypeParameterDef<'tcx>) {
         self.emit_opaque(|this| {
-            Ok(tyencode::enc_type_param_def(this.writer,
+            Ok(tyencode::enc_type_param_def(this,
                                          &ecx.ty_str_ctxt(),
                                          type_param_def))
         });
@@ -920,7 +918,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
     fn emit_predicate<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
                           predicate: &ty::Predicate<'tcx>) {
         self.emit_opaque(|this| {
-            Ok(tyencode::enc_predicate(this.writer,
+            Ok(tyencode::enc_predicate(this,
                                        &ecx.ty_str_ctxt(),
                                        predicate))
         });
@@ -954,20 +952,20 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
 
     fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>,
                                    bounds: &ty::ExistentialBounds<'tcx>) {
-        self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(this.writer,
+        self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(this,
                                                                     &ecx.ty_str_ctxt(),
                                                                     bounds)));
     }
 
     fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds) {
-        self.emit_opaque(|this| Ok(tyencode::enc_builtin_bounds(this.writer,
+        self.emit_opaque(|this| Ok(tyencode::enc_builtin_bounds(this,
                                                                 &ecx.ty_str_ctxt(),
                                                                 bounds)));
     }
 
     fn emit_substs<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
                        substs: &subst::Substs<'tcx>) {
-        self.emit_opaque(|this| Ok(tyencode::enc_substs(this.writer,
+        self.emit_opaque(|this| Ok(tyencode::enc_substs(this,
                                                            &ecx.ty_str_ctxt(),
                                                            substs)));
     }
@@ -1115,7 +1113,7 @@ impl<'a> write_tag_and_id for Encoder<'a> {
     }
 
     fn id(&mut self, id: ast::NodeId) {
-        self.wr_tagged_u64(c::tag_table_id as uint, id as u64);
+        id.encode(self).unwrap();
     }
 }
 
@@ -1152,51 +1150,44 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
     if let Some(def) = tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
         rbml_w.tag(c::tag_table_def, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| def.encode(rbml_w).unwrap());
+            def.encode(rbml_w).unwrap();
         })
     }
 
     if let Some(ty) = tcx.node_types.borrow().get(&id) {
         rbml_w.tag(c::tag_table_node_type, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                rbml_w.emit_ty(ecx, *ty);
-            })
+            rbml_w.emit_ty(ecx, *ty);
         })
     }
 
     if let Some(item_substs) = tcx.item_substs.borrow().get(&id) {
         rbml_w.tag(c::tag_table_item_subst, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                rbml_w.emit_substs(ecx, &item_substs.substs);
-            })
+            rbml_w.emit_substs(ecx, &item_substs.substs);
         })
     }
 
     if let Some(fv) = tcx.freevars.borrow().get(&id) {
         rbml_w.tag(c::tag_table_freevars, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                rbml_w.emit_from_vec(fv, |rbml_w, fv_entry| {
-                    Ok(encode_freevar_entry(rbml_w, fv_entry))
-                });
-            })
+            rbml_w.emit_from_vec(fv, |rbml_w, fv_entry| {
+                Ok(encode_freevar_entry(rbml_w, fv_entry))
+            });
         });
 
         for freevar in fv {
             rbml_w.tag(c::tag_table_upvar_capture_map, |rbml_w| {
                 rbml_w.id(id);
-                rbml_w.tag(c::tag_table_val, |rbml_w| {
-                    let var_id = freevar.def.def_id().node;
-                    let upvar_id = ty::UpvarId {
-                        var_id: var_id,
-                        closure_expr_id: id
-                    };
-                    let upvar_capture = tcx.upvar_capture_map.borrow()[upvar_id].clone();
-                    var_id.encode(rbml_w);
-                    upvar_capture.encode(rbml_w);
-                })
+
+                let var_id = freevar.def.def_id().node;
+                let upvar_id = ty::UpvarId {
+                    var_id: var_id,
+                    closure_expr_id: id
+                };
+                let upvar_capture = tcx.upvar_capture_map.borrow()[upvar_id].clone();
+                var_id.encode(rbml_w);
+                upvar_capture.encode(rbml_w);
             })
         }
     }
@@ -1205,18 +1196,14 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
     if let Some(type_scheme) = tcx.tcache.borrow().get(&lid) {
         rbml_w.tag(c::tag_table_tcache, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                rbml_w.emit_type_scheme(ecx, type_scheme.clone());
-            })
+            rbml_w.emit_type_scheme(ecx, type_scheme.clone());
         })
     }
 
     if let Some(type_param_def) = tcx.ty_param_defs.borrow().get(&id) {
         rbml_w.tag(c::tag_table_param_defs, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                rbml_w.emit_type_param_def(ecx, type_param_def)
-            })
+            rbml_w.emit_type_param_def(ecx, type_param_def)
         })
     }
 
@@ -1224,18 +1211,14 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
     if let Some(method) = tcx.method_map.borrow().get(&method_call) {
         rbml_w.tag(c::tag_table_method_map, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                encode_method_callee(ecx, rbml_w, method_call.adjustment, method)
-            })
+            encode_method_callee(ecx, rbml_w, method_call.adjustment, method)
         })
     }
 
     if let Some(trait_ref) = tcx.object_cast_map.borrow().get(&id) {
         rbml_w.tag(c::tag_table_object_cast_map, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                rbml_w.emit_trait_ref(ecx, &*trait_ref.0);
-            })
+            rbml_w.emit_trait_ref(ecx, &*trait_ref.0);
         })
     }
 
@@ -1246,9 +1229,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
                 if let Some(method) = tcx.method_map.borrow().get(&method_call) {
                     rbml_w.tag(c::tag_table_method_map, |rbml_w| {
                         rbml_w.id(id);
-                        rbml_w.tag(c::tag_table_val, |rbml_w| {
-                            encode_method_callee(ecx, rbml_w, method_call.adjustment, method)
-                        })
+                        encode_method_callee(ecx, rbml_w, method_call.adjustment, method)
                     })
                 }
             }
@@ -1259,10 +1240,8 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
                     if let Some(method) = tcx.method_map.borrow().get(&method_call) {
                         rbml_w.tag(c::tag_table_method_map, |rbml_w| {
                             rbml_w.id(id);
-                            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                                encode_method_callee(ecx, rbml_w,
-                                                     method_call.adjustment, method)
-                            })
+                            encode_method_callee(ecx, rbml_w,
+                                                 method_call.adjustment, method)
                         })
                     }
                 }
@@ -1274,36 +1253,28 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
 
         rbml_w.tag(c::tag_table_adjustments, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                rbml_w.emit_auto_adjustment(ecx, adjustment);
-            })
+            rbml_w.emit_auto_adjustment(ecx, adjustment);
         })
     }
 
     if let Some(closure_type) = tcx.closure_tys.borrow().get(&ast_util::local_def(id)) {
         rbml_w.tag(c::tag_table_closure_tys, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                rbml_w.emit_closure_type(ecx, closure_type);
-            })
+            rbml_w.emit_closure_type(ecx, closure_type);
         })
     }
 
     if let Some(closure_kind) = tcx.closure_kinds.borrow().get(&ast_util::local_def(id)) {
         rbml_w.tag(c::tag_table_closure_kinds, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                encode_closure_kind(rbml_w, *closure_kind)
-            })
+            encode_closure_kind(rbml_w, *closure_kind)
         })
     }
 
     for &qualif in tcx.const_qualif_map.borrow().get(&id).iter() {
         rbml_w.tag(c::tag_table_const_qualif, |rbml_w| {
             rbml_w.id(id);
-            rbml_w.tag(c::tag_table_val, |rbml_w| {
-                qualif.encode(rbml_w).unwrap()
-            })
+            qualif.encode(rbml_w).unwrap()
         })
     }
 }
@@ -1831,8 +1802,9 @@ fn decode_side_tables(dcx: &DecodeContext,
                       ast_doc: rbml::Doc) {
     let tbl_doc = ast_doc.get(c::tag_table as uint);
     reader::docs(tbl_doc, |tag, entry_doc| {
-        let id0 = entry_doc.get(c::tag_table_id as uint).as_int();
-        let id = dcx.tr_id(id0 as ast::NodeId);
+        let mut entry_dsr = reader::Decoder::new(entry_doc);
+        let id0: ast::NodeId = Decodable::decode(&mut entry_dsr).unwrap();
+        let id = dcx.tr_id(id0);
 
         debug!(">> Side table document with tag 0x{:x} \
                 found for id {} (orig {})",
@@ -1845,13 +1817,11 @@ fn decode_side_tables(dcx: &DecodeContext,
                             tag));
             }
             Some(value) => {
-                let val_doc = entry_doc.get(c::tag_table_val as uint);
-                let mut val_dsr = reader::Decoder::new(val_doc);
-                let val_dsr = &mut val_dsr;
+                let val_dsr = &mut entry_dsr;
 
                 match value {
                     c::tag_table_def => {
-                        let def = decode_def(dcx, val_doc);
+                        let def = decode_def(dcx, val_dsr);
                         dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution {
                             base_def: def,
                             // This doesn't matter cross-crate.
@@ -1995,7 +1965,7 @@ fn mk_ctxt() -> parse::ParseSess {
 fn roundtrip(in_item: Option<P<ast::Item>>) {
     let in_item = in_item.unwrap();
     let mut wr = SeekableMemWriter::new();
-    encode_item_ast(&mut writer::Encoder::new(&mut wr), &*in_item);
+    encode_item_ast(&mut Encoder::new(&mut wr), &*in_item);
     let rbml_doc = rbml::Doc::new(wr.get_ref());
     let out_item = decode_item_ast(rbml_doc);