From 1625134d6840d1d1d67733f8ad4fb39a119c0b07 Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Sat, 19 Jul 2025 20:15:19 -0700 Subject: [PATCH 1/3] Add unit tests of the different flush kinds --- src/mem.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/mem.rs b/src/mem.rs index 903e46b5..9021a2e4 100644 --- a/src/mem.rs +++ b/src/mem.rs @@ -640,7 +640,6 @@ mod tests { use crate::write; use crate::{Compression, Decompress, FlushDecompress}; - #[cfg(feature = "any_zlib")] use crate::{Compress, FlushCompress}; #[test] @@ -819,4 +818,66 @@ mod tests { assert_eq!(err.message(), Some("invalid stored block lengths")); } + + fn compress_with_flush(flush: FlushCompress) -> Vec { + let incompressible = (0..=255).collect::>(); + let mut output = vec![0; 1024]; + + // Feed in the incompressible data followed by the indicated flush type. + let mut w = Compress::new(Compression::default(), false); + w.compress(&incompressible, &mut output, flush).unwrap(); + + if flush != FlushCompress::None { + // The first instance of incompressible input should have been written uncompressed. + assert!(w.total_out() >= 261); + assert_eq!(&output[0..5], &[0, 0, 1, 0xff, !1]); + assert_eq!(&output[5..261], &incompressible); + } + + // Feed in the same data again. + let len = w.total_out() as usize; + w.compress(&incompressible, &mut output[len..], FlushCompress::Finish) + .unwrap(); + + if flush != FlushCompress::Full { + // This time, the data should have been compressed (because it is an exact duplicate of + // the earlier block). + assert!(w.total_out() < 300); + } + + // Assert that all input has been processed. + assert_eq!(w.total_in(), 256 * 2); + + output.resize(w.total_out() as usize, 0); + output + } + + #[test] + fn test_partial_flush() { + let output = compress_with_flush(FlushCompress::Partial); + + // Check for partial flush marker. + assert_eq!(output[261], 0x2); + assert_eq!(output[262] & 0x7, 0x4); + } + + #[test] + fn test_sync_flush() { + let output = compress_with_flush(FlushCompress::Sync); + + // Check for sync flush marker. + assert_eq!(&output[261..][..5], &[0, 0, 0, 0xff, 0xff]); + } + + #[test] + fn test_full_flush() { + let output = compress_with_flush(FlushCompress::Full); + assert_eq!(output.len(), 527); + + // Check for flush flush marker. + assert_eq!(&output[261..][..5], &[0, 0, 0, 0xff, 0xff]); + + // Check that the second instance of incompressible input was also written uncompressed. + assert_eq!(&output[266..][..5], &[1, 0, 1, 0xff, !1]); + } } From 069513b690393b1b97f290856601864a4c0e2896 Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Sat, 19 Jul 2025 00:43:14 -0700 Subject: [PATCH 2/3] Use partial flushes with miniz_oxide backend --- src/ffi/miniz_oxide.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ffi/miniz_oxide.rs b/src/ffi/miniz_oxide.rs index 4dc7c478..69978ce4 100644 --- a/src/ffi/miniz_oxide.rs +++ b/src/ffi/miniz_oxide.rs @@ -136,7 +136,8 @@ impl From for MZFlush { fn from(value: FlushCompress) -> Self { match value { FlushCompress::None => Self::None, - FlushCompress::Partial | FlushCompress::Sync => Self::Sync, + FlushCompress::Partial => Self::Partial, + FlushCompress::Sync => Self::Sync, FlushCompress::Full => Self::Full, FlushCompress::Finish => Self::Finish, } From 641d8e94cfecda2899fb8eb2f2c189014256a069 Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Mon, 8 Dec 2025 23:06:31 -0800 Subject: [PATCH 3/3] (temporary) Patch miniz_oxide version --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index d41209c5..3daea13e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,3 +112,6 @@ any_impl = [] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] + +[patch.crates-io] +miniz_oxide = { git = "https://github.com/Frommi/miniz_oxide", branch = "master" }