Skip to content

Commit 8b66c27

Browse files
authored
Merge pull request #525 from Byron/test-zlib-API
test zlib API for all compatible backends
2 parents 71eb5c5 + 5e752c9 commit 8b66c27

File tree

6 files changed

+277
-126
lines changed

6 files changed

+277
-126
lines changed

.github/workflows/main.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ jobs:
4343
- run: cargo test --features zlib-ng --no-default-features
4444
if: matrix.build != 'mingw'
4545
- run: cargo test --features zlib-rs --no-default-features
46-
if: matrix.build != 'mingw'
4746
- run: cargo test --features cloudflare_zlib --no-default-features
4847
if: matrix.build != 'mingw'
4948
- run: |

Cargo.toml

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "flate2"
33
authors = ["Alex Crichton <alex@alexcrichton.com>", "Josh Triplett <josh@joshtriplett.org>"]
4-
version = "1.1.7"
4+
version = "1.1.8"
55
edition = "2018"
66
license = "MIT OR Apache-2.0"
77
readme = "README.md"
@@ -51,7 +51,7 @@ default = ["rust_backend"]
5151
## Use the zlib-rs backend, a pure Rust rewrite of zlib.
5252
## This is the fastest backend overall, providing excellent performance with some `unsafe` code.
5353
## It does not require a C compiler but uses `unsafe` Rust for optimization.
54-
zlib-rs = ["any_impl", "dep:zlib-rs"]
54+
zlib-rs = ["any_zlib", "dep:zlib-rs"]
5555

5656
## Use the pure Rust `miniz_oxide` backend (default).
5757
## This implementation uses only safe Rust code and doesn't require a C compiler.
@@ -63,11 +63,11 @@ rust_backend = ["miniz_oxide", "any_impl"]
6363
## Use the system's installed zlib library.
6464
## This is useful when you need compatibility with other C code that uses zlib,
6565
## or when you want to use the system-provided zlib for consistency.
66-
zlib = ["any_zlib", "libz-sys"]
66+
zlib = ["any_c_zlib", "libz-sys"]
6767

6868
## Use the system's installed zlib library with default features enabled.
6969
## Similar to `zlib` but enables additional features from libz-sys.
70-
zlib-default = ["any_zlib", "libz-sys/default"]
70+
zlib-default = ["any_c_zlib", "libz-sys/default"]
7171

7272
## Use zlib-ng in zlib-compat mode via libz-sys.
7373
## This provides zlib-ng's performance improvements while maintaining compatibility.
@@ -83,13 +83,13 @@ zlib-ng-compat = ["zlib", "libz-sys/zlib-ng"]
8383
## Use the high-performance zlib-ng library directly.
8484
## This typically provides better performance than stock zlib and works even when
8585
## other dependencies use zlib. Requires a C compiler.
86-
zlib-ng = ["any_zlib", "libz-ng-sys"]
86+
zlib-ng = ["any_c_zlib", "libz-ng-sys"]
8787

8888
## Use Cloudflare's optimized zlib implementation.
8989
## This provides better performance than stock zlib on x86-64 (with SSE 4.2) and ARM64 (with NEON & CRC).
9090
## * ⚠ Does not support 32-bit CPUs and is incompatible with mingw.
9191
## * ⚠ May cause conflicts if other crates use different zlib versions.
92-
cloudflare_zlib = ["any_zlib", "cloudflare-zlib-sys"]
92+
cloudflare_zlib = ["any_c_zlib", "cloudflare-zlib-sys"]
9393

9494
## Deprecated alias for `rust_backend`, provided for backwards compatibility.
9595
## Use `rust_backend` instead.
@@ -100,10 +100,15 @@ miniz-sys = ["rust_backend"]
100100
#! They are documented here to aid with maintenance.
101101

102102
## **Internal:** Marker feature indicating that any zlib-based C backend is enabled.
103-
## This is automatically enabled by `zlib`, `zlib-ng`, `zlib-ng-compat`, or `cloudflare_zlib`.
103+
## This is automatically enabled by `zlib-rs`, `zlib`, `zlib-ng`, `zlib-ng-compat`, and `cloudflare_zlib`.
104104
## Do not enable this feature directly; instead, choose a specific backend feature.
105105
any_zlib = ["any_impl"]
106106

