singlefile_formats/
compression.rs

1#![cfg_attr(docsrs, doc(cfg(feature = "compression")))]
2#![cfg(feature = "compression")]
3
4//! Defines a compression format interface, and a [`FileFormat`] which wraps another [`FileFormat`],
5//! is generic over compression formats, and compresses the contents of the wrapped format.
6
7pub mod bzip;
8pub mod flate;
9pub mod xz;
10
11use singlefile::FileFormat;
12
13use std::io::{Read, Write};
14
15/// Combines a [`FileFormat`] and a [`CompressionFormat`], making the contents emitted by
16/// the format compressed before writing to disk, and decompressed before parsing.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct Compressed<C, F> {
19  /// The [`FileFormat`] to be used.
20  pub format: F,
21  /// The [`CompressionFormat`] to be used.
22  pub compression: C,
23  /// The level of compression to use.
24  /// This value may have different meanings for different compression formats.
25  pub level: u32
26}
27
28impl<C, F> Compressed<C, F> {
29  /// Create a new [`Compressed`], given a compression level.
30  #[inline]
31  pub const fn with_level(format: F, compression: C, level: u32) -> Self {
32    Compressed { format, compression, level }
33  }
34}
35
36impl<C, F> Compressed<C, F> where C: CompressionFormatLevels {
37  /// Creates a new [`Compressed`] with the default compression level.
38  #[inline]
39  pub const fn new(format: F, compression: C) -> Self {
40    Compressed::with_level(format, compression, C::COMPRESSION_LEVEL_DEFAULT)
41  }
42
43  /// Creates a new [`Compressed`] with the 'fast' compression level.
44  #[inline]
45  pub const fn new_fast_compression(format: F, compression: C) -> Self {
46    Compressed::with_level(format, compression, C::COMPRESSION_LEVEL_FAST)
47  }
48
49  /// Creates a new [`Compressed`] with the 'best' compression level.
50  #[inline]
51  pub const fn new_best_compression(format: F, compression: C) -> Self {
52    Compressed::with_level(format, compression, C::COMPRESSION_LEVEL_BEST)
53  }
54}
55
56impl<C, F> Default for Compressed<C, F>
57where C: Default + CompressionFormatLevels, F: Default {
58  #[inline]
59  fn default() -> Self {
60    Compressed::new(F::default(), C::default())
61  }
62}
63
64impl<T, C, F> FileFormat<T> for Compressed<C, F>
65where C: CompressionFormat, F: FileFormat<T> {
66  type FormatError = F::FormatError;
67
68  fn from_reader<R: Read>(&self, reader: R) -> Result<T, Self::FormatError> {
69    self.format.from_reader(self.compression.decode_reader(reader))
70  }
71
72  fn to_writer<W: Write>(&self, writer: W, value: &T) -> Result<(), Self::FormatError> {
73    self.format.to_writer(self.compression.encode_writer(writer, self.level), value)
74  }
75}
76
77/// Defines a format for lossless compression of arbitrary data.
78///
79/// In order to use a [`CompressionFormat`], you may consider using the [`Compressed`] struct.
80pub trait CompressionFormat {
81  /// The encoder wrapper type that compresses data sent to the contained writer.
82  type Encoder<W: Write>: Write;
83  /// The decoder wrapper type that decompresses data sent from the contained reader.
84  type Decoder<R: Read>: Read;
85
86  /// Wraps a writer that takes uncompressed data, producing a new writer that outputs compressed data.
87  fn encode_writer<W: Write>(&self, writer: W, level: u32) -> Self::Encoder<W>;
88  /// Wraps a reader that takes compressed data, producing a new reader that outputs uncompressed data.
89  fn decode_reader<R: Read>(&self, reader: R) -> Self::Decoder<R>;
90}
91
92/// Defines compression level presets for a [`CompressionFormat`].
93pub trait CompressionFormatLevels: CompressionFormat {
94  /// The level for no compression.
95  const COMPRESSION_LEVEL_NONE: u32;
96  /// The level for 'fast' compression.
97  const COMPRESSION_LEVEL_FAST: u32;
98  /// The level for 'best' compression.
99  const COMPRESSION_LEVEL_BEST: u32;
100  /// The level for default compression.
101  const COMPRESSION_LEVEL_DEFAULT: u32;
102}