mod deflate_stream { use std::{ io, io::{Read, Write}, }; use bstr::ByteSlice; use flate2::Decompress; use crate::zlib::stream::deflate; /// Provide streaming decompression using the `std::io::Read` trait. /// If `std::io::BufReader` is used, an allocation for the input buffer will be performed. struct InflateReader { inner: R, decompressor: Decompress, } impl InflateReader where R: io::BufRead, { pub fn from_read(read: R) -> InflateReader { InflateReader { decompressor: Decompress::new(true), inner: read, } } } impl io::Read for InflateReader where R: io::BufRead, { fn read(&mut self, into: &mut [u8]) -> io::Result { crate::zlib::stream::inflate::read(&mut self.inner, &mut self.decompressor, into) } } #[test] fn small_file_decompress() -> Result<(), Box> { fn fixture_path(path: &str) -> std::path::PathBuf { std::path::PathBuf::from("tests/fixtures").join(path) } let r = InflateReader::from_read(io::BufReader::new(std::fs::File::open(fixture_path( "objects/37/d4e6c5c48ba0d245164c4e10d5f41140cab980", ))?)); let mut bytes = r.bytes(); let content = bytes.by_ref().take(16).collect::, _>>()?; assert_eq!(content.as_slice().as_bstr(), b"blob 9\0hi there\n".as_bstr()); assert!(bytes.next().is_none()); Ok(()) } #[test] fn all_at_once() -> Result<(), Box> { let mut w = deflate::Write::new(Vec::new()); assert_eq!(w.write(b"hello")?, 5); w.flush()?; let out = w.inner; assert!(out.len() == 12 || out.len() == 13); assert_deflate_buffer(out, b"hello") } fn assert_deflate_buffer(out: Vec, expected: &[u8]) -> Result<(), Box> { let mut actual = Vec::new(); InflateReader::from_read(out.as_slice()).read_to_end(&mut actual)?; assert_eq!(actual, expected); Ok(()) } #[test] fn big_file_small_writes() -> Result<(), Box> { let mut w = deflate::Write::new(Vec::new()); let bytes = include_bytes!( "../../../../../gix-odb/tests/fixtures/objects/pack/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.pack" ); for chunk in bytes.chunks(2) { assert_eq!(w.write(chunk)?, chunk.len()); } w.flush()?; assert_deflate_buffer(w.inner, bytes) } #[test] fn big_file_a_few_big_writes() -> Result<(), Box> { let mut w = deflate::Write::new(Vec::new()); let bytes = include_bytes!( "../../../../../gix-odb/tests/fixtures/objects/pack/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.pack" ); for chunk in bytes.chunks(4096 * 9) { assert_eq!(w.write(chunk)?, chunk.len()); } w.flush()?; assert_deflate_buffer(w.inner, bytes) } }