1use std::fmt;
2use std::io::{Read, Result, Seek, Write};
3
4#[cfg(feature = "brotli")]
5use comde::brotli::{BrotliCompressor, BrotliDecompressor};
6#[cfg(feature = "deflate")]
7use comde::deflate::{DeflateCompressor, DeflateDecompressor};
8#[cfg(feature = "snappy")]
9use comde::snappy::{SnappyCompressor, SnappyDecompressor};
10#[cfg(feature = "xz")]
11use comde::xz::{XzCompressor, XzDecompressor};
12#[cfg(feature = "zstd")]
13use comde::zstd::{ZstdCompressor, ZstdDecompressor};
14use comde::{
15 stored::{StoredCompressor, StoredDecompressor},
16 ByteCount, Compressor, Decompress, Decompressor,
17};
18
19pub mod constants {
20 pub const COMPRESSION_STORED: u8 = 0x00;
21 pub const COMPRESSION_DEFLATE: u8 = 0x10;
22 pub const COMPRESSION_ZSTD: u8 = 0x20;
23 pub const COMPRESSION_XZ: u8 = 0x30;
24 pub const COMPRESSION_SNAPPY: u8 = 0x40;
25 pub const COMPRESSION_BROTLI: u8 = 0x50;
26}
27
28use self::constants::*;
29
30#[derive(Clone, Copy, Eq, PartialEq)]
31pub enum Compression {
32 Stored,
33 Deflate,
34 Zstd,
35 Xz,
36 Snappy,
37 Brotli,
38 Unknown(u8),
39}
40
41impl Default for Compression {
42 fn default() -> Self {
43 Self::Stored
44 }
45}
46
47impl Compression {
48 pub const fn available_variants() -> &'static [&'static str] {
49 &["stored", "brotli", "deflate", "snappy", "xz", "zstd"]
50 }
51}
52
53impl fmt::Display for Compression {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 use Compression::*;
56
57 let s = match self {
58 Stored => "stored",
59 Deflate => "DEFLATE",
60 Zstd => "Zstd",
61 Xz => "xz",
62 Snappy => "Snappy",
63 Brotli => "Brotli",
64 Unknown(id) => return write!(f, "?{:x}?", id),
65 };
66
67 write!(f, "{}", s)
68 }
69}
70
71impl fmt::Debug for Compression {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 fmt::Display::fmt(self, f)
74 }
75}
76
77impl Compression {
78 pub const fn id(self) -> u8 {
79 use Compression::*;
80
81 match self {
82 Stored => COMPRESSION_STORED,
83 Deflate => COMPRESSION_DEFLATE,
84 Zstd => COMPRESSION_ZSTD,
85 Xz => COMPRESSION_XZ,
86 Snappy => COMPRESSION_SNAPPY,
87 Brotli => COMPRESSION_BROTLI,
88 Unknown(id) => id,
89 }
90 }
91
92 pub fn compress<W: Write + Seek, R: Read>(
93 self,
94 mut writer: W,
95 reader: &mut R,
96 ) -> Result<ByteCount> {
97 use Compression::*;
98
99 match self {
100 Stored => StoredCompressor.compress(&mut writer, reader),
101 #[cfg(feature = "deflate")]
102 Deflate => DeflateCompressor.compress(&mut writer, reader),
103 #[cfg(feature = "zstd")]
104 Zstd => ZstdCompressor.compress(&mut writer, reader),
105 #[cfg(feature = "xz")]
106 Xz => XzCompressor.compress(&mut writer, reader),
107 #[cfg(feature = "snappy")]
108 Snappy => SnappyCompressor.compress(&mut writer, reader),
109 #[cfg(feature = "brotli")]
110 Brotli => BrotliCompressor.compress(&mut writer, reader),
111 Unknown(id) => Err(std::io::Error::new(
112 std::io::ErrorKind::InvalidInput,
113 format!("Cannot handle compression with id {}", id),
114 )),
115 #[allow(unreachable_patterns)]
116 missing => Err(std::io::Error::new(
117 std::io::ErrorKind::InvalidInput,
118 format!("Compiled without support for {:?}", missing),
119 )),
120 }
121 }
122
123 pub fn decompress<R: Read, V: Decompress>(self, reader: R) -> Result<V> {
124 use Compression::*;
125
126 match self {
127 Stored => StoredDecompressor.from_reader(reader),
128 #[cfg(feature = "deflate")]
129 Deflate => DeflateDecompressor.from_reader(reader),
130 #[cfg(feature = "zstd")]
131 Zstd => ZstdDecompressor.from_reader(reader),
132 #[cfg(feature = "xz")]
133 Xz => XzDecompressor.from_reader(reader),
134 #[cfg(feature = "snappy")]
135 Snappy => SnappyDecompressor.from_reader(reader),
136 #[cfg(feature = "brotli")]
137 Brotli => BrotliDecompressor.from_reader(reader),
138 Unknown(id) => Err(std::io::Error::new(
139 std::io::ErrorKind::InvalidInput,
140 format!("Cannot handle decompression with id {}", id),
141 )),
142 #[allow(unreachable_patterns)]
143 missing => Err(std::io::Error::new(
144 std::io::ErrorKind::InvalidInput,
145 format!("Compiled without support for {:?}", missing),
146 )),
147 }
148 }
149
150 pub fn decompress_write<R: Read, W: Write>(self, reader: R, writer: W) -> Result<()> {
151 use Compression::*;
152
153 match self {
154 Stored => StoredDecompressor.copy(reader, writer),
155 #[cfg(feature = "deflate")]
156 Deflate => DeflateDecompressor.copy(reader, writer),
157 #[cfg(feature = "zstd")]
158 Zstd => ZstdDecompressor.copy(reader, writer),
159 #[cfg(feature = "xz")]
160 Xz => XzDecompressor.copy(reader, writer),
161 #[cfg(feature = "snappy")]
162 Snappy => SnappyDecompressor.copy(reader, writer),
163 #[cfg(feature = "brotli")]
164 Brotli => BrotliDecompressor.copy(reader, writer),
165 Unknown(id) => Err(std::io::Error::new(
166 std::io::ErrorKind::InvalidInput,
167 format!("Cannot handle decompression with id {}", id),
168 )),
169 #[allow(unreachable_patterns)]
170 missing => Err(std::io::Error::new(
171 std::io::ErrorKind::InvalidInput,
172 format!("Compiled without support for {:?}", missing),
173 )),
174 }?;
175
176 Ok(())
177 }
178}