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
77enum DecompressorImpl<R> {
78 Store(R),
79 #[cfg(feature = "deflate")]
80 Deflate(flate2::bufread::DeflateDecoder<R>),
81 #[cfg(feature = "zstd")]
82 Zstd(zstd::Decoder<'static, R>),
83}
84
85impl<R: io::BufRead> Decompressor<R> {
86 pub fn new(reader: R, method: CompressionMethod) -> io::Result<Self> {
90 let inner = match method {
91 CompressionMethod::STORE => DecompressorImpl::Store(reader),
92 #[cfg(feature = "deflate")]
93 CompressionMethod::DEFLATE => {
94 DecompressorImpl::Deflate(flate2::bufread::DeflateDecoder::new(reader))
95 }
96 #[cfg(feature = "zstd")]
97 CompressionMethod::ZSTD => DecompressorImpl::Zstd(zstd::Decoder::with_buffer(reader)?),
98 _ => return Err(unsupported_method(method)),
99 };
100
101 Ok(Self(inner))
102 }
103
104 pub fn compression_method(&self) -> CompressionMethod {
106 match self.0 {
107 DecompressorImpl::Store(_) => CompressionMethod::STORE,
108 #[cfg(feature = "deflate")]
109 DecompressorImpl::Deflate(_) => CompressionMethod::DEFLATE,
110 #[cfg(feature = "zstd")]
111 DecompressorImpl::Zstd(_) => CompressionMethod::ZSTD,
112 }
113 }
114
115 pub fn get_mut(&mut self) -> &mut R {
119 match &mut self.0 {
120 DecompressorImpl::Store(r) => r,
121 #[cfg(feature = "deflate")]
122 DecompressorImpl::Deflate(r) => r.get_mut(),
123 #[cfg(feature = "zstd")]
124 DecompressorImpl::Zstd(r) => r.get_mut(),
125 }
126 }
127}
128
129impl<R: io::BufRead> io::Read for Decompressor<R> {
130 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
131 match &mut self.0 {
132 DecompressorImpl::Store(r) => r.read(buf),
133 #[cfg(feature = "deflate")]
134 DecompressorImpl::Deflate(r) => r.read(buf),
135 #[cfg(feature = "zstd")]
136 DecompressorImpl::Zstd(r) => r.read(buf),
137 }
138 }
139
140 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
141 match &mut self.0 {
142 DecompressorImpl::Store(r) => r.read_to_end(buf),
143 #[cfg(feature = "deflate")]
144 DecompressorImpl::Deflate(r) => r.read_to_end(buf),
145 #[cfg(feature = "zstd")]
146 DecompressorImpl::Zstd(r) => r.read_to_end(buf),
147 }
148 }
149
150 fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
151 match &mut self.0 {
152 DecompressorImpl::Store(r) => r.read_to_string(buf),
153 #[cfg(feature = "deflate")]
154 DecompressorImpl::Deflate(r) => r.read_to_string(buf),
155 #[cfg(feature = "zstd")]
156 DecompressorImpl::Zstd(r) => r.read_to_string(buf),
157 }
158 }
159}
160
161pub struct Compressor<W: io::Write>(CompressorImpl<W>);
163
164enum CompressorImpl<W: io::Write> {
165 Store(W),
166 #[cfg(feature = "deflate")]
167 Deflate(flate2::write::DeflateEncoder<W>),
168 #[cfg(feature = "zstd")]
169 Zstd(zstd::Encoder<'static, W>),
170}
171
172impl<W: io::Write> Compressor<W> {
173 pub fn new(writer: W, method: CompressionMethod, level: Option<i32>) -> io::Result<Self> {
180 let _ = level;
182
183 let inner = match method {
184 CompressionMethod::STORE => CompressorImpl::Store(writer),
185 #[cfg(feature = "deflate")]
186 CompressionMethod::DEFLATE => {
187 let level = match level {
188 Some(level) => flate2::Compression::new(level as _),
189 None => flate2::Compression::default(),
190 };
191
192 CompressorImpl::Deflate(flate2::write::DeflateEncoder::new(writer, level))
193 }
194 #[cfg(feature = "zstd")]
195 CompressionMethod::ZSTD => {
196 let level = level.unwrap_or(0);
197 CompressorImpl::Zstd(zstd::Encoder::new(writer, level)?)
198 }
199 _ => return Err(unsupported_method(method)),
200 };
201
202 Ok(Self(inner))
203 }
204
205 pub fn compression_method(&self) -> CompressionMethod {
207 match self.0 {
208 CompressorImpl::Store(_) => CompressionMethod::STORE,
209 #[cfg(feature = "deflate")]
210 CompressorImpl::Deflate(_) => CompressionMethod::DEFLATE,
211 #[cfg(feature = "zstd")]
212 CompressorImpl::Zstd(_) => CompressionMethod::ZSTD,
213 }
214 }
215
216 pub fn get_mut(&mut self) -> &mut W {
220 match &mut self.0 {
221 CompressorImpl::Store(w) => w,
222 #[cfg(feature = "deflate")]
223 CompressorImpl::Deflate(w) => w.get_mut(),
224 #[cfg(feature = "zstd")]
225 CompressorImpl::Zstd(w) => w.get_mut(),
226 }
227 }
228
229 pub fn do_finish(&mut self) -> io::Result<()> {
233 match &mut self.0 {
234 CompressorImpl::Store(_) => Ok(()),
235 #[cfg(feature = "deflate")]
236 CompressorImpl::Deflate(w) => w.try_finish(),
237 #[cfg(feature = "zstd")]
238 CompressorImpl::Zstd(w) => w.do_finish(),
239 }
240 }
241
242 pub fn finish(self) -> io::Result<W> {
246 match self.0 {
247 CompressorImpl::Store(w) => Ok(w),
248 #[cfg(feature = "deflate")]
249 CompressorImpl::Deflate(w) => w.finish(),
250 #[cfg(feature = "zstd")]
251 CompressorImpl::Zstd(w) => w.finish(),
252 }
253 }
254}
255
256impl<W: io::Write> io::Write for Compressor<W> {
257 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
258 match &mut self.0 {
259 CompressorImpl::Store(w) => w.write(buf),
260 #[cfg(feature = "deflate")]
261 CompressorImpl::Deflate(w) => w.write(buf),
262 #[cfg(feature = "zstd")]
263 CompressorImpl::Zstd(w) => w.write(buf),
264 }
265 }
266
267 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
268 match &mut self.0 {
269 CompressorImpl::Store(w) => w.write_all(buf),
270 #[cfg(feature = "deflate")]
271 CompressorImpl::Deflate(w) => w.write_all(buf),
272 #[cfg(feature = "zstd")]
273 CompressorImpl::Zstd(w) => w.write_all(buf),
274 }
275 }
276
277 fn flush(&mut self) -> io::Result<()> {
278 match &mut self.0 {
279 CompressorImpl::Store(w) => w.flush(),
280 #[cfg(feature = "deflate")]
281 CompressorImpl::Deflate(w) => w.flush(),
282 #[cfg(feature = "zstd")]
283 CompressorImpl::Zstd(w) => w.flush(),
284 }
285 }
286}