compression_codecs/brotli/
encoder.rs

1use crate::{brotli::params::EncoderParams, Encode};
2use brotli::enc::{
3    backward_references::BrotliEncoderParams,
4    encode::{BrotliEncoderOperation, BrotliEncoderStateStruct},
5    StandardAlloc,
6};
7use compression_core::util::PartialBuffer;
8use std::{fmt, io};
9
10pub struct BrotliEncoder {
11    state: BrotliEncoderStateStruct<StandardAlloc>,
12}
13
14impl BrotliEncoder {
15    pub fn new(params: EncoderParams) -> Self {
16        let params = BrotliEncoderParams::from(params);
17        let mut state = BrotliEncoderStateStruct::new(StandardAlloc::default());
18        state.params = params;
19        Self { state }
20    }
21
22    fn encode(
23        &mut self,
24        input: &mut PartialBuffer<impl AsRef<[u8]>>,
25        output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
26        op: BrotliEncoderOperation,
27    ) -> io::Result<()> {
28        let in_buf = input.unwritten();
29        let out_buf = output.unwritten_mut();
30
31        let mut input_len = 0;
32        let mut output_len = 0;
33
34        if !self.state.compress_stream(
35            op,
36            &mut in_buf.len(),
37            in_buf,
38            &mut input_len,
39            &mut out_buf.len(),
40            out_buf,
41            &mut output_len,
42            &mut None,
43            &mut |_, _, _, _| (),
44        ) {
45            return Err(io::Error::other("brotli error"));
46        }
47
48        input.advance(input_len);
49        output.advance(output_len);
50
51        Ok(())
52    }
53}
54
55impl Encode for BrotliEncoder {
56    fn encode(
57        &mut self,
58        input: &mut PartialBuffer<impl AsRef<[u8]>>,
59        output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
60    ) -> io::Result<()> {
61        self.encode(
62            input,
63            output,
64            BrotliEncoderOperation::BROTLI_OPERATION_PROCESS,
65        )
66    }
67
68    fn flush(
69        &mut self,
70        output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
71    ) -> io::Result<bool> {
72        self.encode(
73            &mut PartialBuffer::new(&[][..]),
74            output,
75            BrotliEncoderOperation::BROTLI_OPERATION_FLUSH,
76        )?;
77
78        Ok(!self.state.has_more_output())
79    }
80
81    fn finish(
82        &mut self,
83        output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
84    ) -> io::Result<bool> {
85        self.encode(
86            &mut PartialBuffer::new(&[][..]),
87            output,
88            BrotliEncoderOperation::BROTLI_OPERATION_FINISH,
89        )?;
90
91        Ok(self.state.is_finished())
92    }
93}
94
95impl fmt::Debug for BrotliEncoder {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        f.debug_struct("BrotliEncoder")
98            .field("compress", &"<no debug>")
99            .finish()
100    }
101}