107+
## **Internal:** Marker feature indicating that any C based fully zlib compatible backend is enabled.
108+
## This is automatically enabled by `zlib`, `zlib-ng`, `zlib-ng-compat`, and `cloudflare_zlib`.
109+
## Do not enable this feature directly; instead, choose a specific backend feature.
110+
any_c_zlib = ["any_zlib"]
111+
107112
## **Internal:** Marker feature indicating that any compression backend is enabled.
108113
## This is automatically enabled by all backend features to ensure at least one implementation is available.
109114
## Do not enable this feature directly; instead, choose a specific backend feature.

src/ffi/mod.rs

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -60,37 +60,25 @@ pub trait DeflateBackend: Backend {
6060
}
6161

6262
// Default to Rust implementation unless explicitly opted in to a different backend.
63-
#[cfg(feature = "any_zlib")]
63+
#[cfg(feature = "any_c_zlib")]
6464
mod c;
65-
#[cfg(feature = "any_zlib")]
65+
#[cfg(feature = "any_c_zlib")]
6666
pub use self::c::*;
6767

68-
// Prefer zlib-rs when both Rust backends are enabled to avoid duplicate exports.
69-
#[cfg(all(not(feature = "any_zlib"), feature = "zlib-rs"))]
68+
// Only bring in `zlib-rs` if there is no C-based backend.
69+
#[cfg(all(not(feature = "any_c_zlib"), feature = "zlib-rs"))]
7070
mod zlib_rs;
71-
#[cfg(all(not(feature = "any_zlib"), feature = "zlib-rs"))]
71+
#[cfg(all(not(feature = "any_c_zlib"), feature = "zlib-rs"))]
7272
pub use self::zlib_rs::*;
7373

74-
// Fallback to miniz_oxide when zlib-rs is not selected.
75-
#[cfg(all(
76-
not(feature = "any_zlib"),
77-
not(feature = "zlib-rs"),
78-
feature = "miniz_oxide"
79-
))]
74+
// Use miniz_oxide when no fully compliant zlib is selected.
75+
#[cfg(all(not(feature = "any_zlib"), feature = "miniz_oxide"))]
8076
mod miniz_oxide;
81-
#[cfg(all(
82-
not(feature = "any_zlib"),
83-
not(feature = "zlib-rs"),
84-
feature = "miniz_oxide"
85-
))]
77+
#[cfg(all(not(feature = "any_zlib"), feature = "miniz_oxide"))]
8678
pub use self::miniz_oxide::*;
8779

8880
// If no backend is enabled, fail fast with a clear error message.
89-
#[cfg(all(
90-
not(feature = "any_zlib"),
91-
not(feature = "zlib-rs"),
92-
not(feature = "miniz_oxide")
93-
))]
81+
#[cfg(not(feature = "any_impl"))]
9482
compile_error!("No compression backend selected; enable one of `zlib`, `zlib-ng`, `zlib-rs`, or the default `rust_backend` feature.");
9583

