titan_api_codec/transform/
brotli.rs1use super::common::BinaryTransform;
6
7use brotli::enc::{BrotliCompress, BrotliCompressCustomAlloc, BrotliEncoderParams, StandardAlloc};
8use brotli::{BrotliDecompress, BrotliDecompressCustomAlloc};
9use bytes::{Buf, BufMut, Bytes, BytesMut};
10
11const INPUT_BUFFER_SIZE: usize = 4096;
12const OUTPUT_BUFFER_SIZE: usize = 4096;
13
14pub struct BrotliCompressor {
16 input_buffer: Vec<u8>,
17 output_buffer: Vec<u8>,
18 params: BrotliEncoderParams,
19 alloc: StandardAlloc,
20}
21
22impl Default for BrotliCompressor {
23 fn default() -> Self {
24 Self {
25 input_buffer: vec![0u8; INPUT_BUFFER_SIZE],
26 output_buffer: vec![0u8; OUTPUT_BUFFER_SIZE],
27 params: BrotliEncoderParams::default(),
28 alloc: StandardAlloc::default(),
29 }
30 }
31}
32
33impl BinaryTransform for BrotliCompressor {
34 fn transform_mut(&mut self, data: Bytes) -> Result<Bytes, std::io::Error> {
35 let mut buffer = BytesMut::new().writer();
36 BrotliCompressCustomAlloc(
37 &mut data.reader(),
38 &mut buffer,
39 &mut self.input_buffer,
40 &mut self.output_buffer,
41 &self.params,
42 self.alloc,
43 )?;
44 Ok(buffer.into_inner().into())
45 }
46
47 fn transform(&self, data: Bytes) -> Result<Bytes, std::io::Error> {
48 let mut buffer = BytesMut::new().writer();
49 BrotliCompress(&mut data.reader(), &mut buffer, &self.params)?;
50 Ok(buffer.into_inner().into())
51 }
52}
53
54pub struct BrotliDecompressor {
56 input_buffer: Vec<u8>,
57 output_buffer: Vec<u8>,
58 alloc: StandardAlloc,
59}
60
61impl Default for BrotliDecompressor {
62 fn default() -> Self {
63 Self {
64 input_buffer: vec![0u8; INPUT_BUFFER_SIZE],
65 output_buffer: vec![0u8; OUTPUT_BUFFER_SIZE],
66 alloc: StandardAlloc::default(),
67 }
68 }
69}
70
71impl BinaryTransform for BrotliDecompressor {
72 fn transform_mut(&mut self, data: Bytes) -> Result<Bytes, std::io::Error> {
73 let mut buffer = BytesMut::new().writer();
74 BrotliDecompressCustomAlloc(
75 &mut data.reader(),
76 &mut buffer,
77 &mut self.input_buffer,
78 &mut self.output_buffer,
79 self.alloc,
80 self.alloc,
81 self.alloc,
82 )?;
83 Ok(buffer.into_inner().into())
84 }
85
86 fn transform(&self, data: Bytes) -> Result<Bytes, std::io::Error> {
87 let mut buffer = BytesMut::new().writer();
88 BrotliDecompress(&mut data.reader(), &mut buffer)?;
89 Ok(buffer.into_inner().into())
90 }
91}
92
93#[cfg(test)]
94mod test {
95 use super::{BrotliCompressor, BrotliDecompressor};
96 use crate::transform::BinaryTransform;
97 use bytes::Bytes;
98 use lipsum::lipsum;
99
100 #[test]
101 fn test_roundtrip_default() {
102 let compressor = BrotliCompressor::default();
103 let decompressor = BrotliDecompressor::default();
104
105 let data = Bytes::from(lipsum(1000));
106
107 let compressed = compressor
108 .transform(data.clone())
109 .expect("should compress via brotli");
110 let uncompressed = decompressor
111 .transform(compressed)
112 .expect("should decompress from brotli");
113
114 assert_eq!(data, uncompressed);
115 }
116
117 #[test]
118 fn test_roundtrip_mut_default() {
119 let mut compressor = BrotliCompressor::default();
120 let mut decompressor = BrotliDecompressor::default();
121
122 let data = Bytes::from(lipsum(1000));
123
124 let compressed = compressor
125 .transform_mut(data.clone())
126 .expect("should compress via brotli");
127 let uncompressed = decompressor
128 .transform_mut(compressed)
129 .expect("should decompress from brotli");
130
131 assert_eq!(data, uncompressed);
132 }
133}