Skip to main content

zstd/stream/write/
mod.rs

1//! Implement push-based [`Write`] trait for both compressing and decompressing.
2use std::io::{self, Write};
3
4use zstd_safe;
5
6use crate::dict::{DecoderDictionary, EncoderDictionary};
7use crate::stream::{raw, zio};
8
9#[cfg(test)]
10mod tests;
11
12/// An encoder that compress and forward data to another writer.
13///
14/// This allows to compress a stream of data
15/// (good for files or heavy network stream).
16///
17/// Don't forget to call [`finish()`] before dropping it!
18///
19/// Alternatively, you can call [`auto_finish()`] to use an
20/// [`AutoFinishEncoder`] that will finish on drop.
21///
22/// Note: The zstd library has its own internal input buffer (~128kb).
23///
24/// [`finish()`]: #method.finish
25/// [`auto_finish()`]: #method.auto_finish
26/// [`AutoFinishEncoder`]: AutoFinishEncoder
27pub struct Encoder<'a, W: Write> {
28    // output writer (compressed data)
29    writer: zio::Writer<W, raw::Encoder<'a>>,
30}
31
32/// A decoder that decompress and forward data to another writer.
33///
34/// Don't forget to call [`finish()`] after writing your stream content: it
35/// flushes the decompressed data, and is the only way to know whether the
36/// input stopped in the middle of a frame.
37///
38/// You can also use [`auto_flush()`] to automatically flush the writer on
39/// drop; note that this does not check for an incomplete frame.
40///
41/// [`finish()`]: Decoder::finish
42/// [`auto_flush()`]: Decoder::auto_flush
43pub struct Decoder<'a, W: Write> {
44    // output writer (decompressed data)
45    writer: zio::Writer<W, raw::Decoder<'a>>,
46}
47
48/// A wrapper around an `Encoder<W>` that finishes the stream on drop.
49///
50/// This can be created by the [`auto_finish()`] method on the [`Encoder`].
51///
52/// If it is dropped because the wrapped writer panicked, the stream is left
53/// unfinished and the writer is not used again.
54///
55/// [`auto_finish()`]: Encoder::auto_finish
56/// [`Encoder`]: Encoder
57pub struct AutoFinishEncoder<
58    'a,
59    W: Write,
60    F: FnMut(io::Result<W>) = Box<dyn Send + FnMut(io::Result<W>)>,
61> {
62    // We wrap this in an option to take it during drop.
63    encoder: Option<Encoder<'a, W>>,
64
65    on_finish: Option<F>,
66}
67
68/// A wrapper around a `Decoder<W>` that flushes the stream on drop.
69///
70/// This can be created by the [`auto_flush()`] method on the [`Decoder`].
71///
72/// If it is dropped because the wrapped writer panicked, nothing is flushed
73/// and the writer is not used again.
74///
75/// [`auto_flush()`]: Decoder::auto_flush
76/// [`Decoder`]: Decoder
77pub struct AutoFlushDecoder<
78    'a,
79    W: Write,
80    F: FnMut(io::Result<()>) = Box<dyn Send + FnMut(io::Result<()>)>,
81> {
82    // We wrap this in an option to take it during drop.
83    decoder: Option<Decoder<'a, W>>,
84
85    on_flush: Option<F>,
86}
87
88impl<'a, W: Write, F: FnMut(io::Result<()>)> AutoFlushDecoder<'a, W, F> {
89    fn new(decoder: Decoder<'a, W>, on_flush: F) -> Self {
90        AutoFlushDecoder {
91            decoder: Some(decoder),
92            on_flush: Some(on_flush),
93        }
94    }
95
96    /// Acquires a reference to the underlying writer.
97    pub fn get_ref(&self) -> &W {
98        self.decoder.as_ref().unwrap().get_ref()
99    }
100
101    /// Acquires a mutable reference to the underlying writer.
102    ///
103    /// Note that mutation of the writer may result in surprising results if
104    /// this decoder is continued to be used.
105    ///
106    /// Mostly used for testing purposes.
107    pub fn get_mut(&mut self) -> &mut W {
108        self.decoder.as_mut().unwrap().get_mut()
109    }
110}
111
112impl<W, F> Drop for AutoFlushDecoder<'_, W, F>
113where
114    W: Write,
115    F: FnMut(io::Result<()>),
116{
117    fn drop(&mut self) {
118        let mut decoder = self.decoder.take().unwrap();
119        // The writer panicked and still has the same data pending: calling
120        // it again would panic again, and a second panic while unwinding
121        // aborts the process.
122        if decoder.writer.panicked() {
123            return;
124        }
125        let result = decoder.flush();
126        if let Some(mut on_finish) = self.on_flush.take() {
127            on_finish(result);
128        }
129    }
130}
131
132impl<W: Write, F: FnMut(io::Result<()>)> Write for AutoFlushDecoder<'_, W, F> {
133    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
134        self.decoder.as_mut().unwrap().write(buf)
135    }
136
137    fn flush(&mut self) -> io::Result<()> {
138        self.decoder.as_mut().unwrap().flush()
139    }
140}
141
142impl<'a, W: Write, F: FnMut(io::Result<W>)> AutoFinishEncoder<'a, W, F> {
143    fn new(encoder: Encoder<'a, W>, on_finish: F) -> Self {
144        AutoFinishEncoder {
145            encoder: Some(encoder),
146            on_finish: Some(on_finish),
147        }
148    }
149
150    /// Acquires a reference to the underlying writer.
151    pub fn get_ref(&self) -> &W {
152        self.encoder.as_ref().unwrap().get_ref()
153    }
154
155    /// Acquires a mutable reference to the underlying writer.
156    ///
157    /// Note that mutation of the writer may result in surprising results if
158    /// this encoder is continued to be used.
159    ///
160    /// Mostly used for testing purposes.
161    pub fn get_mut(&mut self) -> &mut W {
162        self.encoder.as_mut().unwrap().get_mut()
163    }
164}
165
166impl<W: Write, F: FnMut(io::Result<W>)> Drop for AutoFinishEncoder<'_, W, F> {
167    fn drop(&mut self) {
168        let encoder = self.encoder.take().unwrap();
169        // The writer panicked and still has the same data pending: calling
170        // it again would panic again, and a second panic while unwinding
171        // aborts the process.
172        if encoder.writer.panicked() {
173            return;
174        }
175        let result = encoder.finish();
176        if let Some(mut on_finish) = self.on_finish.take() {
177            on_finish(result);
178        }
179    }
180}
181
182impl<W: Write, F: FnMut(io::Result<W>)> Write for AutoFinishEncoder<'_, W, F> {
183    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
184        self.encoder.as_mut().unwrap().write(buf)
185    }
186
187    fn flush(&mut self) -> io::Result<()> {
188        self.encoder.as_mut().unwrap().flush()
189    }
190}
191
192impl<W: Write> Encoder<'static, W> {
193    /// Creates a new encoder.
194    ///
195    /// `level`: compression level (1-22).
196    ///
197    /// A level of `0` uses zstd's default (currently `3`).
198    pub fn new(writer: W, level: i32) -> io::Result<Self> {
199        Self::with_dictionary(writer, level, &[])
200    }
201
202    /// Creates a new encoder, using an existing dictionary.
203    ///
204    /// (Provides better compression ratio for small files,
205    /// but requires the dictionary to be present during decompression.)
206    ///
207    /// A level of `0` uses zstd's default (currently `3`).
208    pub fn with_dictionary(
209        writer: W,
210        level: i32,
211        dictionary: &[u8],
212    ) -> io::Result<Self> {
213        let encoder = raw::Encoder::with_dictionary(level, dictionary)?;
214        Ok(Self::with_encoder(writer, encoder))
215    }
216}
217
218impl<'a, W: Write> Encoder<'a, W> {
219    /// Creates a new encoder from a prepared zio writer.
220    pub fn with_writer(writer: zio::Writer<W, raw::Encoder<'a>>) -> Self {
221        Self { writer }
222    }
223
224    /// Creates a new encoder from the given `Write` and raw encoder.
225    pub fn with_encoder(writer: W, encoder: raw::Encoder<'a>) -> Self {
226        let writer = zio::Writer::new(writer, encoder);
227        Self::with_writer(writer)
228    }
229
230    /// Creates an encoder that uses the provided context to compress a stream.
231    pub fn with_context(
232        writer: W,
233        context: &'a mut zstd_safe::CCtx<'static>,
234    ) -> Self {
235        let encoder = raw::Encoder::with_context(context);
236        Self::with_encoder(writer, encoder)
237    }
238
239    /// Creates a new encoder, using an existing prepared `EncoderDictionary`.
240    ///
241    /// (Provides better compression ratio for small files,
242    /// but requires the dictionary to be present during decompression.)
243    pub fn with_prepared_dictionary<'b>(
244        writer: W,
245        dictionary: &'a EncoderDictionary<'b>,
246    ) -> io::Result<Self>
247    where
248        'b: 'a,
249    {
250        let encoder = raw::Encoder::with_prepared_dictionary(dictionary)?;
251        Ok(Self::with_encoder(writer, encoder))
252    }
253
254    /// Creates a new encoder, using a ref prefix
255    pub fn with_ref_prefix<'b>(
256        writer: W,
257        level: i32,
258        ref_prefix: &'b [u8],
259    ) -> io::Result<Self>
260    where
261        'b: 'a,
262    {
263        let encoder = raw::Encoder::with_ref_prefix(level, ref_prefix)?;
264        Ok(Self::with_encoder(writer, encoder))
265    }
266
267    /// Returns a wrapper around `self` that will finish the stream on drop.
268    pub fn auto_finish(self) -> AutoFinishEncoder<'a, W> {
269        AutoFinishEncoder {
270            encoder: Some(self),
271            on_finish: None,
272        }
273    }
274
275    /// Returns an encoder that will finish the stream on drop.
276    ///
277    /// Calls the given callback with the result from `finish()`. This runs during drop so it's
278    /// important that the provided callback doesn't panic. It is not called if the wrapped
279    /// writer panicked.
280    pub fn on_finish<F: FnMut(io::Result<W>)>(
281        self,
282        f: F,
283    ) -> AutoFinishEncoder<'a, W, F> {
284        AutoFinishEncoder::new(self, f)
285    }
286
287    /// Acquires a reference to the underlying writer.
288    pub fn get_ref(&self) -> &W {
289        self.writer.writer()
290    }
291
292    /// Acquires a mutable reference to the underlying writer.
293    ///
294    /// Note that mutation of the writer may result in surprising results if
295    /// this encoder is continued to be used.
296    pub fn get_mut(&mut self) -> &mut W {
297        self.writer.writer_mut()
298    }
299
300    /// **Required**: Finishes the stream.
301    ///
302    /// You *need* to finish the stream when you're done writing, either with
303    /// this method or with [`try_finish(self)`](#method.try_finish).
304    ///
305    /// This returns the inner writer in case you need it.
306    ///
307    /// To get back `self` in case an error happened, use `try_finish`.
308    ///
309    /// **Note**: If you don't want (or can't) call `finish()` manually after
310    ///           writing your data, consider using `auto_finish()` to get an
311    ///           `AutoFinishEncoder`.
312    pub fn finish(self) -> io::Result<W> {
313        self.try_finish().map_err(|(_, err)| err)
314    }
315
316    /// **Required**: Attempts to finish the stream.
317    ///
318    /// You *need* to finish the stream when you're done writing, either with
319    /// this method or with [`finish(self)`](#method.finish).
320    ///
321    /// This returns the inner writer if the finish was successful, or the
322    /// object plus an error if it wasn't.
323    ///
324    /// `write` on this object will panic after `try_finish` has been called,
325    /// even if it fails.
326    pub fn try_finish(mut self) -> Result<W, (Self, io::Error)> {
327        match self.writer.finish() {
328            // Return the writer, because why not
329            Ok(()) => Ok(self.writer.into_inner().0),
330            Err(e) => Err((self, e)),
331        }
332    }
333
334    /// Attempts to finish the stream.
335    ///
336    /// You *need* to finish the stream when you're done writing, either with
337    /// this method or with [`finish(self)`](#method.finish).
338    pub fn do_finish(&mut self) -> io::Result<()> {
339        self.writer.finish()
340    }
341
342    /// Return a recommendation for the size of data to write at once.
343    pub fn recommended_input_size() -> usize {
344        zstd_safe::CCtx::in_size()
345    }
346
347    crate::encoder_common!(writer);
348}
349
350impl<'a, W: Write> Write for Encoder<'a, W> {
351    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
352        self.writer.write(buf)
353    }
354
355    fn flush(&mut self) -> io::Result<()> {
356        self.writer.flush()
357    }
358}
359
360impl<W: Write> Decoder<'static, W> {
361    /// Creates a new decoder.
362    pub fn new(writer: W) -> io::Result<Self> {
363        Self::with_dictionary(writer, &[])
364    }
365
366    /// Creates a new decoder, using an existing dictionary.
367    ///
368    /// (Provides better compression ratio for small files,
369    /// but requires the dictionary to be present during decompression.)
370    pub fn with_dictionary(writer: W, dictionary: &[u8]) -> io::Result<Self> {
371        let decoder = raw::Decoder::with_dictionary(dictionary)?;
372        Ok(Self::with_decoder(writer, decoder))
373    }
374}
375
376impl<'a, W: Write> Decoder<'a, W> {
377    /// Creates a new decoder around the given prepared zio writer.
378    ///
379    /// # Examples
380    ///
381    /// ```rust
382    /// fn wrap<W: std::io::Write>(writer: W) -> zstd::stream::write::Decoder<'static, W> {
383    ///   let decoder = zstd::stream::raw::Decoder::new().unwrap();
384    ///   let writer = zstd::stream::zio::Writer::new(writer, decoder);
385    ///   zstd::stream::write::Decoder::with_writer(writer)
386    /// }
387    /// ```
388    pub fn with_writer(writer: zio::Writer<W, raw::Decoder<'a>>) -> Self {
389        Decoder { writer }
390    }
391
392    /// Creates a new decoder around the given `Write` and raw decoder.
393    pub fn with_decoder(writer: W, decoder: raw::Decoder<'a>) -> Self {
394        let writer = zio::Writer::new(writer, decoder);
395        Decoder { writer }
396    }
397
398    /// Creates a decoder that uses the provided context to decompress a stream.
399    pub fn with_context(
400        writer: W,
401        context: &'a mut zstd_safe::DCtx<'static>,
402    ) -> Self {
403        let encoder = raw::Decoder::with_context(context);
404        Self::with_decoder(writer, encoder)
405    }
406
407    /// Creates a new decoder, using an existing prepared `DecoderDictionary`.
408    ///
409    /// (Provides better compression ratio for small files,
410    /// but requires the dictionary to be present during decompression.)
411    pub fn with_prepared_dictionary<'b>(
412        writer: W,
413        dictionary: &'a DecoderDictionary<'b>,
414    ) -> io::Result<Self>
415    where
416        'b: 'a,
417    {
418        let decoder = raw::Decoder::with_prepared_dictionary(dictionary)?;
419        Ok(Self::with_decoder(writer, decoder))
420    }
421
422    /// Acquires a reference to the underlying writer.
423    pub fn get_ref(&self) -> &W {
424        self.writer.writer()
425    }
426
427    /// Acquires a mutable reference to the underlying writer.
428    ///
429    /// Note that mutation of the writer may result in surprising results if
430    /// this decoder is continued to be used.
431    pub fn get_mut(&mut self) -> &mut W {
432        self.writer.writer_mut()
433    }
434
435    /// Returns the inner `Write`.
436    ///
437    /// Careful: this neither flushes the decompressed data nor checks that
438    /// the input ended on a complete frame.
439    /// Use [`finish(self)`](#method.finish) for that.
440    pub fn into_inner(self) -> W {
441        self.writer.into_inner().0
442    }
443
444    /// Finishes the stream.
445    ///
446    /// This flushes all the decompressed data, and returns an `UnexpectedEof`
447    /// error if the data written so far does not end on a complete frame.
448    ///
449    /// This returns the inner writer in case you need it.
450    pub fn finish(mut self) -> io::Result<W> {
451        self.do_finish()?;
452        Ok(self.into_inner())
453    }
454
455    /// Attempts to finish the stream.
456    ///
457    /// Same as [`finish(self)`](#method.finish), but does not consume `self`.
458    ///
459    /// `write` on this object will fail after `do_finish` has succeeded.
460    pub fn do_finish(&mut self) -> io::Result<()> {
461        // Unlike when encoding, finishing does not flush anything by itself.
462        self.writer.flush()?;
463        self.writer.finish()
464    }
465
466    /// Return a recommendation for the size of data to write at once.
467    pub fn recommended_input_size() -> usize {
468        zstd_safe::DCtx::in_size()
469    }
470
471    /// Returns a wrapper around `self` that will flush the stream on drop.
472    pub fn auto_flush(self) -> AutoFlushDecoder<'a, W> {
473        AutoFlushDecoder {
474            decoder: Some(self),
475            on_flush: None,
476        }
477    }
478
479    /// Returns a decoder that will flush the stream on drop.
480    ///
481    /// Calls the given callback with the result from `flush()`. This runs during drop so it's
482    /// important that the provided callback doesn't panic. It is not called if the wrapped
483    /// writer panicked.
484    pub fn on_flush<F: FnMut(io::Result<()>)>(
485        self,
486        f: F,
487    ) -> AutoFlushDecoder<'a, W, F> {
488        AutoFlushDecoder::new(self, f)
489    }
490
491    crate::decoder_common!(writer);
492}
493
494impl<W: Write> Write for Decoder<'_, W> {
495    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
496        self.writer.write(buf)
497    }
498
499    fn flush(&mut self) -> io::Result<()> {
500        self.writer.flush()
501    }
502}
503
504fn _assert_traits() {
505    fn _assert_send<T: Send>(_: T) {}
506
507    _assert_send(Decoder::new(Vec::new()));
508    _assert_send(Encoder::new(Vec::new(), 1));
509    _assert_send(Decoder::new(Vec::new()).unwrap().auto_flush());
510    _assert_send(Encoder::new(Vec::new(), 1).unwrap().auto_finish());
511}