]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #15915 : erickt/rust/master, r=alexcrichton
authorbors <bors@rust-lang.org>
Wed, 30 Jul 2014 14:41:18 +0000 (14:41 +0000)
committerbors <bors@rust-lang.org>
Wed, 30 Jul 2014 14:41:18 +0000 (14:41 +0000)
std: rename MemWriter to SeekableMemWriter, add seekless MemWriter

Not all users of MemWriter need to seek, but having MemWriter seekable adds between 3-29% in overhead in certain circumstances. This fixes that performance gap by making a non-seekable MemWriter, and creating a new SeekableMemWriter for those circumstances when that functionality is actually needed.

```
test io::mem::test::bench_buf_reader                        ... bench:       682 ns/iter (+/- 85)
test io::mem::test::bench_buf_writer                        ... bench:       580 ns/iter (+/- 57)
test io::mem::test::bench_mem_reader                        ... bench:       793 ns/iter (+/- 99)
test io::mem::test::bench_mem_writer_001_0000               ... bench:        48 ns/iter (+/- 27)
test io::mem::test::bench_mem_writer_001_0010               ... bench:        65 ns/iter (+/- 27) = 153 MB/s
test io::mem::test::bench_mem_writer_001_0100               ... bench:       132 ns/iter (+/- 12) = 757 MB/s
test io::mem::test::bench_mem_writer_001_1000               ... bench:       802 ns/iter (+/- 151) = 1246 MB/s
test io::mem::test::bench_mem_writer_100_0000               ... bench:       481 ns/iter (+/- 28)
test io::mem::test::bench_mem_writer_100_0010               ... bench:      1957 ns/iter (+/- 126) = 510 MB/s
test io::mem::test::bench_mem_writer_100_0100               ... bench:      8222 ns/iter (+/- 434) = 1216 MB/s
test io::mem::test::bench_mem_writer_100_1000               ... bench:     82496 ns/iter (+/- 11191) = 1212 MB/s
test io::mem::test::bench_seekable_mem_writer_001_0000      ... bench:        48 ns/iter (+/- 2)
test io::mem::test::bench_seekable_mem_writer_001_0010      ... bench:        64 ns/iter (+/- 2) = 156 MB/s
test io::mem::test::bench_seekable_mem_writer_001_0100      ... bench:       129 ns/iter (+/- 7) = 775 MB/s
test io::mem::test::bench_seekable_mem_writer_001_1000      ... bench:       801 ns/iter (+/- 159) = 1248 MB/s
test io::mem::test::bench_seekable_mem_writer_100_0000      ... bench:       711 ns/iter (+/- 51)
test io::mem::test::bench_seekable_mem_writer_100_0010      ... bench:      2532 ns/iter (+/- 227) = 394 MB/s
test io::mem::test::bench_seekable_mem_writer_100_0100      ... bench:      8962 ns/iter (+/- 947) = 1115 MB/s
test io::mem::test::bench_seekable_mem_writer_100_1000      ... bench:     85086 ns/iter (+/- 11555) = 1175 MB/s
```

14 files changed:
src/libcollections/string.rs
src/librustc/lib.rs
src/librustc/metadata/encoder.rs
src/librustc/metadata/tyencode.rs
src/librustc/middle/astencode.rs
src/librustc/util/io.rs [new file with mode: 0644]
src/libserialize/ebml.rs
src/libserialize/json.rs
src/libstd/io/fs.rs
src/libstd/io/mem.rs
src/libsyntax/print/pprust.rs
src/libuuid/lib.rs
src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs
src/test/run-pass/issue-11881.rs

