compression_codecs/brotli/
encoder.rs1use 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}