1use std::{fmt, io};
2
3#[derive(Clone, Copy, PartialEq, Eq)]
7pub struct CompressionMethod(pub u16);
8
9impl fmt::Debug for CompressionMethod {
10 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11 let name = match *self {
12 Self::STORE => "store",
13 Self::DEFLATE => "deflate",
14 Self::DEFLATE64 => "deflate64",
15 Self::BZIP2 => "bzip2",
16 Self::LZMA => "lzma",
17 Self::ZSTD_DEPRECATED => "zstd (deprecated)",
18 Self::ZSTD => "zstd",
19 Self::XZ => "xz",
20 Self::AES => "aes",
21 Self(n) => return write!(f, "unknown ({n})"),
22 };
23
24 f.write_str(name)
25 }
26}
27
28impl Default for CompressionMethod {
29 fn default() -> Self {
30 if cfg!(feature = "zstd") {
31 Self::ZSTD
32 } else if cfg!(feature = "deflate") {
33 Self::DEFLATE
34 } else {
35 Self::STORE
36 }
37 }
38}
39
40impl CompressionMethod {
41 pub const SUPPORTED: &[CompressionMethod] = &[
45 Self::STORE,
46 #[cfg(feature = "deflate")]
47 Self::DEFLATE,
48 #[cfg(feature = "zstd")]
49 Self::ZSTD,
50 ];
51}
52
53impl CompressionMethod {
54 pub const STORE: Self = Self(0);
56 pub const DEFLATE: Self = Self(8);
57 pub const DEFLATE64: Self = Self(9);
58 pub const BZIP2: Self = Self(12);
59 pub const LZMA: Self = Self(14);
60 pub const ZSTD_DEPRECATED: Self = Self(20);
61 pub const ZSTD: Self = Self(93);
62 pub const XZ: Self = Self(95);
63 pub const AES: Self = Self(99);
64}
65
66#[cold]
67fn unsupported_method(method: CompressionMethod) -> io::Error {
68 io::Error::new(
69 io::ErrorKind::Unsupported,
70 format!("Unsupported compression method: {method:?}"),
71 )
72}
73
74pub struct Decompressor<R>(DecompressorImpl<R>);
76
77impl<R: io::BufRead + fmt::Debug> fmt::Debug for Decompressor<R> {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 f.debug_struct("Decompressor")
80 .field("method", &self.compression_method())
81 .field("reader", &self.get_ref())
82 .finish()
83 }
84}
85
86enum DecompressorImpl<R> {
87 Store(R),
88 #[cfg(feature = "deflate")]
89 Deflate(flate2::bufread::DeflateDecoder<R>),
90 #[cfg(feature = "zstd")]
91 Zstd(zstd::Decoder<'static, R>),
92}
93
94impl<R: io::BufRead> Decompressor<R> {
95 pub fn new(reader: R, method: CompressionMethod) -> io::Result<Self> {
99 let inner = match method {
100 CompressionMethod::STORE => DecompressorImpl::Store(reader),
101 #[cfg(feature = "deflate")]
102 CompressionMethod::DEFLATE => {
103 DecompressorImpl::Deflate(flate2::bufread::DeflateDecoder::new(reader))
104 }
105 #[cfg(feature = "zstd")]
106 CompressionMethod::ZSTD => DecompressorImpl::Zstd(zstd::Decoder::with_buffer(reader)?),
107 _ => return Err(unsupported_method(method)),
108 };
109
110 Ok(Self(inner))
111 }
112
113 pub fn compression_method(&self) -> CompressionMethod {
115 match self.0 {
116 DecompressorImpl::Store(_) => CompressionMethod::STORE,
117 #[cfg(feature = "deflate")]
118 DecompressorImpl::Deflate(_) => CompressionMethod::DEFLATE,
119 #[cfg(feature = "zstd")]
120 DecompressorImpl::Zstd(_) => CompressionMethod::ZSTD,
121 }
122 }
123
124 pub fn get_ref(&self) -> &R {
126 match &self.0 {
127 DecompressorImpl::Store(r) => r,
128 #[cfg(feature = "deflate")]
129 DecompressorImpl::Deflate(r) => r.get_ref(),
130 #[cfg(feature = "zstd")]
131 DecompressorImpl::Zstd(r) => r.get_ref(),
132 }
133 }
134
135 pub fn get_mut(&mut self) -> &mut R {
139 match &mut self.0 {
140 DecompressorImpl::Store(r) => r,
141 #[cfg(feature = "deflate")]
142 DecompressorImpl::Deflate(r) => r.get_mut(),
143 #[cfg(feature = "zstd")]
144 DecompressorImpl::Zstd(r) => r.get_mut(),
145 }
146 }
147}
148
149impl<R: io::BufRead> io::Read for Decompressor<R> {
150 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
151 match &mut self.0 {
152 DecompressorImpl::Store(r) => r.read(buf),
153 #[cfg(feature = "deflate")]
154 DecompressorImpl::Deflate(r) => r.read(buf),
155 #[cfg(feature = "zstd")]
156 DecompressorImpl::Zstd(r) => r.read(buf),
157 }
158 }
159
160 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
161 match &mut self.0 {
162 DecompressorImpl::Store(r) => r.read_to_end(buf),
163 #[cfg(feature = "deflate")]
164 DecompressorImpl::Deflate(r) => r.read_to_end(buf),
165 #[cfg(feature = "zstd")]
166 DecompressorImpl::Zstd(r) => r.read_to_end(buf),
167 }
168 }
169
170 fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
171 match &mut self.0 {
172 DecompressorImpl::Store(r) => r.read_to_string(buf),
173 #[cfg(feature = "deflate")]
174 DecompressorImpl::Deflate(r) => r.read_to_string(buf),
175 #[cfg(feature = "zstd")]
176 DecompressorImpl::Zstd(r) => r.read_to_string(buf),
177 }
178 }
179}
180
181pub struct Compressor<W: io::Write>(CompressorImpl<W>);
183
184impl<W: io::Write + fmt::Debug> fmt::Debug for Compressor<W> {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 f.debug_struct("Compressor")
187 .field("method", &self.compression_method())
188 .field("writer", &self.get_ref())
189 .finish()
190 }
191}
192
193enum CompressorImpl<W: io::Write> {
194 Store(W),
195 #[cfg(feature = "deflate")]
196 Deflate(flate2::write::DeflateEncoder<W>),
197 #[cfg(feature = "zstd")]
198 Zstd(zstd::Encoder<'static, W>),
199}
200
201impl<W: io::Write> Compressor<W> {
202 pub fn new(writer: W, method: CompressionMethod, level: Option<i32>) -> io::Result<Self> {
209 let _ = level;
211
212 let inner = match method {
213 CompressionMethod::STORE => CompressorImpl::Store(writer),
214 #[cfg(feature = "deflate")]
215 CompressionMethod::DEFLATE => {
216 let level = match level {
217 Some(level) => flate2::Compression::new(level as _),
218 None => flate2::Compression::default(),
219 };
220
221 CompressorImpl::Deflate(flate2::write::DeflateEncoder::new(writer, level))
222 }
223 #[cfg(feature = "zstd")]
224 CompressionMethod::ZSTD => {
225 let level = level.unwrap_or(0);
226 CompressorImpl::Zstd(zstd::Encoder::new(writer, level)?)
227 }
228 _ => return Err(unsupported_method(method)),
229 };
230
231 Ok(Self(inner))
232 }
233
234 pub fn compression_method(&self) -> CompressionMethod {
236 match self.0 {
237 CompressorImpl::Store(_) => CompressionMethod::STORE,
238 #[cfg(feature = "deflate")]
239 CompressorImpl::Deflate(_) => CompressionMethod::DEFLATE,
240 #[cfg(feature = "zstd")]
241 CompressorImpl::Zstd(_) => CompressionMethod::ZSTD,
242 }
243 }
244
245 pub fn get_ref(&self) -> &W {
247 match &self.0 {
248 CompressorImpl::Store(w) => w,
249 #[cfg(feature = "deflate")]
250 CompressorImpl::Deflate(w) => w.get_ref(),
251 #[cfg(feature = "zstd")]
252 CompressorImpl::Zstd(w) => w.get_ref(),
253 }
254 }
255
256 pub fn get_mut(&mut self) -> &mut W {
260 match &mut self.0 {
261 CompressorImpl::Store(w) => w,
262 #[cfg(feature = "deflate")]
263 CompressorImpl::Deflate(w) => w.get_mut(),
264 #[cfg(feature = "zstd")]
265 CompressorImpl::Zstd(w) => w.get_mut(),
266 }
267 }
268
269 pub fn do_finish(&mut self) -> io::Result<()> {
273 match &mut self.0 {
274 CompressorImpl::Store(_) => Ok(()),
275 #[cfg(feature = "deflate")]
276 CompressorImpl::Deflate(w) => w.try_finish(),
277 #[cfg(feature = "zstd")]
278 CompressorImpl::Zstd(w) => w.do_finish(),
279 }
280 }
281
282 pub fn finish(self) -> io::Result<W> {
286 match self.0 {
287 CompressorImpl::Store(w) => Ok(w),
288 #[cfg(feature = "deflate")]
289 CompressorImpl::Deflate(w) => w.finish(),
290 #[cfg(feature = "zstd")]
291 CompressorImpl::Zstd(w) => w.finish(),
292 }
293 }
294}
295
296impl<W: io::Write> io::Write for Compressor<W> {
297 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
298 match &mut self.0 {
299 CompressorImpl::Store(w) => w.write(buf),
300 #[cfg(feature = "deflate")]
301 CompressorImpl::Deflate(w) => w.write(buf),
302 #[cfg(feature = "zstd")]
303 CompressorImpl::Zstd(w) => w.write(buf),
304 }
305 }
306
307 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
308 match &mut self.0 {
309 CompressorImpl::Store(w) => w.write_all(buf),
310 #[cfg(feature = "deflate")]
311 CompressorImpl::Deflate(w) => w.write_all(buf),
312 #[cfg(feature = "zstd")]
313 CompressorImpl::Zstd(w) => w.write_all(buf),
314 }
315 }
316
317 fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
318 match &mut self.0 {
319 CompressorImpl::Store(w) => w.write_vectored(bufs),
320 #[cfg(feature = "deflate")]
321 CompressorImpl::Deflate(w) => w.write_vectored(bufs),
322 #[cfg(feature = "zstd")]
323 CompressorImpl::Zstd(w) => w.write_vectored(bufs),
324 }
325 }
326
327 fn flush(&mut self) -> io::Result<()> {
328 match &mut self.0 {
329 CompressorImpl::Store(w) => w.flush(),
330 #[cfg(feature = "deflate")]
331 CompressorImpl::Deflate(w) => w.flush(),
332 #[cfg(feature = "zstd")]
333 CompressorImpl::Zstd(w) => w.flush(),
334 }
335 }
336}