From 207790870b8639ce41ed609be20b991c3c37e764 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 2 Mar 2015 15:46:51 -0800 Subject: [PATCH] Don't call read_to_end to read a block of data Delegate to calling `read` at most one time instead. This requires initializing all buffers ahead of time to maintain the safe code invariant, but the writer abstractions can continue to use uninitialized memory (as miniz is known to not read it, just write it). Closes #16 --- src/deflate.rs | 10 ++++++---- src/gz.rs | 6 +++--- src/lib.rs | 3 +-- src/raw.rs | 34 ++++++++++++++++------------------ src/util.rs | 21 --------------------- src/zlib.rs | 10 ++++++---- 6 files changed, 32 insertions(+), 52 deletions(-) delete mode 100644 src/util.rs diff --git a/src/deflate.rs b/src/deflate.rs index 7806f549e..af37bc6d7 100644 --- a/src/deflate.rs +++ b/src/deflate.rs @@ -2,6 +2,7 @@ use std::io::prelude::*; use std::io; +use std::iter::repeat; use raw; @@ -46,7 +47,7 @@ impl EncoderWriter { pub fn new(w: W, level: ::Compression) -> EncoderWriter { EncoderWriter { inner: raw::EncoderWriter::new(w, level, true, - Vec::with_capacity(128 * 1024)) + Vec::with_capacity(32 * 1024)), } } @@ -71,7 +72,7 @@ impl EncoderReader { pub fn new(r: R, level: ::Compression) -> EncoderReader { EncoderReader { inner: raw::EncoderReader::new(r, level, true, - Vec::with_capacity(128 * 1024)) + repeat(0).take(32 * 1024).collect()), } } @@ -89,7 +90,7 @@ impl DecoderReader { /// Creates a new decoder which will decompress data read from the given /// stream. pub fn new(r: R) -> DecoderReader { - DecoderReader::new_with_buf(r, Vec::with_capacity(128 * 1024)) + DecoderReader::new_with_buf(r, repeat(0).take(32 * 1024).collect()) } /// Same as `new`, but the intermediate buffer for data is specified. @@ -114,7 +115,8 @@ impl DecoderWriter { /// be flushed. pub fn new(w: W) -> DecoderWriter { DecoderWriter { - inner: raw::DecoderWriter::new(w, true, Vec::with_capacity(128 * 1024)) + inner: raw::DecoderWriter::new(w, true, + Vec::with_capacity(32 * 1024)), } } diff --git a/src/gz.rs b/src/gz.rs index 77746d8e8..d6a7b73b2 100644 --- a/src/gz.rs +++ b/src/gz.rs @@ -114,7 +114,7 @@ impl Builder { pub fn write(self, w: W, lvl: Compression) -> EncoderWriter { EncoderWriter { inner: raw::EncoderWriter::new(w, lvl, true, - Vec::with_capacity(128 * 1024)), + Vec::with_capacity(32 * 1024)), crc: Crc::new(), header: self.into_header(lvl), } @@ -128,7 +128,7 @@ impl Builder { let crc = CrcReader::new(r); EncoderReader { inner: raw::EncoderReader::new(crc, lvl, true, - Vec::with_capacity(128 * 1024)), + repeat(0).take(32 * 1024).collect()), header: self.into_header(lvl), pos: 0, eof: false, @@ -374,7 +374,7 @@ impl DecoderReader { } let flate = raw::DecoderReader::new(crc_reader.into_inner(), true, - Vec::with_capacity(128 * 1024)); + repeat(0).take(32 * 1024).collect()); return Ok(DecoderReader { inner: CrcReader::new(flate), header: Header { diff --git a/src/lib.rs b/src/lib.rs index 013c94ab3..b607dfac5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ //! These provide convenience methods for creating a decoder/encoder out of an //! already existing stream to chain construction. -#![feature(io, core, collections, std_misc, env)] +#![feature(io, core, collections, std_misc)] #![deny(missing_docs)] #![feature(unsafe_destructor)] // #![cfg_attr(test, deny(warnings))] @@ -44,7 +44,6 @@ mod deflate; mod gz; mod raw; mod zlib; -mod util; /// Types which operate over `Reader` streams, both encoders and decoders for /// various formats. diff --git a/src/raw.rs b/src/raw.rs index 72c6e5f78..62f9e94f7 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -19,15 +19,17 @@ pub struct EncoderWriter { pub struct EncoderReader { pub inner: R, stream: Stream, - buf: Vec, + buf: Box<[u8]>, pos: usize, + cap: usize, } pub struct DecoderReader { pub inner: R, stream: Stream, pub pos: usize, - pub buf: Vec, + pub cap: usize, + pub buf: Box<[u8]>, } pub struct DecoderWriter { @@ -93,7 +95,8 @@ impl EncoderReader { EncoderReader { inner: w, stream: Stream::new(Deflate, raw, level), - buf: buf, + buf: buf.into_boxed_slice(), + cap: 0, pos: 0, } } @@ -101,7 +104,7 @@ impl EncoderReader { impl Read for EncoderReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.stream.read(buf, &mut self.buf, &mut self.pos, + self.stream.read(buf, &mut self.buf, &mut self.pos, &mut self.cap, &mut self.inner, ffi::mz_deflate) } } @@ -112,14 +115,15 @@ impl DecoderReader { inner: r, stream: Stream::new(Inflate, raw, Compression::None), pos: 0, - buf: buf, + buf: buf.into_boxed_slice(), + cap: 0, } } } impl Read for DecoderReader { fn read(&mut self, into: &mut [u8]) -> io::Result { - self.stream.read(into, &mut self.buf, &mut self.pos, + self.stream.read(into, &mut self.buf, &mut self.pos, &mut self.cap, &mut self.inner, ffi::mz_inflate) } } @@ -189,26 +193,20 @@ impl Stream { Stream(state, kind) } - fn read(&mut self, into: &mut [u8], buf: &mut Vec, - pos: &mut usize, reader: &mut R, + fn read(&mut self, into: &mut [u8], buf: &mut [u8], + pos: &mut usize, cap: &mut usize, reader: &mut R, f: unsafe extern fn(*mut ffi::mz_stream, libc::c_int) -> libc::c_int) -> io::Result { loop { let mut eof = false; - if *pos == buf.len() { - buf.truncate(0); + if *pos == *cap { + *cap = try!(reader.take(buf.len() as u64).read(buf)); *pos = 0; - // FIXME(rust-lang/rust#22640) this should be `.take()` - let mut r = ::util::Take { - limit: buf.capacity() as u64, - inner: &mut *reader, - }; - try!(r.read_to_end(buf)); - eof = buf.len() == 0; + eof = *cap == 0; } - let next_in = &buf[*pos..]; + let next_in = &buf[*pos..*cap]; self.next_in = next_in.as_ptr(); self.avail_in = next_in.len() as libc::c_uint; diff --git a/src/util.rs b/src/util.rs deleted file mode 100644 index 2032a066b..000000000 --- a/src/util.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::cmp; -use std::io::prelude::*; -use std::io; - -/// Reader adaptor which limits the bytes read from an underlying reader. -/// -/// For more information, see `ReadExt::take`. -pub struct Take { - pub inner: T, - pub limit: u64, -} - -impl Read for Take { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - if self.limit == 0 { return Ok(0) } - let max = cmp::min(buf.len() as u64, self.limit) as usize; - let n = try!(self.inner.read(&mut buf[..max])); - self.limit -= n as u64; - Ok(n) - } -} diff --git a/src/zlib.rs b/src/zlib.rs index 28ffb07ec..cc7602073 100644 --- a/src/zlib.rs +++ b/src/zlib.rs @@ -2,6 +2,7 @@ use std::io::prelude::*; use std::io; +use std::iter::repeat; use raw; @@ -46,7 +47,7 @@ impl EncoderWriter { pub fn new(w: W, level: ::Compression) -> EncoderWriter { EncoderWriter { inner: raw::EncoderWriter::new(w, level, false, - Vec::with_capacity(128 * 1024)) + Vec::with_capacity(32 * 1024)), } } @@ -71,7 +72,7 @@ impl EncoderReader { pub fn new(r: R, level: ::Compression) -> EncoderReader { EncoderReader { inner: raw::EncoderReader::new(r, level, false, - Vec::with_capacity(128 * 1024)) + repeat(0).take(32 * 1024).collect()) } } @@ -89,7 +90,7 @@ impl DecoderReader { /// Creates a new decoder which will decompress data read from the given /// stream. pub fn new(r: R) -> DecoderReader { - DecoderReader::new_with_buf(r, Vec::with_capacity(128 * 1024)) + DecoderReader::new_with_buf(r, repeat(0).take(32 * 1024).collect()) } /// Same as `new`, but the intermediate buffer for data is specified. @@ -114,7 +115,8 @@ impl DecoderWriter { /// be flushed. pub fn new(w: W) -> DecoderWriter { DecoderWriter { - inner: raw::DecoderWriter::new(w, false, Vec::with_capacity(128 * 1024)) + inner: raw::DecoderWriter::new(w, false, + Vec::with_capacity(32 * 1024)), } }