1
use anyhow::Result;
2
use flate2::{Compression, CrcReader, CrcWriter};
3

            
4
use crate::RwBuilder;
5

            
6
/// Type returned by the `deflate`, `gz` and `zlib` functions on the `RwBuilder`
7
/// trait. It is itself an `RwBuilder` so can be chained further.
8
#[derive(Debug)]
9
pub struct CompressionBuilder<B, C>
10
where
11
    B: RwBuilder,
12
    C: CoderBuilder<B::Reader, B::Writer>,
13
{
14
    /// The inner builder it wraps
15
    builder: B,
16
    /// The compression used for the encoder
17
    compression: Compression,
18
    /// The builder for the encoder and decoder
19
    coder: C,
20
}
21

            
22
impl<B, C> RwBuilder for CompressionBuilder<B, C>
23
where
24
    B: RwBuilder,
25
    B::Reader: std::io::Read,
26
    B::Writer: std::io::Write,
27
    C: CoderBuilder<B::Reader, B::Writer>,
28
    C::Decoder: std::io::Read,
29
    C::Encoder: std::io::Write,
30
{
31
    type Reader = C::Decoder;
32
    type Writer = C::Encoder;
33

            
34
3
    fn reader(&self) -> Result<Self::Reader> {
35
3
        let reader = self.builder.reader()?;
36
3
        Ok(self.coder.decoder(reader))
37
3
    }
38

            
39
3
    fn writer(&self) -> Result<Self::Writer> {
40
3
        let writer = self.builder.writer()?;
41
3
        Ok(self.coder.encoder(writer, self.compression))
42
3
    }
43
}
44

            
45
/// Implementors like `Deflate`, `Gz` and `Zlib` create the associated encoders
46
/// and decoders.
47
pub trait CoderBuilder<R, W> {
48
    /// The type of encoder created
49
    type Encoder;
50

            
51
    /// Create an encoder on top of a writer
52
    fn encoder(&self, writer: W, compression: Compression) -> Self::Encoder;
53

            
54
    /// The type of decoder created
55
    type Decoder;
56

            
57
    /// Create a decoder on top of a reader
58
    fn decoder(&self, reader: R) -> Self::Decoder;
59
}
60

            
61
/// The Zlib encoder and decoder builder
62
#[derive(Default, Debug, Copy, Clone)]
63
pub struct Zlib;
64

            
65
impl<R, W> CoderBuilder<R, W> for Zlib
66
where
67
    R: std::io::Read,
68
    W: std::io::Write,
69
{
70
    type Decoder = flate2::read::ZlibDecoder<R>;
71
    type Encoder = flate2::write::ZlibEncoder<W>;
72

            
73
1
    fn encoder(&self, writer: W, compression: Compression) -> Self::Encoder {
74
1
        flate2::write::ZlibEncoder::new(writer, compression)
75
1
    }
76

            
77
1
    fn decoder(&self, reader: R) -> Self::Decoder {
78
1
        flate2::read::ZlibDecoder::new(reader)
79
1
    }
80
}
81

            
82
/// Convenience trait for creating a new encoder/decoder builder
83
pub trait Constructor<B>
84
where
85
    Self: Sized + CoderBuilder<B::Reader, B::Writer> + Default,
86
    B: RwBuilder,
87
{
88
    /// Create the encoder/decoder builder
89
3
    fn new(builder: B, compression: Compression) -> CompressionBuilder<B, Self> {
90
3
        CompressionBuilder { builder, compression, coder: Self::default() }
91
3
    }
92
}
93

            
94
impl<B> Constructor<B> for Zlib where B: RwBuilder {}
95

            
96
/// The Gz encoder and decoder builder
97
#[derive(Default, Debug, Copy, Clone)]
98
pub struct Gz;
99

            
100
impl<R, W> CoderBuilder<R, W> for Gz
101
where
102
    R: std::io::Read,
103
    W: std::io::Write,
104
{
105
    type Decoder = flate2::read::GzDecoder<R>;
106
    type Encoder = flate2::write::GzEncoder<W>;
107

            
108
1
    fn encoder(&self, writer: W, compression: Compression) -> Self::Encoder {
109
1
        flate2::write::GzEncoder::new(writer, compression)
110
1
    }
111

            
112
1
    fn decoder(&self, reader: R) -> Self::Decoder {
113
1
        flate2::read::GzDecoder::new(reader)
114
1
    }
115
}
116

            
117
impl<B> Constructor<B> for Gz where B: RwBuilder {}
118

            
119
/// The Deflate encoder and decoder builder
120
#[derive(Default, Debug, Copy, Clone)]
121
pub struct Deflate;
122

            
123
impl<R, W> CoderBuilder<R, W> for Deflate
124
where
125
    R: std::io::Read,
126
    W: std::io::Write,
127
{
128
    type Decoder = flate2::read::DeflateDecoder<R>;
129
    type Encoder = flate2::write::DeflateEncoder<W>;
130

            
131
1
    fn encoder(&self, writer: W, compression: Compression) -> Self::Encoder {
132
1
        flate2::write::DeflateEncoder::new(writer, compression)
133
1
    }
134

            
135
1
    fn decoder(&self, reader: R) -> Self::Decoder {
136
1
        flate2::read::DeflateDecoder::new(reader)
137
1
    }
138
}
139

            
140
impl<B> Constructor<B> for Deflate where B: RwBuilder {}
141

            
142
/// Type returned by the `crc` function on the `RwBuilder` trait.
143
/// It is itself an `RwBuilder` so can be chained further, although this is an
144
/// uncommon scenario
145
#[derive(Debug)]
146
pub struct CrcBuilder<B>
147
where
148
    B: RwBuilder,
149
{
150
    /// The inner builder it wraps
151
    builder: B,
152
}
153

            
154
impl<B> CrcBuilder<B>
155
where
156
    B: RwBuilder,
157
{
158
    /// Factory function to wrap an inner builder
159
    #[must_use]
160
1
    pub const fn new(builder: B) -> Self {
161
1
        Self { builder }
162
1
    }
163
}
164

            
165
impl<B> RwBuilder for CrcBuilder<B>
166
where
167
    B: RwBuilder,
168
    B::Reader: std::io::Read,
169
    B::Writer: std::io::Write,
170
{
171
    type Reader = CrcReader<B::Reader>;
172
    type Writer = CrcWriter<B::Writer>;
173

            
174
1
    fn reader(&self) -> Result<Self::Reader> {
175
1
        Ok(CrcReader::new(self.builder.reader()?))
176
1
    }
177

            
178
1
    fn writer(&self) -> Result<Self::Writer> {
179
1
        Ok(CrcWriter::new(self.builder.writer()?))
180
1
    }
181
}