Skip to content

Commit

Permalink
Split Flush into two enums.
Browse files Browse the repository at this point in the history
The Flush enum is now FlushCompress and FlushDecompress. Each enum only
contains the valid types necessary for fuctioning of the compress and
decompress methods respectively. Also removed the Flush enum and added
a Flush trait to allow Writer to remain generic in Ops.
  • Loading branch information
chrisvittal committed May 6, 2017
1 parent 42156e6 commit 1bdd11c
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 38 deletions.
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ use std::io;

pub use gz::Builder as GzBuilder;
pub use gz::Header as GzHeader;
pub use mem::{Compress, Decompress, DataError, Status, Flush};
pub use mem::{Compress, Decompress, DataError, Status, FlushCompress, FlushDecompress};
use mem::Flush;
pub use crc::{Crc, CrcReader};

mod bufreader;
Expand Down
118 changes: 93 additions & 25 deletions src/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,22 @@ enum DirCompress {}
#[derive(Debug)]
enum DirDecompress {}

/// Values which indicate the form of flushing to be used when compressing or
/// decompressing in-memory data.
// A trait for being generic over our two flush enums, FlushCompress
// and FlushDecompress. These methods will panic if called for an invalid
// member of an enum. For example, FlushDecompress does not have Partial
// or Full members, so FlushDecompress::full() panics.
pub trait Flush {
fn none() -> Self;
fn sync() -> Self;
fn partial() -> Self;
fn full() -> Self;
fn finish() -> Self;
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Flush {
/// Values which indicate the form of flushing to be used when compressing
/// in-memory data.
pub enum FlushCompress {
/// A typical parameter for passing to compression/decompression functions,
/// this indicates that the underlying stream to decide how much data to
/// accumulate before producing output in order to maximize compression.
Expand All @@ -91,18 +103,6 @@ pub enum Flush {
/// block before the empty fixed code block.
Partial = ffi::MZ_PARTIAL_FLUSH as isize,

/// A deflate block is completed and emitted, as for `Flush::Sync`, but the
/// output is not aligned on a byte boundary and up to seven vits of the
/// current block are held to be written as the next byte after the next
/// deflate block is completed.
///
/// In this case the decompressor may not be provided enough bits at this
/// point in order to complete decompression of the data provided so far to
/// the compressor, it may need to wait for the next block to be emitted.
/// This is for advanced applications that need to control the emission of
/// deflate blocks.
Block = ffi::MZ_BLOCK as isize,

/// All output is flushed as with `Flush::Sync` and the compression state is
/// reset so decompression can restart from this point if previous
/// compressed data has been damaged or if random access is desired.
Expand All @@ -114,7 +114,75 @@ pub enum Flush {
///
/// The return value may indicate that the stream is not yet done and more
/// data has yet to be processed.
Finish = ffi::MZ_FINISH as isize,
Finish = ffi::MZ_FINISH as isize
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
/// Values which indicate the form of flushing to be used when or
/// decompressing in-memory data.
pub enum FlushDecompress {
/// A typical parameter for passing to compression/decompression functions,
/// this indicates that the underlying stream to decide how much data to
/// accumulate before producing output in order to maximize compression.
None = ffi::MZ_NO_FLUSH as isize,

/// All pending output is flushed to the output buffer and the output is
/// aligned on a byte boundary so that the decompressor can get all input
/// data available so far.
///
/// Flushing may degrade compression for some compression algorithms and so
/// it should only be used when necessary. This will complete the current
/// deflate block and follow it with an empty stored block.
Sync = ffi::MZ_SYNC_FLUSH as isize,

/// Pending input is processed and pending output is flushed.
///
/// The return value may indicate that the stream is not yet done and more
/// data has yet to be processed.
Finish = ffi::MZ_FINISH as isize
}

impl Flush for FlushCompress {
fn none() -> Self {
FlushCompress::None
}

fn sync() -> Self {
FlushCompress::Sync
}

fn partial() -> Self {
FlushCompress::Partial
}

fn full() -> Self {
FlushCompress::Full
}

fn finish() -> Self {
FlushCompress::Finish
}
}
impl Flush for FlushDecompress {
fn none() -> Self {
FlushDecompress::None
}

fn sync() -> Self {
FlushDecompress::Sync
}

fn partial() -> Self {
panic!("Partial not valid for decompression");
}

fn full() -> Self {
panic!("Full not valid for decompression");
}

fn finish() -> Self {
FlushDecompress::Finish
}
}

/// Error returned when a decompression object finds that the input stream of
Expand Down Expand Up @@ -215,7 +283,7 @@ impl Compress {
pub fn compress(&mut self,
input: &[u8],
output: &mut [u8],
flush: Flush)
flush: FlushCompress)
-> Status {
let raw = &mut *self.inner.stream_wrapper;
raw.next_in = input.as_ptr() as *mut _;
Expand Down Expand Up @@ -251,7 +319,7 @@ impl Compress {
pub fn compress_vec(&mut self,
input: &[u8],
output: &mut Vec<u8>,
flush: Flush)
flush: FlushCompress)
-> Status {
let cap = output.capacity();
let len = output.len();
Expand Down Expand Up @@ -330,7 +398,7 @@ impl Decompress {
pub fn decompress(&mut self,
input: &[u8],
output: &mut [u8],
flush: Flush)
flush: FlushDecompress)
-> Result<Status, DataError> {
let raw = &mut *self.inner.stream_wrapper;
raw.next_in = input.as_ptr() as *mut u8;
Expand Down Expand Up @@ -374,7 +442,7 @@ impl Decompress {
pub fn decompress_vec(&mut self,
input: &[u8],
output: &mut Vec<u8>,
flush: Flush)
flush: FlushDecompress)
-> Result<Status, DataError> {
let cap = output.capacity();
let len = output.len();
Expand Down Expand Up @@ -463,7 +531,7 @@ mod tests {
use std::io::Write;

use write;
use {Compression, Decompress, Flush};
use {Compression, Decompress, FlushDecompress};

#[test]
fn issue51() {
Expand All @@ -485,11 +553,11 @@ mod tests {

let mut d = Decompress::new(false);
// decompressed whole deflate stream
assert!(d.decompress_vec(&data[10..], &mut decoded, Flush::Finish).is_ok());
assert!(d.decompress_vec(&data[10..], &mut decoded, FlushDecompress::Finish).is_ok());

// decompress data that has nothing to do with the deflate stream (this
// used to panic)
drop(d.decompress_vec(&[0], &mut decoded, Flush::None));
drop(d.decompress_vec(&[0], &mut decoded, FlushDecompress::None));
}

#[test]
Expand All @@ -504,12 +572,12 @@ mod tests {

let mut dst = [0; 1024];
let mut decoder = Decompress::new(true);
decoder.decompress(&zlib, &mut dst, Flush::Finish).unwrap();
decoder.decompress(&zlib, &mut dst, FlushDecompress::Finish).unwrap();
assert_eq!(decoder.total_out(), string.len() as u64);
assert!(dst.starts_with(string));

decoder.reset(false);
decoder.decompress(&deflate, &mut dst, Flush::Finish).unwrap();
decoder.decompress(&deflate, &mut dst, FlushDecompress::Finish).unwrap();
assert_eq!(decoder.total_out(), string.len() as u64);
assert!(dst.starts_with(string));
}
Expand Down
31 changes: 19 additions & 12 deletions src/zio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::io::prelude::*;
use std::io;
use std::mem;

use {Decompress, Compress, Status, Flush, DataError};
use {Decompress, Compress, Status, Flush, FlushCompress, FlushDecompress, DataError};

#[derive(Debug)]
pub struct Writer<W: Write, D: Ops> {
Expand All @@ -12,35 +12,38 @@ pub struct Writer<W: Write, D: Ops> {
}

pub trait Ops {
type Flush: Flush;
fn total_in(&self) -> u64;
fn total_out(&self) -> u64;
fn run(&mut self, input: &[u8], output: &mut [u8], flush: Flush)
fn run(&mut self, input: &[u8], output: &mut [u8], flush: Self::Flush)
-> Result<Status, DataError>;
fn run_vec(&mut self, input: &[u8], output: &mut Vec<u8>, flush: Flush)
fn run_vec(&mut self, input: &[u8], output: &mut Vec<u8>, flush: Self::Flush)
-> Result<Status, DataError>;
}

impl Ops for Compress {
type Flush = FlushCompress;
fn total_in(&self) -> u64 { self.total_in() }
fn total_out(&self) -> u64 { self.total_out() }
fn run(&mut self, input: &[u8], output: &mut [u8], flush: Flush)
fn run(&mut self, input: &[u8], output: &mut [u8], flush: Self::Flush)
-> Result<Status, DataError> {
Ok(self.compress(input, output, flush))
}
fn run_vec(&mut self, input: &[u8], output: &mut Vec<u8>, flush: Flush)
fn run_vec(&mut self, input: &[u8], output: &mut Vec<u8>, flush: Self::Flush)
-> Result<Status, DataError> {
Ok(self.compress_vec(input, output, flush))
}
}

impl Ops for Decompress {
type Flush = FlushDecompress;
fn total_in(&self) -> u64 { self.total_in() }
fn total_out(&self) -> u64 { self.total_out() }
fn run(&mut self, input: &[u8], output: &mut [u8], flush: Flush)
fn run(&mut self, input: &[u8], output: &mut [u8], flush: Self::Flush)
-> Result<Status, DataError> {
self.decompress(input, output, flush)
}
fn run_vec(&mut self, input: &[u8], output: &mut Vec<u8>, flush: Flush)
fn run_vec(&mut self, input: &[u8], output: &mut Vec<u8>, flush: Self::Flush)
-> Result<Status, DataError> {
self.decompress_vec(input, output, flush)
}
Expand All @@ -56,7 +59,11 @@ pub fn read<R, D>(obj: &mut R, data: &mut D, dst: &mut [u8]) -> io::Result<usize
eof = input.is_empty();
let before_out = data.total_out();
let before_in = data.total_in();
let flush = if eof {Flush::Finish} else {Flush::None};
let flush = if eof {
D::Flush::finish()
} else {
D::Flush::none()
};
ret = data.run(input, dst, flush);
read = (data.total_out() - before_out) as usize;
consumed = (data.total_in() - before_in) as usize;
Expand Down Expand Up @@ -96,7 +103,7 @@ impl<W: Write, D: Ops> Writer<W, D> {
try!(self.dump());

let before = self.data.total_out();
try!(self.data.run_vec(&[], &mut self.buf, Flush::Finish));
try!(self.data.run_vec(&[], &mut self.buf, D::Flush::finish()));
if before == self.data.total_out() {
return Ok(())
}
Expand Down Expand Up @@ -151,7 +158,7 @@ impl<W: Write, D: Ops> Write for Writer<W, D> {
try!(self.dump());

let before_in = self.data.total_in();
let ret = self.data.run_vec(buf, &mut self.buf, Flush::None);
let ret = self.data.run_vec(buf, &mut self.buf, D::Flush::none());
let written = (self.data.total_in() - before_in) as usize;

if buf.len() > 0 && written == 0 && ret.is_ok() {
Expand All @@ -169,7 +176,7 @@ impl<W: Write, D: Ops> Write for Writer<W, D> {
}

fn flush(&mut self) -> io::Result<()> {
self.data.run_vec(&[], &mut self.buf, Flush::Sync).unwrap();
self.data.run_vec(&[], &mut self.buf, D::Flush::sync()).unwrap();

// Unfortunately miniz doesn't actually tell us when we're done with
// pulling out all the data from the internal stream. To remedy this we
Expand All @@ -179,7 +186,7 @@ impl<W: Write, D: Ops> Write for Writer<W, D> {
loop {
try!(self.dump());
let before = self.data.total_out();
self.data.run_vec(&[], &mut self.buf, Flush::None).unwrap();
self.data.run_vec(&[], &mut self.buf, D::Flush::none()).unwrap();
if before == self.data.total_out() {
break
}
Expand Down

0 comments on commit 1bdd11c

Please sign in to comment.