Skip to main content

async_compression_issue_150_workaround/codec/brotli/
encoder.rs

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