Skip to content

Commit

Permalink
Add Builder to configure Compress/Decompress.
Browse files Browse the repository at this point in the history
In order to not break the API, but to allow configuring more settings
(e.g. the max. window size), a configuration builder is added.
  • Loading branch information
twittner committed Jun 7, 2019
1 parent 7d3cbe5 commit 338d97a
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 31 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ mod libc {
pub use crc::{Crc, CrcReader, CrcWriter};
pub use gz::GzBuilder;
pub use gz::GzHeader;
pub use mem::{Compress, CompressError, Decompress, DecompressError, Status};
pub use mem::{Builder, Compress, CompressError, Decompress, DecompressError, Status};
pub use mem::{FlushCompress, FlushDecompress};

mod bufreader;
Expand Down
129 changes: 99 additions & 30 deletions src/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,23 +191,62 @@ pub enum Status {
StreamEnd,
}

impl Compress {
/// Creates a new object ready for compressing data that it's given.
/// Configuration builder for [`Compress`] and [`Decompress`].
#[derive(Debug)]
pub struct Builder<T> {
window_bits: c_int,
zlib_header: bool,
level: Compression,
_marker: std::marker::PhantomData<T>
}

impl<T> Builder<T> {
fn new() -> Self {
Builder {
window_bits: ffi::MZ_DEFAULT_WINDOW_BITS,
zlib_header: false,
level: Compression::fast(),
_marker: std::marker::PhantomData
}
}

/// Set the maximum window bits to use.
///
/// The `level` argument here indicates what level of compression is going
/// to be performed, and the `zlib_header` argument indicates whether the
/// output data should have a zlib header or not.
pub fn new(level: Compression, zlib_header: bool) -> Compress {
/// # Panics
///
/// If `bits` does not fall into the range 9 ..= 15.
pub fn window_bits(&mut self, bits: u8) -> &mut Self {
assert!(bits > 8 && bits < 16, "window bits must be within 9 ..= 15");
self.window_bits = bits as c_int;
self
}

/// Should a zlib header be used or not?
pub fn zlib_header(&mut self, flag: bool) -> &mut Self {
self.zlib_header = flag;
self
}
}

impl Builder<Compress> {
/// Set the compression level to use.
pub fn level(&mut self, value: Compression) -> &mut Self {
self.level = value;
self
}

/// Create a `Compress` object based on the configured values.
pub fn finish(&mut self) -> Compress {
unsafe {
let mut state = ffi::StreamWrapper::default();
let ret = ffi::mz_deflateInit2(
&mut *state,
level.0 as c_int,
self.level.0 as c_int,
ffi::MZ_DEFLATED,
if zlib_header {
ffi::MZ_DEFAULT_WINDOW_BITS
if self.zlib_header {
self.window_bits
} else {
-ffi::MZ_DEFAULT_WINDOW_BITS
-self.window_bits
},
9,
ffi::MZ_DEFAULT_STRATEGY,
Expand All @@ -223,6 +262,49 @@ impl Compress {
}
}
}
}

impl Builder<Decompress> {
/// Create a `Decompress` object based on the configured values.
pub fn finish(&mut self) -> Decompress {
unsafe {
let mut state = ffi::StreamWrapper::default();
let ret = ffi::mz_inflateInit2(
&mut *state,
if self.zlib_header {
self.window_bits
} else {
-self.window_bits
},
);
debug_assert_eq!(ret, 0);
Decompress {
inner: Stream {
stream_wrapper: state,
total_in: 0,
total_out: 0,
_marker: marker::PhantomData,
},
}
}
}
}

impl Compress {
/// Creates a new object ready for compressing data that it's given.
///
/// The `level` argument here indicates what level of compression is going
/// to be performed, and the `zlib_header` argument indicates whether the
/// output data should have a zlib header or not.
pub fn new(level: Compression, zlib_header: bool) -> Compress {
let mut b = Self::builder();
b.level(level).zlib_header(zlib_header).finish()
}

/// Create a configuration builder for this compression object.
pub fn builder() -> Builder<Compress> {
Builder::new()
}

/// Returns the total number of input bytes which have been processed by
/// this compression object.
Expand Down Expand Up @@ -358,26 +440,13 @@ impl Decompress {
/// The `zlib_header` argument indicates whether the input data is expected
/// to have a zlib header or not.
pub fn new(zlib_header: bool) -> Decompress {
unsafe {
let mut state = ffi::StreamWrapper::default();
let ret = ffi::mz_inflateInit2(
&mut *state,
if zlib_header {
ffi::MZ_DEFAULT_WINDOW_BITS
} else {
-ffi::MZ_DEFAULT_WINDOW_BITS
},
);
debug_assert_eq!(ret, 0);
Decompress {
inner: Stream {
stream_wrapper: state,
total_in: 0,
total_out: 0,
_marker: marker::PhantomData,
},
}
}
let mut b = Self::builder();
b.zlib_header(zlib_header).finish()
}

/// Create a configuration builder for this decompression object.
pub fn builder() -> Builder<Decompress> {
Builder::new()
}

/// Returns the total number of input bytes which have been processed by
Expand Down

0 comments on commit 338d97a

Please sign in to comment.