1use anyhow::Result;
2use bytes::Bytes;
3use flate2::write::GzEncoder;
4use flate2::Compression;
5use std::io::Write;
6
7#[derive(Debug, Clone)]
8pub struct CompressedContent {
9 pub plain: Bytes,
10 pub gzip: Option<Bytes>,
11 pub brotli: Option<Bytes>,
12 pub zstd: Option<Bytes>,
13}
14
15impl CompressedContent {
16 pub fn new(content: Vec<u8>, should_compress: bool) -> Result<Self> {
17 let plain = Bytes::from(content);
18
19 if !should_compress || plain.len() < 1024 {
20 return Ok(Self {
21 plain,
22 gzip: None,
23 brotli: None,
24 zstd: None,
25 });
26 }
27
28 let plain_ref = &plain;
29 let (gzip, (brotli, zstd)) = rayon::join(
30 || gzip_compress(plain_ref),
31 || rayon::join(|| brotli_compress(plain_ref), || zstd_compress(plain_ref)),
32 );
33
34 Ok(Self {
35 plain,
36 gzip: Some(gzip?),
37 brotli: Some(brotli?),
38 zstd: Some(zstd?),
39 })
40 }
41}
42
43pub fn gzip_compress(data: &[u8]) -> Result<Bytes> {
44 let mut encoder = GzEncoder::new(Vec::new(), Compression::best());
45 encoder.write_all(data)?;
46 let compressed = encoder.finish()?;
47 Ok(Bytes::from(compressed))
48}
49
50pub fn brotli_compress(data: &[u8]) -> Result<Bytes> {
51 let mut compressed = Vec::new();
52 let mut cursor = std::io::Cursor::new(data);
53 let params = brotli::enc::BrotliEncoderParams {
54 quality: 11, ..Default::default()
56 };
57 brotli::BrotliCompress(&mut cursor, &mut compressed, ¶ms)?;
58 Ok(Bytes::from(compressed))
59}
60
61pub fn zstd_compress(data: &[u8]) -> Result<Bytes> {
62 let compressed = zstd::bulk::compress(data, 22)?; Ok(Bytes::from(compressed))
64}