Skip to content

Commit

Permalink
Implement the other direction of encoder/decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcrichton committed Jul 23, 2014
1 parent 3a5e816 commit 240b27c
Show file tree
Hide file tree
Showing 4 changed files with 412 additions and 145 deletions.
121 changes: 102 additions & 19 deletions src/deflate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,44 @@ use std::io::IoResult;
///
/// This structure implements a `Writer` interface and takes a stream of
/// uncompressed data, writing the compressed data to the wrapped writer.
pub struct Encoder<W> {
inner: ::Encoder<W>,
pub struct EncoderWriter<W> {
inner: ::EncoderWriter<W>,
}

/// A DEFLATE encoder, or compressor.
///
/// This structure implements a `Reader` interface and will read uncompressed
/// data from an underlying stream and emit a stream of compressed data.
pub struct EncoderReader<R> {
inner: ::EncoderReader<R>,
}

/// A DEFLATE decoder, or decompressor.
///
/// This structure implements a `Reader` interface and takes a stream of
/// compressed data as input, providing the decompressed data when read from.
pub struct Decoder<R> {
inner: ::Decoder<R>,
pub struct DecoderReader<R> {
inner: ::DecoderReader<R>,
}

impl<W: Writer> Encoder<W> {
/// A DEFLATE decoder, or decompressor.
///
/// This structure implements a `Writer` and will emit a stream of decompressed
/// data when fed a stream of compressed data.
pub struct DecoderWriter<W> {
inner: ::DecoderWriter<W>,
}

impl<W: Writer> EncoderWriter<W> {
/// Creates a new encoder which will write compressed data to the stream
/// given at the given compression level.
///
/// When this encoder is dropped or unwrapped the final pieces of data will
/// be flushed.
pub fn new(w: W, level: ::CompressionLevel) -> Encoder<W> {
Encoder {
inner: ::Encoder::new(w, level, true, Vec::with_capacity(128 * 1024))
pub fn new(w: W, level: ::CompressionLevel) -> EncoderWriter<W> {
EncoderWriter {
inner: ::EncoderWriter::new(w, level, true,
Vec::with_capacity(128 * 1024))
}
}

Expand All @@ -40,54 +57,120 @@ impl<W: Writer> Encoder<W> {
}
}

impl<W: Writer> Writer for Encoder<W> {
impl<W: Writer> Writer for EncoderWriter<W> {
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write(buf) }
fn flush(&mut self) -> IoResult<()> { self.inner.flush() }
}

impl<R: Reader> Decoder<R> {
impl<R: Reader> EncoderReader<R> {
/// Creates a new encoder which will read uncompressed data from the given
/// stream and emit the compressed stream.
pub fn new(r: R, level: ::CompressionLevel) -> EncoderReader<R> {
EncoderReader {
inner: ::EncoderReader::new(r, level, true,
Vec::with_capacity(128 * 1024))
}
}

/// Consumes this encoder, returning the underlying reader.
pub fn unwrap(self) -> R {
self.inner.inner
}
}

impl<R: Reader> Reader for EncoderReader<R> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.inner.read(buf) }
}

impl<R: Reader> DecoderReader<R> {
/// Creates a new decoder which will decompress data read from the given
/// stream.
pub fn new(r: R) -> Decoder<R> {
Decoder::new_with_buf(r, Vec::with_capacity(128 * 1024))
pub fn new(r: R) -> DecoderReader<R> {
DecoderReader::new_with_buf(r, Vec::with_capacity(128 * 1024))
}

/// Same as `new`, but the intermediate buffer for data is specified.
///
/// Note that the capacity of the intermediate buffer is never increased,
/// and it is recommended for it to be large.
pub fn new_with_buf(r: R, buf: Vec<u8>) -> Decoder<R> {
Decoder { inner: ::Decoder::new(r, true, buf) }
pub fn new_with_buf(r: R, buf: Vec<u8>) -> DecoderReader<R> {
DecoderReader { inner: ::DecoderReader::new(r, true, buf) }
}
}

impl<R: Reader> Reader for Decoder<R> {
impl<R: Reader> Reader for DecoderReader<R> {
fn read(&mut self, into: &mut [u8]) -> IoResult<uint> {
self.inner.read(into)
}
}

impl<W: Writer> DecoderWriter<W> {
/// Creates a new decoder which will write uncompressed data to the stream.
///
/// When this encoder is dropped or unwrapped the final pieces of data will
/// be flushed.
pub fn new(w: W) -> DecoderWriter<W> {
DecoderWriter {
inner: ::DecoderWriter::new(w, true, Vec::with_capacity(128 * 1024))
}
}

/// Consumes this encoder, flushing the output stream.
///
/// This will flush the underlying data stream and then return the contained
/// writer if the flush succeeded.
pub fn finish(mut self) -> IoResult<W> {
try!(self.inner.do_finish());
Ok(self.inner.inner.take().unwrap())
}
}

impl<W: Writer> Writer for DecoderWriter<W> {
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write(buf) }
fn flush(&mut self) -> IoResult<()> { self.inner.flush() }
}

#[cfg(test)]
mod tests {
use super::{Encoder, Decoder};
use std::io::{MemWriter, MemReader};
use super::{EncoderWriter, EncoderReader, DecoderReader, DecoderWriter};
use std::io::{MemWriter, MemReader, BufReader};
use std::rand::{task_rng, Rng};

use {Default};

#[test]
fn roundtrip() {
let mut real = Vec::new();
let mut w = Encoder::new(MemWriter::new(), Default);
let mut w = EncoderWriter::new(MemWriter::new(), Default);
let v = task_rng().gen_iter::<u8>().take(1024).collect::<Vec<_>>();
for _ in range(0u, 200) {
let to_write = v.slice_to(task_rng().gen_range(0, v.len()));
real.push_all(to_write);
w.write(to_write).unwrap();
}
let result = w.finish().unwrap();
let mut r = Decoder::new(MemReader::new(result.unwrap()));
let mut r = DecoderReader::new(MemReader::new(result.unwrap()));
assert!(r.read_to_end().unwrap() == real);
}

#[test]
fn roundtrip2() {
let v = task_rng().gen_iter::<u8>().take(1024 * 1024).collect::<Vec<_>>();
let v = v.as_slice();
let buf = BufReader::new(v);
let mut r = DecoderReader::new(EncoderReader::new(buf, Default));
assert!(r.read_to_end().unwrap().as_slice() == v);
}

#[test]
fn roundtrip3() {
let v = task_rng().gen_iter::<u8>().take(1024 * 1024).collect::<Vec<_>>();
let v = v.as_slice();
let mut w = EncoderWriter::new(DecoderWriter::new(MemWriter::new()),
Default);
w.write(v.as_slice()).unwrap();
let w = w.finish().unwrap().finish().unwrap().unwrap();
assert!(w.as_slice() == v);
}
}

8 changes: 4 additions & 4 deletions src/gz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ static FCOMMENT: u8 = 1 << 4;
/// This structure exposes a `Writer` interface that will emit compressed data
/// to the underlying writer `W`.
pub struct Encoder<W> {
inner: ::Encoder<W>,
inner: ::EncoderWriter<W>,
crc: libc::c_ulong,
amt: u32,
extra: Option<Vec<u8>>,
Expand All @@ -40,7 +40,7 @@ pub struct Encoder<W> {
/// This structure exposes a `Reader` interface that will consume compressed
/// data from the underlying reader and emit uncompressed data.
pub struct Decoder<R> {
inner: ::Decoder<R>,
inner: ::DecoderReader<R>,
crc: libc::c_ulong,
amt: u32,
extra: Option<Vec<u8>>,
Expand All @@ -57,7 +57,7 @@ impl<W: Writer> Encoder<W> {
/// methods of this encoder.
pub fn new(w: W, level: CompressionLevel) -> Encoder<W> {
Encoder {
inner: ::Encoder::new(w, level, true, Vec::with_capacity(128 * 1024)),
inner: ::EncoderWriter::new(w, level, true, Vec::with_capacity(128 * 1024)),
crc: 0,
amt: 0,
wrote_header: false,
Expand Down Expand Up @@ -259,7 +259,7 @@ impl<R: Reader> Decoder<R> {
}

return Ok(Decoder {
inner: ::Decoder::new(r, true, Vec::with_capacity(128 * 1024)),
inner: ::DecoderReader::new(r, true, Vec::with_capacity(128 * 1024)),
crc: 0,
amt: 0,
extra: extra,
Expand Down
Loading

0 comments on commit 240b27c

Please sign in to comment.