1 use crate::{codec::Encode, util::PartialBuffer}; 2 use std::{ 3 fmt, 4 io::{Error, ErrorKind, Result}, 5 }; 6 7 use brotli::enc::{ 8 backward_references::BrotliEncoderParams, 9 encode::{ 10 BrotliEncoderCompressStream, BrotliEncoderCreateInstance, BrotliEncoderHasMoreOutput, 11 BrotliEncoderIsFinished, BrotliEncoderOperation, BrotliEncoderStateStruct, 12 }, 13 StandardAlloc, 14 }; 15 16 pub struct BrotliEncoder { 17 state: BrotliEncoderStateStruct<StandardAlloc>, 18 } 19 20 impl BrotliEncoder { new(params: BrotliEncoderParams) -> Self21 pub(crate) fn new(params: BrotliEncoderParams) -> Self { 22 let mut state = BrotliEncoderCreateInstance(StandardAlloc::default()); 23 state.params = params; 24 Self { state } 25 } 26 encode( &mut self, input: &mut PartialBuffer<impl AsRef<[u8]>>, output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>, op: BrotliEncoderOperation, ) -> Result<()>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 &mut 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 62 impl Encode for BrotliEncoder { encode( &mut self, input: &mut PartialBuffer<impl AsRef<[u8]>>, output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>, ) -> Result<()>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 flush( &mut self, output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>, ) -> Result<bool>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 finish( &mut self, output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>, ) -> Result<bool>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 102 impl fmt::Debug for BrotliEncoder { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 104 f.debug_struct("BrotliEncoder") 105 .field("compress", &"<no debug>") 106 .finish() 107 } 108 } 109