http_json_stream/
body_decoder.rs

1#[cfg(feature = "flate2")]
2use flate2::write::MultiGzDecoder;
3use http::HeaderMap;
4use std::io::Write;
5
6/// Supported HTTP Content-Encoding headers.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
8pub enum ContentEncoding {
9    #[cfg(feature = "flate2")]
10    Gzip,
11    #[default]
12    None,
13}
14
15impl From<&HeaderMap> for ContentEncoding {
16    fn from(headers: &HeaderMap) -> Self {
17        match headers.get("Content-Encoding") {
18            Some(encoding) => match encoding.to_str().ok() {
19                #[cfg(feature = "flate2")]
20                Some("gzip") => ContentEncoding::Gzip,
21                _ => ContentEncoding::default(),
22            },
23            None => ContentEncoding::default(),
24        }
25    }
26}
27
28/// A streaming decoder that abstracts over supported content encodings.
29#[derive(Debug)]
30pub enum BodyDecoder<W: Write> {
31    #[cfg(feature = "flate2")]
32    Gzip(MultiGzDecoder<W>),
33    None(W),
34}
35
36impl<W: Write> BodyDecoder<W> {
37    /// Creates a new decoder which will write uncompressed data to the stream.
38    pub fn new(writer: W, encoding: ContentEncoding) -> Self {
39        match encoding {
40            #[cfg(feature = "flate2")]
41            ContentEncoding::Gzip => Self::gzip(writer),
42            ContentEncoding::None => Self::None(writer),
43        }
44    }
45    /// Creates a new decoder which will write uncompressed gzip data to the stream.
46    #[cfg(feature = "flate2")]
47    pub fn gzip(writer: W) -> Self {
48        Self::Gzip(MultiGzDecoder::new(writer))
49    }
50}
51
52impl<W: Write> BodyDecoder<W> {
53    /// Acquires a reference to the underlying writer.
54    pub fn get_ref(&self) -> &W {
55        match self {
56            #[cfg(feature = "flate2")]
57            BodyDecoder::Gzip(writer) => writer.get_ref(),
58            BodyDecoder::None(writer) => writer,
59        }
60    }
61    /// Acquires a mutable reference to the underlying writer.
62    pub fn get_mut(&mut self) -> &mut W {
63        match self {
64            #[cfg(feature = "flate2")]
65            BodyDecoder::Gzip(writer) => writer.get_mut(),
66            BodyDecoder::None(writer) => writer,
67        }
68    }
69    /// See [`MultiGzDecoder::try_finish`].
70    pub fn try_finish(&mut self) -> std::io::Result<()> {
71        match self {
72            #[cfg(feature = "flate2")]
73            BodyDecoder::Gzip(writer) => writer.try_finish(),
74            BodyDecoder::None(_) => Ok(()),
75        }
76    }
77    /// See [`MultiGzDecoder::finish`].
78    pub fn finish(self) -> std::io::Result<W> {
79        match self {
80            #[cfg(feature = "flate2")]
81            BodyDecoder::Gzip(writer) => writer.finish(),
82            BodyDecoder::None(writer) => Ok(writer),
83        }
84    }
85}
86
87impl<W: Write> Write for BodyDecoder<W> {
88    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
89        match self {
90            #[cfg(feature = "flate2")]
91            BodyDecoder::Gzip(writer) => writer.write(buf),
92            BodyDecoder::None(writer) => writer.write(buf),
93        }
94    }
95    fn flush(&mut self) -> std::io::Result<()> {
96        match self {
97            #[cfg(feature = "flate2")]
98            BodyDecoder::Gzip(writer) => writer.flush(),
99            BodyDecoder::None(writer) => writer.flush(),
100        }
101    }
102}