9684
impl std::fmt::Debug for ErrorMessage {

src/ffi/zlib_rs.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,11 @@ impl Deflate {
242242
match self.inner.set_level(level.level() as i32) {
243243
Ok(status) => match status {
244244
Status::Ok => Ok(()),
245-
246245
Status::BufError => compress_failed(ErrorMessage(Some("insufficient space"))),
247-
248-
Status::StreamEnd => unreachable!(),
246+
Status::StreamEnd => {
247+
unreachable!("zlib-rs is known to never return the StreamEnd status")
248+
}
249249
},
250-
251250
Err(_) => self.compress_error(),
252251
}
253252
}

src/mem.rs

Lines changed: 13 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ impl Compress {
212212
/// # Panics
213213
///
214214
/// If `window_bits` does not fall into the range 9 ..= 15,
215-
/// `new_with_window_bits` will panic.
215+
/// this function will panic.
216216
#[cfg(feature = "any_zlib")]
217217
pub fn new_with_window_bits(
218218
level: Compression,
@@ -239,7 +239,7 @@ impl Compress {
239239
/// # Panics
240240
///
241241
/// If `window_bits` does not fall into the range 9 ..= 15,
242-
/// `new_with_window_bits` will panic.
242+
/// this function will panic.
243243
#[cfg(feature = "any_zlib")]
244244
pub fn new_gzip(level: Compression, window_bits: u8) -> Compress {
245245
assert!(
@@ -266,7 +266,7 @@ impl Compress {
266266
/// Specifies the compression dictionary to use.
267267
///
268268
/// Returns the Adler-32 checksum of the dictionary.
269-
#[cfg(feature = "any_zlib")]
269+
#[cfg(feature = "any_c_zlib")]
270270
pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, CompressError> {
271271
// SAFETY: The field `inner` must always be accessed as a raw pointer,
272272
// since it points to a cyclic structure. No copies of `inner` can be
@@ -289,7 +289,7 @@ impl Compress {
289289
/// Specifies the compression dictionary to use.
290290
///
291291
/// Returns the Adler-32 checksum of the dictionary.
292-
#[cfg(all(not(feature = "any_zlib"), feature = "zlib-rs"))]
292+
#[cfg(all(not(feature = "any_c_zlib"), feature = "zlib-rs"))]
293293
pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, CompressError> {
294294
self.inner.set_dictionary(dictionary)
295295
}
@@ -311,14 +311,14 @@ impl Compress {
311311
/// the compression of the available input data before changing the
312312
/// compression level. Flushing the stream before calling this method
313313
/// ensures that the function will succeed on the first call.
314-
#[cfg(any(feature = "any_zlib", feature = "zlib-rs"))]
314+
#[cfg(feature = "any_zlib")]
315315
pub fn set_level(&mut self, level: Compression) -> Result<(), CompressError> {
316-
#[cfg(all(not(feature = "any_zlib"), feature = "zlib-rs"))]
316+
#[cfg(all(not(feature = "any_c_zlib"), feature = "zlib-rs"))]
317317
{
318318
self.inner.set_level(level)
319319
}
320320

321-
#[cfg(feature = "any_zlib")]
321+
#[cfg(feature = "any_c_zlib")]
322322
{
323323
use std::os::raw::c_int;
324324
// SAFETY: The field `inner` must always be accessed as a raw pointer,
@@ -415,7 +415,7 @@ impl Decompress {
415415
/// # Panics
416416
///
417417
/// If `window_bits` does not fall into the range 9 ..= 15,
418-
/// `new_with_window_bits` will panic.
418+
/// this function will panic.
419419
#[cfg(feature = "any_zlib")]
420420
pub fn new_with_window_bits(zlib_header: bool, window_bits: u8) -> Decompress {
421421
assert!(
@@ -435,7 +435,7 @@ impl Decompress {
435435
/// # Panics
436436
///
437437
/// If `window_bits` does not fall into the range 9 ..= 15,
438-
/// `new_with_window_bits` will panic.
438+
/// this function will panic.
439439
#[cfg(feature = "any_zlib")]
440440
pub fn new_gzip(window_bits: u8) -> Decompress {
441441
assert!(
@@ -536,7 +536,7 @@ impl Decompress {
536536
}
537537

538538
/// Specifies the decompression dictionary to use.
539-
#[cfg(feature = "any_zlib")]
539+
#[cfg(feature = "any_c_zlib")]
540540
pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, DecompressError> {
541541
// SAFETY: The field `inner` must always be accessed as a raw pointer,
542542
// since it points to a cyclic structure. No copies of `inner` can be
@@ -558,7 +558,7 @@ impl Decompress {
558558
}
559559

560560
/// Specifies the decompression dictionary to use.
561-
#[cfg(all(not(feature = "any_zlib"), feature = "zlib-rs"))]
561+
#[cfg(all(not(feature = "any_c_zlib"), feature = "zlib-rs"))]
562562
pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, DecompressError> {
563563
self.inner.set_dictionary(dictionary)
564564
}
@@ -723,86 +723,6 @@ mod tests {
723723
assert!(dst.starts_with(string));
724724
}
725725

726-
#[cfg(feature = "any_zlib")]
727-
#[test]
728-
fn set_dictionary_with_zlib_header() {
729-
let string = "hello, hello!".as_bytes();
730-
let dictionary = "hello".as_bytes();
731-
732-
let mut encoded = Vec::with_capacity(1024);
733-
734-
let mut encoder = Compress::new(Compression::default(), true);
735-
736-
let dictionary_adler = encoder.set_dictionary(&dictionary).unwrap();
737-
738-
encoder
739-
.compress_vec(string, &mut encoded, FlushCompress::Finish)
740-
.unwrap();
741-
742-
assert_eq!(encoder.total_in(), string.len() as u64);
743-
assert_eq!(encoder.total_out(), encoded.len() as u64);
744-
745-
let mut decoder = Decompress::new(true);
746-
let mut decoded = [0; 1024];
747-
let decompress_error = decoder
748-
.decompress(&encoded, &mut decoded, FlushDecompress::Finish)
749-
.expect_err("decompression should fail due to requiring a dictionary");
750-
751-
let required_adler = decompress_error.needs_dictionary()
752-
.expect("the first call to decompress should indicate a dictionary is required along with the required Adler-32 checksum");
753-
754-
assert_eq!(required_adler, dictionary_adler,
755-
"the Adler-32 checksum should match the value when the dictionary was set on the compressor");
756-
757-
let actual_adler = decoder.set_dictionary(&dictionary).unwrap();
758-
759-
assert_eq!(required_adler, actual_adler);
760-
761-
// Decompress the rest of the input to the remainder of the output buffer
762-
let total_in = decoder.total_in();
763-
let total_out = decoder.total_out();
764-
765-
let decompress_result = decoder.decompress(
766-
&encoded[total_in as usize..],
767-
&mut decoded[total_out as usize..],
768-
FlushDecompress::Finish,
769-
);
770-
assert!(decompress_result.is_ok());
771-
772-
assert_eq!(&decoded[..decoder.total_out() as usize], string);
773-
}
774-
775-
#[cfg(feature = "any_zlib")]
776-
#[test]
777-
fn set_dictionary_raw() {
778-
let string = "hello, hello!".as_bytes();
779-
let dictionary = "hello".as_bytes();
780-
781-
let mut encoded = Vec::with_capacity(1024);
782-
783-
let mut encoder = Compress::new(Compression::default(), false);
784-
785-
encoder.set_dictionary(&dictionary).unwrap();
786-
787-
encoder
788-
.compress_vec(string, &mut encoded, FlushCompress::Finish)
789-
.unwrap();
790-
791-
assert_eq!(encoder.total_in(), string.len() as u64);
792-
assert_eq!(encoder.total_out(), encoded.len() as u64);
793-
794-
let mut decoder = Decompress::new(false);
795-
796-
decoder.set_dictionary(&dictionary).unwrap();
797-
798-
let mut decoded = [0; 1024];
799-
let decompress_result = decoder.decompress(&encoded, &mut decoded, FlushDecompress::Finish);
800-
801-
assert!(decompress_result.is_ok());
802-
803-
assert_eq!(&decoded[..decoder.total_out() as usize], string);
804-
}
805-
806726
#[cfg(feature = "any_zlib")]
807727
#[test]
808728
fn test_gzip_flate() {
@@ -829,15 +749,15 @@ mod tests {
829749
assert_eq!(&decoded[..decoder.total_out() as usize], string);
830750
}
831751

832-
#[cfg(any(feature = "any_zlib", feature = "zlib-rs"))]
752+
#[cfg(feature = "any_zlib")]
833753
#[test]
834754
fn test_error_message() {
835755
let mut decoder = Decompress::new(false);
836756
let mut decoded = [0; 128];
837757
let garbage = b"xbvxzi";
838758

839759
let err = decoder
840-
.decompress(&*garbage, &mut decoded, FlushDecompress::Finish)
760+
.decompress(garbage, &mut decoded, FlushDecompress::Finish)
841761
.unwrap_err();
842762

843763
assert_eq!(err.message(), Some("invalid stored block lengths"));

0 commit comments

Comments
 (0)