Skip to main content

leyline/core/request/
compress.rs

1#[cfg(not(all(
2    feature = "compression-gzip",
3    feature = "compression-brotli",
4    feature = "compression-zstd",
5    feature = "compression-deflate"
6)))]
7use crate::core::error::Kind;
8use crate::core::error::{Error, Result};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[non_exhaustive]
12pub enum ContentEncoding {
13    Gzip,
14    Brotli,
15    Zstd,
16    Deflate,
17}
18
19impl ContentEncoding {
20    pub(crate) fn header_value(self) -> &'static str {
21        match self {
22            ContentEncoding::Gzip => "gzip",
23            ContentEncoding::Brotli => "br",
24            ContentEncoding::Zstd => "zstd",
25            ContentEncoding::Deflate => "deflate",
26        }
27    }
28
29    pub(crate) fn encode(self, data: &[u8]) -> Result<Vec<u8>> {
30        match self {
31            ContentEncoding::Gzip => gzip(data),
32            ContentEncoding::Brotli => brotli(data),
33            ContentEncoding::Zstd => zstd(data),
34            ContentEncoding::Deflate => deflate(data),
35        }
36    }
37}
38
39#[cfg(feature = "compression-gzip")]
40fn gzip(data: &[u8]) -> Result<Vec<u8>> {
41    use std::io::Write;
42    let mut enc = flate2::write::GzEncoder::new(
43        Vec::with_capacity(data.len() / 2),
44        flate2::Compression::default(),
45    );
46    enc.write_all(data).map_err(Error::from)?;
47    enc.finish().map_err(Error::from)
48}
49
50#[cfg(not(feature = "compression-gzip"))]
51fn gzip(_data: &[u8]) -> Result<Vec<u8>> {
52    Err(feature_off("gzip", "compression-gzip"))
53}
54
55#[cfg(feature = "compression-brotli")]
56fn brotli(data: &[u8]) -> Result<Vec<u8>> {
57    use std::io::Read;
58    let mut out = Vec::with_capacity(data.len() / 2);
59    brotli::CompressorReader::new(data, 4096, 5, 22)
60        .read_to_end(&mut out)
61        .map_err(Error::from)?;
62    Ok(out)
63}
64
65#[cfg(not(feature = "compression-brotli"))]
66fn brotli(_data: &[u8]) -> Result<Vec<u8>> {
67    Err(feature_off("brotli", "compression-brotli"))
68}
69
70#[cfg(feature = "compression-zstd")]
71fn zstd(data: &[u8]) -> Result<Vec<u8>> {
72    zstd::encode_all(data, 3).map_err(Error::from)
73}
74
75#[cfg(not(feature = "compression-zstd"))]
76fn zstd(_data: &[u8]) -> Result<Vec<u8>> {
77    Err(feature_off("zstd", "compression-zstd"))
78}
79
80#[cfg(feature = "compression-deflate")]
81fn deflate(data: &[u8]) -> Result<Vec<u8>> {
82    use std::io::Write;
83    let mut enc = flate2::write::ZlibEncoder::new(
84        Vec::with_capacity(data.len() / 2),
85        flate2::Compression::default(),
86    );
87    enc.write_all(data).map_err(Error::from)?;
88    enc.finish().map_err(Error::from)
89}
90
91#[cfg(not(feature = "compression-deflate"))]
92fn deflate(_data: &[u8]) -> Result<Vec<u8>> {
93    Err(feature_off("deflate", "compression-deflate"))
94}
95
96#[cfg(not(all(
97    feature = "compression-gzip",
98    feature = "compression-brotli",
99    feature = "compression-zstd",
100    feature = "compression-deflate"
101)))]
102fn feature_off(codec: &str, feature: &str) -> Error {
103    Error::new(Kind::Body).with_message(format!(
104        "{codec} request compression requested but the `{feature}` feature is not compiled in"
105    ))
106}
107
108#[cfg(test)]
109mod tests;