gix_features/zlib/stream/deflate/
mod.rs1use crate::zlib::Status;
2use zlib_rs::DeflateError;
3
4const BUF_SIZE: usize = 4096 * 8;
5
6pub struct Write<W> {
10 compressor: Compress,
11 inner: W,
12 buf: [u8; BUF_SIZE],
13}
14
15impl<W> Clone for Write<W>
16where
17 W: Clone,
18{
19 fn clone(&self) -> Self {
20 Write {
21 compressor: impls::new_compress(),
22 inner: self.inner.clone(),
23 buf: self.buf,
24 }
25 }
26}
27
28pub struct Compress(zlib_rs::Deflate);
30
31impl Default for Compress {
32 fn default() -> Self {
33 Self::new()
34 }
35}
36
37impl Compress {
38 pub fn total_in(&self) -> u64 {
40 self.0.total_in()
41 }
42
43 pub fn total_out(&self) -> u64 {
45 self.0.total_out()
46 }
47
48 pub fn new() -> Self {
50 let config = zlib_rs::DeflateConfig::best_speed();
51 let header = true;
52 let inner = zlib_rs::Deflate::new(config.level, header, config.window_bits as u8);
53 Self(inner)
54 }
55
56 pub fn reset(&mut self) {
58 self.0.reset();
59 }
60
61 pub fn compress(&mut self, input: &[u8], output: &mut [u8], flush: FlushCompress) -> Result<Status, CompressError> {
63 let flush = match flush {
64 FlushCompress::None => zlib_rs::DeflateFlush::NoFlush,
65 FlushCompress::Partial => zlib_rs::DeflateFlush::PartialFlush,
66 FlushCompress::Sync => zlib_rs::DeflateFlush::SyncFlush,
67 FlushCompress::Full => zlib_rs::DeflateFlush::FullFlush,
68 FlushCompress::Finish => zlib_rs::DeflateFlush::Finish,
69 };
70 let status = self.0.compress(input, output, flush)?;
71 match status {
72 zlib_rs::Status::Ok => Ok(Status::Ok),
73 zlib_rs::Status::BufError => Ok(Status::BufError),
74 zlib_rs::Status::StreamEnd => Ok(Status::StreamEnd),
75 }
76 }
77}
78
79#[derive(Debug, thiserror::Error)]
81#[allow(missing_docs)]
82pub enum CompressError {
83 #[error("stream error")]
84 StreamError,
85 #[error("The input is not a valid deflate stream.")]
86 DataError,
87 #[error("Not enough memory")]
88 InsufficientMemory,
89}
90
91impl From<zlib_rs::DeflateError> for CompressError {
92 fn from(value: zlib_rs::DeflateError) -> Self {
93 match value {
94 DeflateError::StreamError => CompressError::StreamError,
95 DeflateError::DataError => CompressError::DataError,
96 DeflateError::MemError => CompressError::InsufficientMemory,
97 }
98 }
99}
100
101#[derive(Copy, Clone, PartialEq, Eq, Debug)]
104#[non_exhaustive]
105#[allow(clippy::unnecessary_cast)]
106pub enum FlushCompress {
107 None = 0,
111
112 Partial = 1,
121
122 Sync = 2,
130
131 Full = 3,
137
138 Finish = 4,
143}
144
145mod impls {
146 use std::io;
147
148 use crate::zlib::stream::deflate::{self, Compress, FlushCompress};
149 use crate::zlib::Status;
150
151 pub(crate) fn new_compress() -> Compress {
152 Compress::new()
153 }
154
155 impl<W> deflate::Write<W>
156 where
157 W: io::Write,
158 {
159 pub fn new(inner: W) -> deflate::Write<W> {
161 deflate::Write {
162 compressor: new_compress(),
163 inner,
164 buf: [0; deflate::BUF_SIZE],
165 }
166 }
167
168 pub fn reset(&mut self) {
172 self.compressor.reset();
173 }
174
175 pub fn into_inner(self) -> W {
177 self.inner
178 }
179
180 fn write_inner(&mut self, mut buf: &[u8], flush: FlushCompress) -> io::Result<usize> {
181 let total_in_when_start = self.compressor.total_in();
182 loop {
183 let last_total_in = self.compressor.total_in();
184 let last_total_out = self.compressor.total_out();
185
186 let status = self
187 .compressor
188 .compress(buf, &mut self.buf, flush)
189 .map_err(io::Error::other)?;
190
191 let written = self.compressor.total_out() - last_total_out;
192 if written > 0 {
193 self.inner.write_all(&self.buf[..written as usize])?;
194 }
195
196 match status {
197 Status::StreamEnd => return Ok((self.compressor.total_in() - total_in_when_start) as usize),
198 Status::Ok | Status::BufError => {
199 let consumed = self.compressor.total_in() - last_total_in;
200 buf = &buf[consumed as usize..];
201
202 if self.compressor.total_out() > last_total_out {
204 continue;
205 }
206 if self.compressor.total_in() > last_total_in {
208 continue;
209 }
210 return Ok((self.compressor.total_in() - total_in_when_start) as usize);
212 }
213 }
214 }
215 }
216 }
217
218 impl<W: io::Write> io::Write for deflate::Write<W> {
219 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
220 self.write_inner(buf, FlushCompress::None)
221 }
222
223 fn flush(&mut self) -> io::Result<()> {
224 self.write_inner(&[], FlushCompress::Finish).map(|_| ())
225 }
226 }
227}
228
229#[cfg(test)]
230mod tests;