distant_net/common/transport/framed/codec/
compression.rs1use std::io::{self, Read};
2
3use flate2::bufread::{
4 DeflateDecoder, DeflateEncoder, GzDecoder, GzEncoder, ZlibDecoder, ZlibEncoder,
5};
6use flate2::Compression;
7use serde::{Deserialize, Serialize};
8
9use super::{Codec, Frame};
10
11#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
13pub enum CompressionLevel {
14 Zero = 0,
16
17 One = 1,
19
20 Two = 2,
21 Three = 3,
22 Four = 4,
23 Five = 5,
24 Six = 6,
25 Seven = 7,
26 Eight = 8,
27
28 Nine = 9,
30}
31
32impl CompressionLevel {
33 pub const BEST: Self = Self::Nine;
35 pub const FAST: Self = Self::One;
37 pub const NONE: Self = Self::Zero;
39}
40
41impl Default for CompressionLevel {
42 fn default() -> Self {
44 Self::Six
45 }
46}
47
48#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
50pub enum CompressionType {
51 Deflate,
52 Gzip,
53 Zlib,
54
55 #[serde(other)]
57 Unknown,
58}
59
60impl CompressionType {
61 pub const fn known_variants() -> &'static [CompressionType] {
63 &[
64 CompressionType::Deflate,
65 CompressionType::Gzip,
66 CompressionType::Zlib,
67 ]
68 }
69
70 pub fn is_unknown(&self) -> bool {
72 matches!(self, Self::Unknown)
73 }
74
75 pub fn new_codec(&self, level: CompressionLevel) -> io::Result<CompressionCodec> {
77 CompressionCodec::from_type_and_level(*self, level)
78 }
79}
80
81#[derive(Copy, Clone, Debug, PartialEq, Eq)]
84pub enum CompressionCodec {
85 Deflate { level: CompressionLevel },
87
88 Gzip { level: CompressionLevel },
90
91 Zlib { level: CompressionLevel },
93}
94
95impl CompressionCodec {
96 pub fn from_type_and_level(
99 ty: CompressionType,
100 level: CompressionLevel,
101 ) -> io::Result<CompressionCodec> {
102 match ty {
103 CompressionType::Deflate => Ok(Self::Deflate { level }),
104 CompressionType::Gzip => Ok(Self::Gzip { level }),
105 CompressionType::Zlib => Ok(Self::Zlib { level }),
106 CompressionType::Unknown => Err(io::Error::new(
107 io::ErrorKind::InvalidInput,
108 "Unknown compression type",
109 )),
110 }
111 }
112
113 pub fn deflate(level: impl Into<CompressionLevel>) -> Self {
115 Self::Deflate {
116 level: level.into(),
117 }
118 }
119
120 pub fn gzip(level: impl Into<CompressionLevel>) -> Self {
122 Self::Gzip {
123 level: level.into(),
124 }
125 }
126
127 pub fn zlib(level: impl Into<CompressionLevel>) -> Self {
129 Self::Zlib {
130 level: level.into(),
131 }
132 }
133
134 pub fn level(&self) -> CompressionLevel {
136 match self {
137 Self::Deflate { level } => *level,
138 Self::Gzip { level } => *level,
139 Self::Zlib { level } => *level,
140 }
141 }
142
143 pub fn ty(&self) -> CompressionType {
145 match self {
146 Self::Deflate { .. } => CompressionType::Deflate,
147 Self::Gzip { .. } => CompressionType::Gzip,
148 Self::Zlib { .. } => CompressionType::Zlib,
149 }
150 }
151}
152
153impl Codec for CompressionCodec {
154 fn encode<'a>(&mut self, frame: Frame<'a>) -> io::Result<Frame<'a>> {
155 let item = frame.as_item();
156
157 let mut buf = Vec::new();
158 match *self {
159 Self::Deflate { level } => {
160 DeflateEncoder::new(item, Compression::new(level as u32)).read_to_end(&mut buf)?
161 }
162 Self::Gzip { level } => {
163 GzEncoder::new(item, Compression::new(level as u32)).read_to_end(&mut buf)?
164 }
165 Self::Zlib { level } => {
166 ZlibEncoder::new(item, Compression::new(level as u32)).read_to_end(&mut buf)?
167 }
168 };
169
170 Ok(Frame::from(buf))
171 }
172
173 fn decode<'a>(&mut self, frame: Frame<'a>) -> io::Result<Frame<'a>> {
174 let item = frame.as_item();
175
176 let mut buf = Vec::new();
177 match *self {
178 Self::Deflate { .. } => DeflateDecoder::new(item).read_to_end(&mut buf)?,
179 Self::Gzip { .. } => GzDecoder::new(item).read_to_end(&mut buf)?,
180 Self::Zlib { .. } => ZlibDecoder::new(item).read_to_end(&mut buf)?,
181 };
182
183 Ok(Frame::from(buf))
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use test_log::test;
190
191 use super::*;
192
193 #[test]
194 fn encode_should_apply_appropriate_compression_algorithm() {
195 let mut codec = CompressionCodec::deflate(CompressionLevel::BEST);
197 let frame = codec.encode(Frame::new(b"some bytes")).unwrap();
198
199 let mut item = Vec::new();
200 DeflateDecoder::new(frame.as_item())
201 .read_to_end(&mut item)
202 .unwrap();
203 assert_eq!(item, b"some bytes");
204
205 let mut codec = CompressionCodec::gzip(CompressionLevel::BEST);
207 let frame = codec.encode(Frame::new(b"some bytes")).unwrap();
208
209 let mut item = Vec::new();
210 GzDecoder::new(frame.as_item())
211 .read_to_end(&mut item)
212 .unwrap();
213 assert_eq!(item, b"some bytes");
214
215 let mut codec = CompressionCodec::zlib(CompressionLevel::BEST);
217 let frame = codec.encode(Frame::new(b"some bytes")).unwrap();
218
219 let mut item = Vec::new();
220 ZlibDecoder::new(frame.as_item())
221 .read_to_end(&mut item)
222 .unwrap();
223 assert_eq!(item, b"some bytes");
224 }
225
226 #[test]
227 fn decode_should_apply_appropriate_decompression_algorithm() {
228 let frame = {
230 let mut item = Vec::new();
231 DeflateEncoder::new(b"some bytes".as_slice(), Compression::best())
232 .read_to_end(&mut item)
233 .unwrap();
234 Frame::from(item)
235 };
236 let mut codec = CompressionCodec::deflate(CompressionLevel::BEST);
237 let frame = codec.decode(frame).unwrap();
238 assert_eq!(frame, b"some bytes");
239
240 let frame = {
242 let mut item = Vec::new();
243 GzEncoder::new(b"some bytes".as_slice(), Compression::best())
244 .read_to_end(&mut item)
245 .unwrap();
246 Frame::from(item)
247 };
248 let mut codec = CompressionCodec::gzip(CompressionLevel::BEST);
249 let frame = codec.decode(frame).unwrap();
250 assert_eq!(frame, b"some bytes");
251
252 let frame = {
254 let mut item = Vec::new();
255 ZlibEncoder::new(b"some bytes".as_slice(), Compression::best())
256 .read_to_end(&mut item)
257 .unwrap();
258 Frame::from(item)
259 };
260 let mut codec = CompressionCodec::zlib(CompressionLevel::BEST);
261 let frame = codec.decode(frame).unwrap();
262 assert_eq!(frame, b"some bytes");
263 }
264}