index e5c2d98519163926720ceccbbd5c78194e8d1ece..d9aea8b0a28a3143d3ec7b8087502f82f8933a9e 100644 (file)
@@ -688,7 +688,7 @@ pub unsafe fn shift_byte(&mut self) -> Option<u8> {
     /// assert_eq!(s.shift_char(), Some('o'));
     /// assert_eq!(s.shift_char(), None);
     /// ```
-    pub fn shift_char (&mut self) -> Option<char> {
+    pub fn shift_char(&mut self) -> Option<char> {
         let len = self.len();
         if len == 0 {
             return None
index 2a7f7e8c54dd1f66bfb07e10df12e630a06b1bad..82040f141593e7575a1ed9224a5f5757e8835903 100644 (file)
@@ -48,6 +48,9 @@
 #[phase(plugin, link)] extern crate log;
 #[phase(plugin, link)] extern crate syntax;
 
+#[cfg(test)]
+extern crate test;
+
 mod diagnostics;
 
 pub mod back {
@@ -129,6 +132,7 @@ pub mod util {
 
     pub mod common;
     pub mod ppaux;
+    pub mod io;
     pub mod nodemap;
 }
 
index 6665e913e192fbd0b0ca71bedec63499c9c22bcf..dbda4f58d960f91fc721e205ccdc5431acf6dc87 100644 (file)
@@ -26,6 +26,7 @@
 use middle::typeck;
 use middle::stability;
 use middle;
+use util::io::SeekableMemWriter;
 use util::nodemap::{NodeMap, NodeSet};
 
 use serialize::Encodable;
@@ -33,7 +34,6 @@
 use std::gc::Gc;
 use std::hash::Hash;
 use std::hash;
-use std::io::MemWriter;
 use std::mem;
 use std::collections::HashMap;
 use syntax::abi;
@@ -61,7 +61,7 @@ pub enum InlinedItemRef<'a> {
     IIForeignRef(&'a ast::ForeignItem)
 }
 
-pub type Encoder<'a> = writer::Encoder<'a, MemWriter>;
+pub type Encoder<'a> = writer::Encoder<'a, SeekableMemWriter>;
 
 pub type EncodeInlinedItem<'a> = |ecx: &EncodeContext,
                                   ebml_w: &mut Encoder,
@@ -1407,7 +1407,7 @@ fn encode_info_for_items(ecx: &EncodeContext,
 // Path and definition ID indexing
 
 fn encode_index<T: Hash>(ebml_w: &mut Encoder, index: Vec<entry<T>>,
-                         write_fn: |&mut MemWriter, &T|) {
+                         write_fn: |&mut SeekableMemWriter, &T|) {
     let mut buckets: Vec<Vec<entry<T>>> = Vec::from_fn(256, |_| Vec::new());
     for elt in index.move_iter() {
         let h = hash::hash(&elt.val) as uint;
@@ -1424,7 +1424,7 @@ fn encode_index<T: Hash>(ebml_w: &mut Encoder, index: Vec<entry<T>>,
             ebml_w.start_tag(tag_index_buckets_bucket_elt);
             assert!(elt.pos < 0xffff_ffff);
             {
-                let wr: &mut MemWriter = ebml_w.writer;
+                let wr: &mut SeekableMemWriter = ebml_w.writer;
                 wr.write_be_u32(elt.pos as u32);
             }
             write_fn(ebml_w.writer, &elt.val);
@@ -1436,15 +1436,15 @@ fn encode_index<T: Hash>(ebml_w: &mut Encoder, index: Vec<entry<T>>,
     ebml_w.start_tag(tag_index_table);
     for pos in bucket_locs.iter() {
         assert!(*pos < 0xffff_ffff);
-        let wr: &mut MemWriter = ebml_w.writer;
+        let wr: &mut SeekableMemWriter = ebml_w.writer;
         wr.write_be_u32(*pos as u32);
     }
     ebml_w.end_tag();
     ebml_w.end_tag();
 }
 
-fn write_i64(writer: &mut MemWriter, &n: &i64) {
-    let wr: &mut MemWriter = writer;
+fn write_i64(writer: &mut SeekableMemWriter, &n: &i64) {
+    let wr: &mut SeekableMemWriter = writer;
     assert!(n < 0x7fff_ffff);
     wr.write_be_u32(n as u32);
 }
@@ -1545,14 +1545,14 @@ fn encode_lang_items(ecx: &EncodeContext, ebml_w: &mut Encoder) {
 
                 ebml_w.start_tag(tag_lang_items_item_id);
                 {
-                    let wr: &mut MemWriter = ebml_w.writer;
+                    let wr: &mut SeekableMemWriter = ebml_w.writer;
                     wr.write_be_u32(i as u32);
                 }
                 ebml_w.end_tag();   // tag_lang_items_item_id
 
                 ebml_w.start_tag(tag_lang_items_item_node_id);
                 {
-                    let wr: &mut MemWriter = ebml_w.writer;
+                    let wr: &mut SeekableMemWriter = ebml_w.writer;
                     wr.write_be_u32(id.node as u32);
                 }
                 ebml_w.end_tag();   // tag_lang_items_item_node_id
@@ -1824,12 +1824,12 @@ fn encode_dylib_dependency_formats(ebml_w: &mut Encoder, ecx: &EncodeContext) {
       0, 0, 0, 1 ];
 
 pub fn encode_metadata(parms: EncodeParams, krate: &Crate) -> Vec<u8> {
-    let mut wr = MemWriter::new();
+    let mut wr = SeekableMemWriter::new();
     encode_metadata_inner(&mut wr, parms, krate);
     wr.unwrap().move_iter().collect()
 }
 
-fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate) {
+fn encode_metadata_inner(wr: &mut SeekableMemWriter, parms: EncodeParams, krate: &Crate) {
     struct Stats {
         attr_bytes: u64,
         dep_bytes: u64,
@@ -1982,7 +1982,7 @@ struct Stats {
 
 // Get the encoded string for a type
 pub fn encoded_ty(tcx: &ty::ctxt, t: ty::t) -> String {
-    let mut wr = MemWriter::new();
+    let mut wr = SeekableMemWriter::new();
     tyencode::enc_ty(&mut wr, &tyencode::ctxt {
         diag: tcx.sess.diagnostic(),
         ds: def_to_string,
index 15e4e85ddb7114323b884f90f3c4bf057642330a..f301dc3760db60200a76df86f24de4b34f83cbef 100644 (file)
@@ -15,7 +15,6 @@
 
 use std::cell::RefCell;
 use std::collections::HashMap;
-use std::io::MemWriter;
 
 use middle::subst;
 use middle::subst::VecPerParamSpace;
@@ -28,6 +27,8 @@
 use syntax::diagnostic::SpanHandler;
 use syntax::parse::token;
 
+use util::io::SeekableMemWriter;
+
 macro_rules! mywrite( ($($arg:tt)*) => ({ write!($($arg)*); }) )
 
 pub struct ctxt<'a> {
@@ -48,7 +49,7 @@ pub struct ty_abbrev {
 
 pub type abbrev_map = RefCell<HashMap<ty::t, ty_abbrev>>;
 
-pub fn enc_ty(w: &mut MemWriter, cx: &ctxt, t: ty::t) {
+pub fn enc_ty(w: &mut SeekableMemWriter, cx: &ctxt, t: ty::t) {
     match cx.abbrevs.borrow_mut().find(&t) {
         Some(a) => { w.write(a.s.as_bytes()); return; }
         None => {}
@@ -72,19 +73,19 @@ fn estimate_sz(u: u64) -> u64 {
     }
 }
 
-fn enc_mutability(w: &mut MemWriter, mt: ast::Mutability) {
+fn enc_mutability(w: &mut SeekableMemWriter, mt: ast::Mutability) {
     match mt {
         MutImmutable => (),
         MutMutable => mywrite!(w, "m"),
     }
 }
 
-fn enc_mt(w: &mut MemWriter, cx: &ctxt, mt: ty::mt) {
+fn enc_mt(w: &mut SeekableMemWriter, cx: &ctxt, mt: ty::mt) {
     enc_mutability(w, mt.mutbl);
     enc_ty(w, cx, mt.ty);
 }
 
-fn enc_opt<T>(w: &mut MemWriter, t: Option<T>, enc_f: |&mut MemWriter, T|) {
+fn enc_opt<T>(w: &mut SeekableMemWriter, t: Option<T>, enc_f: |&mut SeekableMemWriter, T|) {
     match t {
         None => mywrite!(w, "n"),
         Some(v) => {
@@ -94,10 +95,10 @@ fn enc_opt<T>(w: &mut MemWriter, t: Option<T>, enc_f: |&mut MemWriter, T|) {
     }
 }
 
-fn enc_vec_per_param_space<T>(w: &mut MemWriter,
+fn enc_vec_per_param_space<T>(w: &mut SeekableMemWriter,
                               cx: &ctxt,
                               v: &VecPerParamSpace<T>,
-                              op: |&mut MemWriter, &ctxt, &T|) {
+                              op: |&mut SeekableMemWriter, &ctxt, &T|) {
     for &space in subst::ParamSpace::all().iter() {
         mywrite!(w, "[");
         for t in v.get_slice(space).iter() {
@@ -107,13 +108,13 @@ fn enc_vec_per_param_space<T>(w: &mut MemWriter,
     }
 }
 
-pub fn enc_substs(w: &mut MemWriter, cx: &ctxt, substs: &subst::Substs) {
+pub fn enc_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::Substs) {
     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 MemWriter, cx: &ctxt, substs: &subst::RegionSubsts) {
+fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::RegionSubsts) {
     match *substs {
         subst::ErasedRegions => {
             mywrite!(w, "e");
@@ -126,7 +127,7 @@ fn enc_region_substs(w: &mut MemWriter, cx: &ctxt, substs: &subst::RegionSubsts)
     }
 }
 
-fn enc_region(w: &mut MemWriter, cx: &ctxt, r: ty::Region) {
+fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
     match r {
         ty::ReLateBound(id, br) => {
             mywrite!(w, "b[{}|", id);
@@ -161,7 +162,7 @@ fn enc_region(w: &mut MemWriter, cx: &ctxt, r: ty::Region) {
     }
 }
 
-fn enc_bound_region(w: &mut MemWriter, cx: &ctxt, br: ty::BoundRegion) {
+fn enc_bound_region(w: &mut SeekableMemWriter, cx: &ctxt, br: ty::BoundRegion) {
     match br {
         ty::BrAnon(idx) => {
             mywrite!(w, "a{}|", idx);
@@ -177,12 +178,12 @@ fn enc_bound_region(w: &mut MemWriter, cx: &ctxt, br: ty::BoundRegion) {
     }
 }
 
-pub fn enc_trait_ref(w: &mut MemWriter, cx: &ctxt, s: &ty::TraitRef) {
+pub fn enc_trait_ref(w: &mut SeekableMemWriter, cx: &ctxt, s: &ty::TraitRef) {
     mywrite!(w, "{}|", (cx.ds)(s.def_id));
     enc_substs(w, cx, &s.substs);
 }
 
-pub fn enc_trait_store(w: &mut MemWriter, cx: &ctxt, s: ty::TraitStore) {
+pub fn enc_trait_store(w: &mut SeekableMemWriter, cx: &ctxt, s: ty::TraitStore) {
     match s {
         ty::UniqTraitStore => mywrite!(w, "~"),
         ty::RegionTraitStore(re, m) => {
@@ -193,7 +194,7 @@ pub fn enc_trait_store(w: &mut MemWriter, cx: &ctxt, s: ty::TraitStore) {
     }
 }
 
-fn enc_sty(w: &mut MemWriter, cx: &ctxt, st: &ty::sty) {
+fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
     match *st {
         ty::ty_nil => mywrite!(w, "n"),
         ty::ty_bot => mywrite!(w, "z"),
@@ -293,33 +294,33 @@ fn enc_sty(w: &mut MemWriter, cx: &ctxt, st: &ty::sty) {
     }
 }
 
-fn enc_fn_style(w: &mut MemWriter, p: FnStyle) {
+fn enc_fn_style(w: &mut SeekableMemWriter, p: FnStyle) {
     match p {
         NormalFn => mywrite!(w, "n"),
         UnsafeFn => mywrite!(w, "u"),
     }
 }
 
-fn enc_abi(w: &mut MemWriter, abi: Abi) {
+fn enc_abi(w: &mut SeekableMemWriter, abi: Abi) {
     mywrite!(w, "[");
     mywrite!(w, "{}", abi.name());
     mywrite!(w, "]")
 }
 
-fn enc_onceness(w: &mut MemWriter, o: Onceness) {
+fn enc_onceness(w: &mut SeekableMemWriter, o: Onceness) {
     match o {
         Once => mywrite!(w, "o"),
         Many => mywrite!(w, "m")
     }
 }
 
-pub fn enc_bare_fn_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::BareFnTy) {
+pub fn enc_bare_fn_ty(w: &mut SeekableMemWriter, cx: &ctxt, ft: &ty::BareFnTy) {
     enc_fn_style(w, ft.fn_style);
     enc_abi(w, ft.abi);
     enc_fn_sig(w, cx, &ft.sig);
 }
 
-pub fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) {
+pub fn enc_closure_ty(w: &mut SeekableMemWriter, cx: &ctxt, ft: &ty::ClosureTy) {
     enc_fn_style(w, ft.fn_style);
     enc_onceness(w, ft.onceness);
     enc_trait_store(w, cx, ft.store);
@@ -330,7 +331,7 @@ pub fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) {
     enc_abi(w, ft.abi);
 }
 
-fn enc_fn_sig(w: &mut MemWriter, cx: &ctxt, fsig: &ty::FnSig) {
+fn enc_fn_sig(w: &mut SeekableMemWriter, cx: &ctxt, fsig: &ty::FnSig) {
     mywrite!(w, "[{}|", fsig.binder_id);
     for ty in fsig.inputs.iter() {
         enc_ty(w, cx, *ty);
@@ -344,7 +345,7 @@ fn enc_fn_sig(w: &mut MemWriter, cx: &ctxt, fsig: &ty::FnSig) {
     enc_ty(w, cx, fsig.output);
 }
 
-fn enc_bounds(w: &mut MemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
+fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
     for bound in bs.builtin_bounds.iter() {
         match bound {
             ty::BoundSend => mywrite!(w, "S"),
@@ -363,7 +364,7 @@ fn enc_bounds(w: &mut MemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
     mywrite!(w, ".");
 }
 
-pub fn enc_type_param_def(w: &mut MemWriter, cx: &ctxt, v: &ty::TypeParameterDef) {
+pub fn enc_type_param_def(w: &mut SeekableMemWriter, cx: &ctxt, v: &ty::TypeParameterDef) {
     mywrite!(w, "{}:{}|{}|{}|",
              token::get_ident(v.ident), (cx.ds)(v.def_id),
              v.space.to_uint(), v.index);
index 722715405bce4ec08c06e69f070ac309f712f1ba..9a587dd77418259b7000b976386c77c0cbdfdd23 100644 (file)
@@ -28,6 +28,7 @@
 use middle::subst::VecPerParamSpace;
 use middle::typeck::{MethodCall, MethodCallee, MethodOrigin};
 use middle::{ty, typeck};
+use util::io::SeekableMemWriter;
 use util::ppaux::ty_to_string;
 
 use syntax::{ast, ast_map, ast_util, codemap, fold};
@@ -39,7 +40,6 @@
 
 use libc;
 use std::io::Seek;
-use std::io::MemWriter;
 use std::mem;
 use std::gc::GC;
 
@@ -73,7 +73,7 @@ trait tr_intern {
     fn tr_intern(&self, xcx: &ExtendedDecodeContext) -> ast::DefId;
 }
 
-pub type Encoder<'a> = writer::Encoder<'a, MemWriter>;
+pub type Encoder<'a> = writer::Encoder<'a, SeekableMemWriter>;
 
 // ______________________________________________________________________
 // Top-level methods.
@@ -1573,10 +1573,8 @@ fn mk_ctxt() -> parse::ParseSess {
 
 #[cfg(test)]
 fn roundtrip(in_item: Option<Gc<ast::Item>>) {
-    use std::io::MemWriter;
-
     let in_item = in_item.unwrap();
-    let mut wr = MemWriter::new();
+    let mut wr = SeekableMemWriter::new();
     {
         let mut ebml_w = writer::Encoder::new(&mut wr);
         encode_item_ast(&mut ebml_w, in_item);
diff --git a/src/librustc/util/io.rs b/src/librustc/util/io.rs
new file mode 100644 (file)
index 0000000..f153aca
--- /dev/null
@@ -0,0 +1,232 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::io::{IoError, IoResult, SeekStyle};
+use std::io;
+use std::slice;
+
+static BUF_CAPACITY: uint = 128;
+
+fn combine(seek: SeekStyle, cur: uint, end: uint, offset: i64) -> IoResult<u64> {
+    // compute offset as signed and clamp to prevent overflow
+    let pos = match seek {
+        io::SeekSet => 0,
+        io::SeekEnd => end,
+        io::SeekCur => cur,
+    } as i64;
+
+    if offset + pos < 0 {
+        Err(IoError {
+            kind: io::InvalidInput,
+            desc: "invalid seek to a negative offset",
+            detail: None
+        })
+    } else {
+        Ok((offset + pos) as u64)
+    }
+}
+
+/// Writes to an owned, growable byte vector that supports seeking.
+///
+/// # Example
+///
+/// ```rust
+/// # #![allow(unused_must_use)]
+/// use std::io::SeekableMemWriter;
+///
+/// let mut w = SeekableMemWriter::new();
+/// w.write([0, 1, 2]);
+///
+/// assert_eq!(w.unwrap(), vec!(0, 1, 2));
+/// ```
+pub struct SeekableMemWriter {
+    buf: Vec<u8>,
+    pos: uint,
+}
+
+impl SeekableMemWriter {
+    /// Create a new `SeekableMemWriter`.
+    #[inline]
+    pub fn new() -> SeekableMemWriter {
+        SeekableMemWriter::with_capacity(BUF_CAPACITY)
+    }
+    /// Create a new `SeekableMemWriter`, allocating at least `n` bytes for
+    /// the internal buffer.
+    #[inline]
+    pub fn with_capacity(n: uint) -> SeekableMemWriter {
+        SeekableMemWriter { buf: Vec::with_capacity(n), pos: 0 }
+    }
+
+    /// Acquires an immutable reference to the underlying buffer of this
+    /// `SeekableMemWriter`.
+    ///
+    /// No method is exposed for acquiring a mutable reference to the buffer
+    /// because it could corrupt the state of this `MemWriter`.
+    #[inline]
+    pub fn get_ref<'a>(&'a self) -> &'a [u8] { self.buf.as_slice() }
+
+    /// Unwraps this `SeekableMemWriter`, returning the underlying buffer
+    #[inline]
+    pub fn unwrap(self) -> Vec<u8> { self.buf }
+}
+
+impl Writer for SeekableMemWriter {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        if self.pos == self.buf.len() {
+            self.buf.push_all(buf)
+        } else {
+            // Make sure the internal buffer is as least as big as where we
+            // currently are
+            let difference = self.pos as i64 - self.buf.len() as i64;
+            if difference > 0 {
+                self.buf.grow(difference as uint, &0);
+            }
+
+            // Figure out what bytes will be used to overwrite what's currently
+            // there (left), and what will be appended on the end (right)
+            let cap = self.buf.len() - self.pos;
+            let (left, right) = if cap <= buf.len() {
+                (buf.slice_to(cap), buf.slice_from(cap))
+            } else {
+                (buf, &[])
+            };
+
+            // Do the necessary writes
+            if left.len() > 0 {
+                slice::bytes::copy_memory(self.buf.mut_slice_from(self.pos), left);
+            }
+            if right.len() > 0 {
+                self.buf.push_all(right);
+            }
+        }
+
+        // Bump us forward
+        self.pos += buf.len();
+        Ok(())
+    }
+}
+
+impl Seek for SeekableMemWriter {
+    #[inline]
+    fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
+
+    #[inline]
+    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
+        let new = try!(combine(style, self.pos, self.buf.len(), pos));
+        self.pos = new as uint;
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::SeekableMemWriter;
+    use std::io;
+    use test::Bencher;
+
+    #[test]
+    fn test_seekable_mem_writer() {
+        let mut writer = SeekableMemWriter::new();
+        assert_eq!(writer.tell(), Ok(0));
+        writer.write([0]).unwrap();
+        assert_eq!(writer.tell(), Ok(1));
+        writer.write([1, 2, 3]).unwrap();
+        writer.write([4, 5, 6, 7]).unwrap();
+        assert_eq!(writer.tell(), Ok(8));
+        assert_eq!(writer.get_ref(), &[0, 1, 2, 3, 4, 5, 6, 7]);
+
+        writer.seek(0, io::SeekSet).unwrap();
+        assert_eq!(writer.tell(), Ok(0));
+        writer.write([3, 4]).unwrap();
+        assert_eq!(writer.get_ref(), &[3, 4, 2, 3, 4, 5, 6, 7]);
+
+        writer.seek(1, io::SeekCur).unwrap();
+        writer.write([0, 1]).unwrap();
+        assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 7]);
+
+        writer.seek(-1, io::SeekEnd).unwrap();
+        writer.write([1, 2]).unwrap();
+        assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 1, 2]);
+
+        writer.seek(1, io::SeekEnd).unwrap();
+        writer.write([1]).unwrap();
+        assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]);
+    }
+
+    #[test]
+    fn seek_past_end() {
+        let mut r = SeekableMemWriter::new();
+        r.seek(10, io::SeekSet).unwrap();
+        assert!(r.write([3]).is_ok());
+    }
+
+    #[test]
+    fn seek_before_0() {
+        let mut r = SeekableMemWriter::new();
+        assert!(r.seek(-1, io::SeekSet).is_err());
+    }
+
+    fn do_bench_seekable_mem_writer(b: &mut Bencher, times: uint, len: uint) {
+        let src: Vec<u8> = Vec::from_elem(len, 5);
+
+        b.bytes = (times * len) as u64;
+        b.iter(|| {
+            let mut wr = SeekableMemWriter::new();
+            for _ in range(0, times) {
+                wr.write(src.as_slice()).unwrap();
+            }
+
+            let v = wr.unwrap();
+            assert_eq!(v.len(), times * len);
+            assert!(v.iter().all(|x| *x == 5));
+        });
+    }
+
+    #[bench]
+    fn bench_seekable_mem_writer_001_0000(b: &mut Bencher) {
+        do_bench_seekable_mem_writer(b, 1, 0)
+    }
+
+    #[bench]
+    fn bench_seekable_mem_writer_001_0010(b: &mut Bencher) {
+        do_bench_seekable_mem_writer(b, 1, 10)
+    }
+
+    #[bench]
+    fn bench_seekable_mem_writer_001_0100(b: &mut Bencher) {
+        do_bench_seekable_mem_writer(b, 1, 100)
+    }
+
+    #[bench]
+    fn bench_seekable_mem_writer_001_1000(b: &mut Bencher) {
+        do_bench_seekable_mem_writer(b, 1, 1000)
+    }
+
+    #[bench]
+    fn bench_seekable_mem_writer_100_0000(b: &mut Bencher) {
+        do_bench_seekable_mem_writer(b, 100, 0)
+    }
+
+    #[bench]
+    fn bench_seekable_mem_writer_100_0010(b: &mut Bencher) {
+        do_bench_seekable_mem_writer(b, 100, 10)
+    }
+
+    #[bench]
+    fn bench_seekable_mem_writer_100_0100(b: &mut Bencher) {
+        do_bench_seekable_mem_writer(b, 100, 100)
+    }
+
+    #[bench]
+    fn bench_seekable_mem_writer_100_1000(b: &mut Bencher) {
+        do_bench_seekable_mem_writer(b, 100, 1000)
+    }
+}
index dfce1eeb832d574a635e4ac8abf8041513470dfd..c3434466836175f85242aabbbbff81c343fc3469 100644 (file)
@@ -1023,8 +1023,124 @@ mod tests {
     use ebml::writer;
     use {Encodable, Decodable};
 
-    use std::io::MemWriter;
+    use std::io::{IoError, IoResult, SeekStyle};
+    use std::io;
     use std::option::{None, Option, Some};
+    use std::slice;
+
+    static BUF_CAPACITY: uint = 128;
+
+    fn combine(seek: SeekStyle, cur: uint, end: uint, offset: i64) -> IoResult<u64> {
+        // compute offset as signed and clamp to prevent overflow
+        let pos = match seek {
+            io::SeekSet => 0,
+            io::SeekEnd => end,
+            io::SeekCur => cur,
+        } as i64;
+
+        if offset + pos < 0 {
+            Err(IoError {
+                kind: io::InvalidInput,
+                desc: "invalid seek to a negative offset",
+                detail: None
+            })
+        } else {
+            Ok((offset + pos) as u64)
+        }
+    }
+
+    /// Writes to an owned, growable byte vector that supports seeking.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// # #![allow(unused_must_use)]
+    /// use std::io::SeekableMemWriter;
+    ///
+    /// let mut w = SeekableMemWriter::new();
+    /// w.write([0, 1, 2]);
+    ///
+    /// assert_eq!(w.unwrap(), vec!(0, 1, 2));
+    /// ```
+    pub struct SeekableMemWriter {
+        buf: Vec<u8>,
+        pos: uint,
+    }
+
+    impl SeekableMemWriter {
+        /// Create a new `SeekableMemWriter`.
+        #[inline]
+        pub fn new() -> SeekableMemWriter {
+            SeekableMemWriter::with_capacity(BUF_CAPACITY)
+        }
+        /// Create a new `SeekableMemWriter`, allocating at least `n` bytes for
+        /// the internal buffer.
+        #[inline]
+        pub fn with_capacity(n: uint) -> SeekableMemWriter {
+            SeekableMemWriter { buf: Vec::with_capacity(n), pos: 0 }
+        }
+
+        /// Acquires an immutable reference to the underlying buffer of this
+        /// `SeekableMemWriter`.
+        ///
+        /// No method is exposed for acquiring a mutable reference to the buffer
+        /// because it could corrupt the state of this `MemWriter`.
+        #[inline]
+        pub fn get_ref<'a>(&'a self) -> &'a [u8] { self.buf.as_slice() }
+
+        /// Unwraps this `SeekableMemWriter`, returning the underlying buffer
+        #[inline]
+        pub fn unwrap(self) -> Vec<u8> { self.buf }
+    }
+
+    impl Writer for SeekableMemWriter {
+        #[inline]
+        fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+            if self.pos == self.buf.len() {
+                self.buf.push_all(buf)
+            } else {
+                // Make sure the internal buffer is as least as big as where we
+                // currently are
+                let difference = self.pos as i64 - self.buf.len() as i64;
+                if difference > 0 {
+                    self.buf.grow(difference as uint, &0);
+                }
+
+                // Figure out what bytes will be used to overwrite what's currently
+                // there (left), and what will be appended on the end (right)
+                let cap = self.buf.len() - self.pos;
+                let (left, right) = if cap <= buf.len() {
+                    (buf.slice_to(cap), buf.slice_from(cap))
+                } else {
+                    (buf, &[])
+                };
+
+                // Do the necessary writes
+                if left.len() > 0 {
+                    slice::bytes::copy_memory(self.buf.mut_slice_from(self.pos), left);
+                }
+                if right.len() > 0 {
+                    self.buf.push_all(right);
+                }
+            }
+
+            // Bump us forward
+            self.pos += buf.len();
+            Ok(())
+        }
+    }
+
+    impl Seek for SeekableMemWriter {
+        #[inline]
+        fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
+
+        #[inline]
+        fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
+            let new = try!(combine(style, self.pos, self.buf.len(), pos));
+            self.pos = new as uint;
+            Ok(())
+        }
+    }
 
     #[test]
     fn test_vuint_at() {
@@ -1078,7 +1194,7 @@ fn test_vuint_at() {
     fn test_option_int() {
         fn test_v(v: Option<int>) {
             debug!("v == {}", v);
-            let mut wr = MemWriter::new();
+            let mut wr = SeekableMemWriter::new();
             {
                 let mut ebml_w = writer::Encoder::new(&mut wr);
                 let _ = v.encode(&mut ebml_w);
index a56904c9ef4db700d0c2917d7f5b531082327488..0752c68f4d0b29d5bb9f107438f9cc1165345608 100644 (file)
@@ -2991,7 +2991,7 @@ fn assert_stream_equal(src: &str,
                 Some(e) => e,
                 None => { break; }
             };
-            let (ref expected_evt, ref expected_stack) = *expected.get(i);
+            let (ref expected_evt, ref expected_stack) = expected[i];
             if !parser.stack().is_equal_to(expected_stack.as_slice()) {
                 fail!("Parser stack is not equal to {}", expected_stack);
             }
index fcb41c8f6fcc7a5be96e5fbd5c56feb4a8f2bf67..1b2706b3f5b22c8434e6af0853911e52ad1554fa 100644 (file)
@@ -955,7 +955,7 @@ macro_rules! error( ($e:expr, $s:expr) => (
         }
     ) )
 
-    struct TempDir(Path);
+    pub struct TempDir(Path);
 
     impl TempDir {
         fn join(&self, path: &str) -> Path {
index b93b84b7d63f3a6dc5eedb524f8bf6f5629e88ac..8879f7e25063cb56890d5f57daee1d5cb8717e55 100644 (file)
@@ -22,6 +22,8 @@
 use slice::{Vector, ImmutableVector, MutableVector};
 use vec::Vec;
 
+static BUF_CAPACITY: uint = 128;
+
 fn combine(seek: SeekStyle, cur: uint, end: uint, offset: i64) -> IoResult<u64> {
     // compute offset as signed and clamp to prevent overflow
     let pos = match seek {
@@ -54,29 +56,26 @@ fn combine(seek: SeekStyle, cur: uint, end: uint, offset: i64) -> IoResult<u64>
 ///
 /// assert_eq!(w.unwrap(), vec!(0, 1, 2));
 /// ```
+#[deriving(Clone)]
 pub struct MemWriter {
     buf: Vec<u8>,
-    pos: uint,
 }
 
 impl MemWriter {
     /// Create a new `MemWriter`.
     #[inline]
     pub fn new() -> MemWriter {
-        MemWriter::with_capacity(128)
+        MemWriter::with_capacity(BUF_CAPACITY)
     }
     /// Create a new `MemWriter`, allocating at least `n` bytes for
     /// the internal buffer.
     #[inline]
     pub fn with_capacity(n: uint) -> MemWriter {
-        MemWriter { buf: Vec::with_capacity(n), pos: 0 }
+        MemWriter { buf: Vec::with_capacity(n) }
     }
 
     /// Acquires an immutable reference to the underlying buffer of this
     /// `MemWriter`.
-    ///
-    /// No method is exposed for acquiring a mutable reference to the buffer
-    /// because it could corrupt the state of this `MemWriter`.
     #[inline]
     pub fn get_ref<'a>(&'a self) -> &'a [u8] { self.buf.as_slice() }
 
@@ -88,44 +87,7 @@ pub fn unwrap(self) -> Vec<u8> { self.buf }
 impl Writer for MemWriter {
     #[inline]
     fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        // Make sure the internal buffer is as least as big as where we
-        // currently are
-        let difference = self.pos as i64 - self.buf.len() as i64;
-        if difference > 0 {
-            self.buf.grow(difference as uint, &0);
-        }
-
-        // Figure out what bytes will be used to overwrite what's currently
-        // there (left), and what will be appended on the end (right)
-        let cap = self.buf.len() - self.pos;
-        let (left, right) = if cap <= buf.len() {
-            (buf.slice_to(cap), buf.slice_from(cap))
-        } else {
-            (buf, &[])
-        };
-
-        // Do the necessary writes
-        if left.len() > 0 {
-            slice::bytes::copy_memory(self.buf.mut_slice_from(self.pos), left);
-        }
-        if right.len() > 0 {
-            self.buf.push_all(right);
-        }
-
-        // Bump us forward
-        self.pos += buf.len();
-        Ok(())
-    }
-}
-
-impl Seek for MemWriter {
-    #[inline]
-    fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
-
-    #[inline]
-    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
-        let new = try!(combine(style, self.pos, self.buf.len(), pos));
-        self.pos = new as uint;
+        self.buf.push_all(buf);
         Ok(())
     }
 }
@@ -381,30 +343,10 @@ mod test {
     #[test]
     fn test_mem_writer() {
         let mut writer = MemWriter::new();
-        assert_eq!(writer.tell(), Ok(0));
         writer.write([0]).unwrap();
-        assert_eq!(writer.tell(), Ok(1));
         writer.write([1, 2, 3]).unwrap();
         writer.write([4, 5, 6, 7]).unwrap();
-        assert_eq!(writer.tell(), Ok(8));
         assert_eq!(writer.get_ref(), &[0, 1, 2, 3, 4, 5, 6, 7]);
-
-        writer.seek(0, SeekSet).unwrap();
-        assert_eq!(writer.tell(), Ok(0));
-        writer.write([3, 4]).unwrap();
-        assert_eq!(writer.get_ref(), &[3, 4, 2, 3, 4, 5, 6, 7]);
-
-        writer.seek(1, SeekCur).unwrap();
-        writer.write([0, 1]).unwrap();
-        assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 7]);
-
-        writer.seek(-1, SeekEnd).unwrap();
-        writer.write([1, 2]).unwrap();
-        assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 1, 2]);
-
-        writer.seek(1, SeekEnd).unwrap();
-        writer.write([1]).unwrap();
-        assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]);
     }
 
     #[test]
@@ -570,10 +512,6 @@ fn seek_past_end() {
         r.seek(10, SeekSet).unwrap();
         assert!(r.read(&mut []).is_err());
 
-        let mut r = MemWriter::new();
-        r.seek(10, SeekSet).unwrap();
-        assert!(r.write([3]).is_ok());
-
         let mut buf = [0];
         let mut r = BufWriter::new(buf);
         r.seek(10, SeekSet).unwrap();
@@ -589,9 +527,6 @@ fn seek_before_0() {
         let mut r = MemReader::new(vec!(10));
         assert!(r.seek(-1, SeekSet).is_err());
 
-        let mut r = MemWriter::new();
-        assert!(r.seek(-1, SeekSet).is_err());
-
         let mut buf = [0];
         let mut r = BufWriter::new(buf);
         assert!(r.seek(-1, SeekSet).is_err());
@@ -614,6 +549,7 @@ fn io_read_at_least() {
     fn do_bench_mem_writer(b: &mut Bencher, times: uint, len: uint) {
         let src: Vec<u8> = Vec::from_elem(len, 5);
 
+        b.bytes = (times * len) as u64;
         b.iter(|| {
             let mut wr = MemWriter::new();
             for _ in range(0, times) {
index 4ab9d1b486a34170ba9683c044b6207c7b2d190a..675588a4460fffd3ba82f3cfbaefed12040bd5c1 100644 (file)
@@ -136,7 +136,7 @@ pub fn to_string(f: |&mut State| -> IoResult<()>) -> String {
         // downcasts.
         let (_, wr): (uint, Box<MemWriter>) = mem::transmute_copy(&s.s.out);
         let result =
-            String::from_utf8(Vec::from_slice(wr.get_ref())).unwrap();
+            String::from_utf8(Vec::from_slice(wr.get_ref().as_slice())).unwrap();
         mem::forget(wr);
         result.to_string()
     }
index 0e29e6215032ae104c3531a8748424bae6c0b94b..037afce9b167a7c5a404ff3906af076d7ffa8bca 100644 (file)
@@ -790,16 +790,12 @@ fn test_rand_rand() {
 
     #[test]
     fn test_serialize_round_trip() {
-        use serialize::ebml::Doc;
-        use serialize::ebml::writer::Encoder;
-        use serialize::ebml::reader::Decoder;
+        use serialize::json;
         use serialize::{Encodable, Decodable};
 
         let u = Uuid::new_v4();
-        let mut wr = MemWriter::new();
-        let _ = u.encode(&mut Encoder::new(&mut wr));
-        let doc = Doc::new(wr.get_ref());
-        let u2 = Decodable::decode(&mut Decoder::new(doc)).unwrap();
+        let s = json::encode(&u);
+        let u2 = json::decode(s.as_slice()).unwrap();
         assert_eq!(u, u2);
     }
 
index a7738bb803cf5cae24f1531f9d8c9977c3841ea2..9eef83184e139e49d049bedc996a6068e53a8138 100644 (file)
@@ -16,9 +16,7 @@
 use std::cell::{Cell, RefCell};
 use std::io::MemWriter;
 use serialize::{Encodable, Decodable};
-use serialize::ebml;
-use serialize::ebml::writer::Encoder;
-use serialize::ebml::reader::Decoder;
+use serialize::json;
 
 #[deriving(Encodable, Decodable)]
 struct A {
@@ -36,20 +34,8 @@ fn main() {
         foo: Cell::new(true),
         bar: RefCell::new( A { baz: 2 } )
     };
-    let mut w = MemWriter::new();
-    {
-        let mut e = Encoder::new(&mut w);
-        match obj.encode(&mut e) {
-            Ok(()) => (),
-            Err(e) => fail!("Failed to encode: {}", e)
-        };
-    }
-    let doc = ebml::Doc::new(w.get_ref());
-    let mut dec = Decoder::new(doc);
-    let obj2: B = match Decodable::decode(&mut dec) {
-        Ok(v) => v,
-        Err(e) => fail!("Failed to decode: {}", e)
-    };
+    let s = json::encode(&obj);
+    let obj2: B = json::decode(s.as_slice()).unwrap();
     assert!(obj.foo.get() == obj2.foo.get());
     assert!(obj.bar.borrow().baz == obj2.bar.borrow().baz);
 }
index e0cd91adb1c595724bdd945be55d390032824141..d7f487b629b5eb05817ad3f93631d0606eb1fba8 100644 (file)
 
 extern crate serialize;
 
+use std::io;
+use std::io::{IoError, IoResult, SeekStyle};
+use std::slice;
+
 use serialize::{Encodable, Encoder};
 use serialize::json;
 use serialize::ebml::writer;
-use std::io::MemWriter;
+
+static BUF_CAPACITY: uint = 128;
+
+fn combine(seek: SeekStyle, cur: uint, end: uint, offset: i64) -> IoResult<u64> {
+    // compute offset as signed and clamp to prevent overflow
+    let pos = match seek {
+        io::SeekSet => 0,
+        io::SeekEnd => end,
+        io::SeekCur => cur,
+    } as i64;
+
+    if offset + pos < 0 {
+        Err(IoError {
+            kind: io::InvalidInput,
+            desc: "invalid seek to a negative offset",
+            detail: None
+        })
+    } else {
+        Ok((offset + pos) as u64)
+    }
+}
+
+/// Writes to an owned, growable byte vector that supports seeking.
+///
+/// # Example
+///
+/// ```rust
+/// # #![allow(unused_must_use)]
+/// use std::io::SeekableMemWriter;
+///
+/// let mut w = SeekableMemWriter::new();
+/// w.write([0, 1, 2]);
+///
+/// assert_eq!(w.unwrap(), vec!(0, 1, 2));
+/// ```
+pub struct SeekableMemWriter {
+    buf: Vec<u8>,
+    pos: uint,
+}
+
+impl SeekableMemWriter {
+    /// Create a new `SeekableMemWriter`.
+    #[inline]
+    pub fn new() -> SeekableMemWriter {
+        SeekableMemWriter::with_capacity(BUF_CAPACITY)
+    }
+    /// Create a new `SeekableMemWriter`, allocating at least `n` bytes for
+    /// the internal buffer.
+    #[inline]
+    pub fn with_capacity(n: uint) -> SeekableMemWriter {
+        SeekableMemWriter { buf: Vec::with_capacity(n), pos: 0 }
+    }
+
+    /// Acquires an immutable reference to the underlying buffer of this
+    /// `SeekableMemWriter`.
+    ///
+    /// No method is exposed for acquiring a mutable reference to the buffer
+    /// because it could corrupt the state of this `MemWriter`.
+    #[inline]
+    pub fn get_ref<'a>(&'a self) -> &'a [u8] { self.buf.as_slice() }
+
+    /// Unwraps this `SeekableMemWriter`, returning the underlying buffer
+    #[inline]
+    pub fn unwrap(self) -> Vec<u8> { self.buf }
+}
+
+impl Writer for SeekableMemWriter {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        if self.pos == self.buf.len() {
+            self.buf.push_all(buf)
+        } else {
+            // Make sure the internal buffer is as least as big as where we
+            // currently are
+            let difference = self.pos as i64 - self.buf.len() as i64;
+            if difference > 0 {
+                self.buf.grow(difference as uint, &0);
+            }
+
+            // Figure out what bytes will be used to overwrite what's currently
+            // there (left), and what will be appended on the end (right)
+            let cap = self.buf.len() - self.pos;
+            let (left, right) = if cap <= buf.len() {
+                (buf.slice_to(cap), buf.slice_from(cap))
+            } else {
+                (buf, &[])
+            };
+
+            // Do the necessary writes
+            if left.len() > 0 {
+                slice::bytes::copy_memory(self.buf.mut_slice_from(self.pos), left);
+            }
+            if right.len() > 0 {
+                self.buf.push_all(right);
+            }
+        }
+
+        // Bump us forward
+        self.pos += buf.len();
+        Ok(())
+    }
+}
+
+impl Seek for SeekableMemWriter {
+    #[inline]
+    fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
+
+    #[inline]
+    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
+        let new = try!(combine(style, self.pos, self.buf.len(), pos));
+        self.pos = new as uint;
+        Ok(())
+    }
+}
 
 #[deriving(Encodable)]
 struct Foo {
@@ -34,21 +151,21 @@ enum WireProtocol {
 fn encode_json<'a,
                T: Encodable<json::Encoder<'a>,
                             std::io::IoError>>(val: &T,
-                                               wr: &'a mut MemWriter) {
+                                               wr: &'a mut SeekableMemWriter) {
     let mut encoder = json::Encoder::new(wr);
     val.encode(&mut encoder);
 }
 fn encode_ebml<'a,
-               T: Encodable<writer::Encoder<'a, MemWriter>,
+               T: Encodable<writer::Encoder<'a, SeekableMemWriter>,
                             std::io::IoError>>(val: &T,
-                                               wr: &'a mut MemWriter) {
+                                               wr: &'a mut SeekableMemWriter) {
     let mut encoder = writer::Encoder::new(wr);
     val.encode(&mut encoder);
 }
 
 pub fn main() {
     let target = Foo{baz: false,};
-    let mut wr = MemWriter::new();
+    let mut wr = SeekableMemWriter::new();
     let proto = JSON;
     match proto {
         JSON => encode_json(&target, &mut wr),