1#![cfg_attr(docsrs, feature(doc_cfg))]
16#![forbid(unsafe_code)]
17#![warn(
18 future_incompatible,
19 missing_copy_implementations,
20 missing_debug_implementations,
21 missing_docs,
22 unreachable_pub
23)]
24
25pub extern crate singlefile;
26
27use singlefile::FileFormat;
28
29use std::io::{Read, Write};
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub struct Compressed<C, F> {
35 pub format: F,
37 pub compression: C,
39 pub level: u32
42}
43
44impl<C, F> Compressed<C, F> {
45 #[inline]
47 pub const fn with_level(format: F, compression: C, level: u32) -> Self {
48 Compressed { format, compression, level }
49 }
50}
51
52impl<C, F> Compressed<C, F> where C: CompressionFormatLevels {
53 #[inline]
55 pub const fn new(format: F, compression: C) -> Self {
56 Compressed::with_level(format, compression, C::COMPRESSION_LEVEL_DEFAULT)
57 }
58
59 #[inline]
61 pub const fn new_fast_compression(format: F, compression: C) -> Self {
62 Compressed::with_level(format, compression, C::COMPRESSION_LEVEL_FAST)
63 }
64
65 #[inline]
67 pub const fn new_best_compression(format: F, compression: C) -> Self {
68 Compressed::with_level(format, compression, C::COMPRESSION_LEVEL_BEST)
69 }
70}
71
72impl<C, F> Default for Compressed<C, F>
73where C: Default + CompressionFormatLevels, F: Default {
74 #[inline]
75 fn default() -> Self {
76 Compressed::new(F::default(), C::default())
77 }
78}
79
80impl<T, C, F> FileFormat<T> for Compressed<C, F>
81where C: CompressionFormat, F: FileFormat<T> {
82 type FormatError = F::FormatError;
83
84 fn from_reader<R: Read>(&self, reader: R) -> Result<T, Self::FormatError> {
85 self.format.from_reader(self.compression.decode_reader(reader))
86 }
87
88 fn to_writer<W: Write>(&self, writer: W, value: &T) -> Result<(), Self::FormatError> {
89 self.format.to_writer(self.compression.encode_writer(writer, self.level), value)
90 }
91}
92
93pub trait CompressionFormat {
97 type Encoder<W: Write>: Write;
99 type Decoder<R: Read>: Read;
101
102 fn encode_writer<W: Write>(&self, writer: W, level: u32) -> Self::Encoder<W>;
104 fn decode_reader<R: Read>(&self, reader: R) -> Self::Decoder<R>;
106}
107
108pub trait CompressionFormatLevels: CompressionFormat {
110 const COMPRESSION_LEVEL_NONE: u32;
112 const COMPRESSION_LEVEL_FAST: u32;
114 const COMPRESSION_LEVEL_BEST: u32;
116 const COMPRESSION_LEVEL_DEFAULT: u32;
118}
119
120#[cfg_attr(docsrs, doc(cfg(feature = "cbor-serde")))]
122#[cfg(feature = "cbor-serde")]
123pub mod cbor_serde {
124 pub extern crate ciborium;
125
126 use serde::ser::Serialize;
127 use serde::de::DeserializeOwned;
128 use singlefile::FileFormat;
129 use thiserror::Error;
130
131 use std::io::{Read, Write};
132
133 #[derive(Debug, Error)]
135 pub enum CborError {
136 #[error(transparent)]
138 SerializeError(#[from] ciborium::ser::Error<std::io::Error>),
139 #[error(transparent)]
141 DeserializeError(#[from] ciborium::de::Error<std::io::Error>)
142 }
143
144 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
147 pub struct Cbor;
148
149 impl<T> FileFormat<T> for Cbor
150 where T: Serialize + DeserializeOwned {
151 type FormatError = CborError;
152
153 fn from_reader<R: Read>(&self, reader: R) -> Result<T, Self::FormatError> {
154 ciborium::de::from_reader(reader).map_err(From::from)
155 }
156
157 fn to_writer<W: Write>(&self, writer: W, value: &T) -> Result<(), Self::FormatError> {
158 ciborium::ser::into_writer(value, writer).map_err(From::from)
159 }
160 }
161
162 pub type CompressedCbor<C> = crate::Compressed<C, Cbor>;
165}
166
167#[cfg_attr(docsrs, doc(cfg(feature = "json-serde")))]
169#[cfg(feature = "json-serde")]
170pub mod json_serde {
171 pub extern crate serde_json;
172
173 use serde::ser::Serialize;
174 use serde::de::DeserializeOwned;
175 use singlefile::FileFormat;
176
177 use std::io::{Read, Write};
178
179 pub type JsonError = serde_json::Error;
181
182 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
187 pub struct Json<const PRETTY: bool = true>;
188
189 impl<T, const PRETTY: bool> FileFormat<T> for Json<PRETTY>
190 where T: Serialize + DeserializeOwned {
191 type FormatError = JsonError;
192
193 fn from_reader<R: Read>(&self, reader: R) -> Result<T, Self::FormatError> {
194 serde_json::from_reader(reader)
195 }
196
197 fn to_writer<W: Write>(&self, writer: W, value: &T) -> Result<(), Self::FormatError> {
198 match PRETTY {
199 true => serde_json::to_writer_pretty(writer, value),
200 false => serde_json::to_writer(writer, value)
201 }
202 }
203
204 fn to_buffer(&self, value: &T) -> Result<Vec<u8>, Self::FormatError> {
205 match PRETTY {
206 true => serde_json::to_vec_pretty(value),
207 false => serde_json::to_vec(value)
208 }
209 }
210 }
211
212 pub type PrettyJson = Json<true>;
214 pub type RegularJson = Json<false>;
216
217 pub type CompressedJson<C, const PRETTY: bool = false> = crate::Compressed<C, Json<PRETTY>>;
220}
221
222#[cfg_attr(docsrs, doc(cfg(feature = "toml-serde")))]
224#[cfg(feature = "toml-serde")]
225pub mod toml_serde {
226 pub extern crate toml;
227
228 use serde::ser::Serialize;
229 use serde::de::DeserializeOwned;
230 use singlefile::FileFormat;
231 use thiserror::Error;
232
233 use std::io::{Read, Write};
234
235 #[derive(Debug, Error)]
237 pub enum TomlError {
238 #[error(transparent)]
240 IoError(#[from] std::io::Error),
241 #[error(transparent)]
243 SerializeError(#[from] toml::ser::Error),
244 #[error(transparent)]
246 DeserializeError(#[from] toml::de::Error)
247 }
248
249 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
254 pub struct Toml<const PRETTY: bool = true>;
255
256 impl<T, const PRETTY: bool> FileFormat<T> for Toml<PRETTY>
258 where T: Serialize + DeserializeOwned {
259 type FormatError = TomlError;
260
261 fn from_reader<R: Read>(&self, mut reader: R) -> Result<T, Self::FormatError> {
262 let mut buf = String::new();
263 reader.read_to_string(&mut buf)?;
264 toml::de::from_str(&buf).map_err(From::from)
265 }
266
267 #[inline]
268 fn from_reader_buffered<R: Read>(&self, reader: R) -> Result<T, Self::FormatError> {
269 self.from_reader(reader)
271 }
272
273 fn to_writer<W: Write>(&self, mut writer: W, value: &T) -> Result<(), Self::FormatError> {
274 let buf = self.to_buffer(value)?;
275 writer.write_all(&buf).map_err(From::from)
276 }
277
278 #[inline]
279 fn to_writer_buffered<W: Write>(&self, writer: W, value: &T) -> Result<(), Self::FormatError> {
280 self.to_writer(writer, value)
282 }
283
284 fn to_buffer(&self, value: &T) -> Result<Vec<u8>, Self::FormatError> {
285 Ok(match PRETTY {
286 true => toml::ser::to_string_pretty(value),
287 false => toml::ser::to_string(value)
288 }?.into_bytes())
289 }
290 }
291
292 pub type PrettyToml = Toml<true>;
294 pub type RegularToml = Toml<false>;
296
297 pub type CompressedToml<C, const PRETTY: bool = false> = crate::Compressed<C, Toml<PRETTY>>;
300}
301
302#[cfg_attr(docsrs, doc(cfg(feature = "bzip")))]
304#[cfg(feature = "bzip")]
305pub mod bzip {
306 pub extern crate bzip2;
307
308 use crate::{CompressionFormat, CompressionFormatLevels};
309
310 use std::io::{Read, Write};
311
312 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
315 pub struct BZip2;
316
317 impl CompressionFormat for BZip2 {
318 type Encoder<W: Write> = bzip2::write::BzEncoder::<W>;
319 type Decoder<R: Read> = bzip2::read::BzDecoder::<R>;
320
321 fn encode_writer<W: Write>(&self, writer: W, level: u32) -> Self::Encoder<W> {
322 Self::Encoder::new(writer, bzip2::Compression::new(level))
323 }
324
325 fn decode_reader<R: Read>(&self, reader: R) -> Self::Decoder<R> {
326 Self::Decoder::new(reader)
327 }
328 }
329
330 impl CompressionFormatLevels for BZip2 {
331 const COMPRESSION_LEVEL_NONE: u32 = 0;
332 const COMPRESSION_LEVEL_FAST: u32 = 1;
333 const COMPRESSION_LEVEL_BEST: u32 = 9;
334 const COMPRESSION_LEVEL_DEFAULT: u32 = 6;
335 }
336}
337
338#[cfg_attr(docsrs, doc(cfg(feature = "flate")))]
340#[cfg(feature = "flate")]
341pub mod flate {
342 pub extern crate flate2;
343
344 use crate::{CompressionFormat, CompressionFormatLevels};
345
346 use std::io::{Read, Write};
347
348 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
351 pub struct Deflate;
352
353 impl CompressionFormat for Deflate {
354 type Encoder<W: Write> = flate2::write::DeflateEncoder::<W>;
355 type Decoder<R: Read> = flate2::read::DeflateDecoder::<R>;
356
357 fn encode_writer<W: Write>(&self, writer: W, compression: u32) -> Self::Encoder<W> {
358 Self::Encoder::new(writer, flate2::Compression::new(compression))
359 }
360
361 fn decode_reader<R: Read>(&self, reader: R) -> Self::Decoder<R> {
362 Self::Decoder::new(reader)
363 }
364 }
365
366 impl CompressionFormatLevels for Deflate {
367 const COMPRESSION_LEVEL_NONE: u32 = 0;
368 const COMPRESSION_LEVEL_FAST: u32 = 1;
369 const COMPRESSION_LEVEL_BEST: u32 = 9;
370 const COMPRESSION_LEVEL_DEFAULT: u32 = 6;
371 }
372
373 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
376 pub struct Gz;
377
378 impl CompressionFormat for Gz {
379 type Encoder<W: Write> = flate2::write::GzEncoder::<W>;
380 type Decoder<R: Read> = flate2::read::GzDecoder::<R>;
381
382 fn encode_writer<W: Write>(&self, writer: W, compression: u32) -> Self::Encoder<W> {
383 Self::Encoder::new(writer, flate2::Compression::new(compression))
384 }
385
386 fn decode_reader<R: Read>(&self, reader: R) -> Self::Decoder<R> {
387 Self::Decoder::new(reader)
388 }
389 }
390
391 impl CompressionFormatLevels for Gz {
392 const COMPRESSION_LEVEL_NONE: u32 = 0;
393 const COMPRESSION_LEVEL_FAST: u32 = 1;
394 const COMPRESSION_LEVEL_BEST: u32 = 9;
395 const COMPRESSION_LEVEL_DEFAULT: u32 = 6;
396 }
397
398 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
401 pub struct ZLib;
402
403 impl CompressionFormat for ZLib {
404 type Encoder<W: Write> = flate2::write::ZlibEncoder::<W>;
405 type Decoder<R: Read> = flate2::read::ZlibDecoder::<R>;
406
407 fn encode_writer<W: Write>(&self, writer: W, compression: u32) -> Self::Encoder<W> {
408 Self::Encoder::new(writer, flate2::Compression::new(compression))
409 }
410
411 fn decode_reader<R: Read>(&self, reader: R) -> Self::Decoder<R> {
412 Self::Decoder::new(reader)
413 }
414 }
415
416 impl CompressionFormatLevels for ZLib {
417 const COMPRESSION_LEVEL_NONE: u32 = 0;
418 const COMPRESSION_LEVEL_FAST: u32 = 1;
419 const COMPRESSION_LEVEL_BEST: u32 = 9;
420 const COMPRESSION_LEVEL_DEFAULT: u32 = 6;
421 }
422}
423
424#[cfg_attr(docsrs, doc(cfg(feature = "xz")))]
426#[cfg(feature = "xz")]
427pub mod xz {
428 pub extern crate xz2;
429
430 use crate::{CompressionFormat, CompressionFormatLevels};
431
432 use std::io::{Read, Write};
433
434 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
437 pub struct Xz;
438
439 impl CompressionFormat for Xz {
440 type Encoder<W: Write> = xz2::write::XzEncoder::<W>;
441 type Decoder<R: Read> = xz2::read::XzDecoder::<R>;
442
443 fn encode_writer<W: Write>(&self, writer: W, compression: u32) -> Self::Encoder<W> {
444 Self::Encoder::new(writer, compression)
445 }
446
447 fn decode_reader<R: Read>(&self, reader: R) -> Self::Decoder<R> {
448 Self::Decoder::new(reader)
449 }
450 }
451
452 impl CompressionFormatLevels for Xz {
453 const COMPRESSION_LEVEL_NONE: u32 = 0;
454 const COMPRESSION_LEVEL_FAST: u32 = 1;
455 const COMPRESSION_LEVEL_BEST: u32 = 9;
456 const COMPRESSION_LEVEL_DEFAULT: u32 = 6;
457 }
458}