compression_codecs/flate/
encoder.rs1use crate::{flate::params::FlateEncoderParams, EncodeV2};
2use compression_core::util::{PartialBuffer, WriteBuffer};
3use flate2::{Compress, FlushCompress, Status};
4use std::io;
5
6#[derive(Debug)]
7pub struct FlateEncoder {
8 compress: Compress,
9 flushed: bool,
10}
11
12impl FlateEncoder {
13 pub fn new(level: FlateEncoderParams, zlib_header: bool) -> Self {
14 let level = flate2::Compression::from(level);
15 Self {
16 compress: Compress::new(level, zlib_header),
17 flushed: true,
18 }
19 }
20
21 pub fn get_ref(&self) -> &Compress {
22 &self.compress
23 }
24
25 fn encode(
26 &mut self,
27 input: &mut PartialBuffer<&[u8]>,
28 output: &mut WriteBuffer<'_>,
29 flush: FlushCompress,
30 ) -> io::Result<Status> {
31 let prior_in = self.compress.total_in();
32 let prior_out = self.compress.total_out();
33
34 let result = self
35 .compress
36 .compress_uninit(input.unwritten(), unsafe { output.unwritten_mut() }, flush);
38
39 input.advance((self.compress.total_in() - prior_in) as usize);
40 unsafe { output.assume_init_and_advance((self.compress.total_out() - prior_out) as usize) };
42
43 Ok(result?)
44 }
45}
46
47impl EncodeV2 for FlateEncoder {
48 fn encode(
49 &mut self,
50 input: &mut PartialBuffer<&[u8]>,
51 output: &mut WriteBuffer<'_>,
52 ) -> io::Result<()> {
53 self.flushed = false;
54 match self.encode(input, output, FlushCompress::None)? {
55 Status::Ok => Ok(()),
56 Status::StreamEnd => unreachable!(),
57 Status::BufError => Err(io::Error::other("unexpected BufError")),
58 }
59 }
60
61 fn flush(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool> {
62 if self.flushed {
65 return Ok(true);
66 }
67
68 self.encode(
69 &mut PartialBuffer::new(&[][..]),
70 output,
71 FlushCompress::Sync,
72 )?;
73
74 loop {
75 let old_len = output.written_len();
76 self.encode(
77 &mut PartialBuffer::new(&[][..]),
78 output,
79 FlushCompress::None,
80 )?;
81 if output.written_len() == old_len {
82 break;
83 }
84 }
85
86 let internal_flushed = !output.has_no_spare_space();
87 self.flushed = internal_flushed;
88 Ok(internal_flushed)
89 }
90
91 fn finish(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool> {
92 self.flushed = false;
93 match self.encode(
94 &mut PartialBuffer::new(&[][..]),
95 output,
96 FlushCompress::Finish,
97 )? {
98 Status::Ok => Ok(false),
99 Status::StreamEnd => Ok(true),
100 Status::BufError => Err(io::Error::other("unexpected BufError")),
101 }
102 }
103}