Skip to main content

zstd/stream/zio/
writer.rs

1use std::io::{self, Write};
2
3use crate::stream::raw::{InBuffer, Operation, OutBuffer};
4
5// input -> [ zstd -> buffer -> writer ]
6
7/// Implements the [`Write`] API around an [`Operation`].
8///
9/// This can be used to wrap a raw in-memory operation in a write-focused API.
10///
11/// It can be used with either compression or decompression, and forwards the
12/// output to a wrapped `Write`.
13pub struct Writer<W, D> {
14    /// Either an encoder or a decoder.
15    operation: D,
16
17    /// Where we send the output of the operation.
18    writer: W,
19
20    /// Offset into the buffer
21    ///
22    /// Only things after this matter. Things before have already been sent to the writer.
23    offset: usize,
24
25    /// Output buffer
26    ///
27    /// Where the operation writes, before it gets flushed to the writer
28    buffer: Vec<u8>,
29
30    // When `true`, indicates that nothing should be added to the buffer.
31    // All that's left if to empty the buffer.
32    finished: bool,
33
34    /// When `true`, the operation just finished a frame.
35    ///
36    /// Only happens when decompressing.
37    /// The context needs to be re-initialized to process the next frame.
38    finished_frame: bool,
39
40    /// When `true`, a call into `writer` is in progress.
41    ///
42    /// Stays `true` if that call panicked: the pending data must not be
43    /// handed to the writer again, in particular not from a destructor.
44    panicked: bool,
45}
46
47impl<W, D> Writer<W, D>
48where
49    W: Write,
50    D: Operation,
51{
52    /// Creates a new `Writer` with a fixed buffer capacity of 32KB
53    ///
54    /// All output from the given operation will be forwarded to `writer`.
55    pub fn new(writer: W, operation: D) -> Self {
56        // 32KB buffer? That's what flate2 uses
57        Self::new_with_capacity(writer, operation, 32 * 1024)
58    }
59
60    /// Creates a new `Writer` with user defined capacity.
61    ///
62    /// All output from the given operation will be forwarded to `writer`.
63    pub fn new_with_capacity(
64        writer: W,
65        operation: D,
66        capacity: usize,
67    ) -> Self {
68        Self::with_output_buffer(
69            Vec::with_capacity(capacity),
70            writer,
71            operation,
72        )
73    }
74
75    /// Creates a new `Writer` using the given output buffer.
76    ///
77    /// The output buffer _must_ have pre-allocated capacity (its capacity will not be changed after).
78    ///
79    /// Usually you would use `Vec::with_capacity(desired_buffer_size)`.
80    pub fn with_output_buffer(
81        output_buffer: Vec<u8>,
82        writer: W,
83        operation: D,
84    ) -> Self {
85        Writer {
86            writer,
87            operation,
88
89            offset: 0,
90            // 32KB buffer? That's what flate2 uses
91            buffer: output_buffer,
92
93            finished: false,
94            finished_frame: false,
95            panicked: false,
96        }
97    }
98
99    /// Ends the stream.
100    ///
101    /// This *must* be called after all data has been written to finish the
102    /// stream.
103    ///
104    /// If you forget to call this and just drop the `Writer`, you *will* have
105    /// an incomplete output.
106    ///
107    /// Keep calling it until it returns `Ok(())`, then don't call it again.
108    pub fn finish(&mut self) -> io::Result<()> {
109        loop {
110            // Keep trying until we're really done.
111            self.write_from_offset()?;
112
113            // At this point the buffer has been fully written out.
114
115            if self.finished {
116                return Ok(());
117            }
118
119            // Let's fill this buffer again!
120
121            let finished_frame = self.finished_frame;
122            let hint =
123                self.with_buffer(|dst, op| op.finish(dst, finished_frame));
124            self.offset = 0;
125            // println!("Hint: {:?}\nOut:{:?}", hint, &self.buffer);
126
127            // We return here if zstd had a problem.
128            // Could happen with invalid data, ...
129            let hint = hint?;
130
131            if hint != 0 && self.buffer.is_empty() {
132                // This happens if we are decoding an incomplete frame.
133                return Err(io::Error::new(
134                    io::ErrorKind::UnexpectedEof,
135                    "incomplete frame",
136                ));
137            }
138
139            // println!("Finishing {}, {}", bytes_written, hint);
140
141            self.finished = hint == 0;
142        }
143    }
144
145    /// Run the given closure on `self.buffer`.
146    ///
147    /// The buffer will be cleared, and made available wrapped in an `OutBuffer`.
148    fn with_buffer<F, T>(&mut self, f: F) -> T
149    where
150        F: FnOnce(&mut OutBuffer<'_, Vec<u8>>, &mut D) -> T,
151    {
152        self.buffer.clear();
153        let mut output = OutBuffer::around(&mut self.buffer);
154        // eprintln!("Output: {:?}", output);
155        f(&mut output, &mut self.operation)
156    }
157
158    /// Attempt to write `self.buffer` to the wrapped writer.
159    ///
160    /// Returns `Ok(())` once all the buffer has been written.
161    fn write_from_offset(&mut self) -> io::Result<()> {
162        // The code looks a lot like `write_all`, but keeps track of what has
163        // been written in case we're interrupted.
164        while self.offset < self.buffer.len() {
165            self.panicked = true;
166            let result = self.writer.write(&self.buffer[self.offset..]);
167            self.panicked = false;
168            match result {
169                Ok(0) => {
170                    return Err(io::Error::new(
171                        io::ErrorKind::WriteZero,
172                        "writer will not accept any more data",
173                    ))
174                }
175                Ok(n) => self.offset += n,
176                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (),
177                Err(e) => return Err(e),
178            }
179        }
180        Ok(())
181    }
182
183    /// Return the wrapped `Writer` and `Operation`.
184    ///
185    /// Careful: if you call this before calling [`Writer::finish()`], the
186    /// output may be incomplete.
187    pub fn into_inner(self) -> (W, D) {
188        (self.writer, self.operation)
189    }
190
191    /// Gives a reference to the inner writer.
192    pub fn writer(&self) -> &W {
193        &self.writer
194    }
195
196    /// Gives a mutable reference to the inner writer.
197    pub fn writer_mut(&mut self) -> &mut W {
198        &mut self.writer
199    }
200
201    /// Gives a reference to the inner operation.
202    pub fn operation(&self) -> &D {
203        &self.operation
204    }
205
206    /// Gives a mutable reference to the inner operation.
207    pub fn operation_mut(&mut self) -> &mut D {
208        &mut self.operation
209    }
210
211    /// Returns `true` if the last call into the wrapped writer panicked.
212    ///
213    /// Calling the writer again would likely panic again, which aborts the
214    /// process if it happens during unwinding.
215    pub(crate) fn panicked(&self) -> bool {
216        self.panicked
217    }
218
219    /// Returns the offset in the current buffer. Only useful for debugging.
220    #[cfg(test)]
221    pub fn offset(&self) -> usize {
222        self.offset
223    }
224
225    /// Returns the current buffer. Only useful for debugging.
226    #[cfg(test)]
227    pub fn buffer(&self) -> &[u8] {
228        &self.buffer
229    }
230}
231
232impl<W, D> Write for Writer<W, D>
233where
234    W: Write,
235    D: Operation,
236{
237    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
238        if self.finished {
239            return Err(io::Error::new(
240                io::ErrorKind::Other,
241                "encoder is finished",
242            ));
243        }
244        // Keep trying until _something_ has been consumed.
245        // As soon as some input has been taken, we cannot afford
246        // to take any chance: if an error occurs, the user couldn't know
247        // that some data _was_ successfully written.
248        loop {
249            // First, write any pending data from `self.buffer`.
250            self.write_from_offset()?;
251            // At this point `self.buffer` can safely be discarded.
252
253            // Support writing concatenated frames by re-initializing the
254            // context.
255            // We don't want empty input to cause a frame re-initialization:
256            // it would forget that the stream ended on a complete frame.
257            if self.finished_frame && !buf.is_empty() {
258                self.operation.reinit()?;
259                self.finished_frame = false;
260            }
261
262            let mut src = InBuffer::around(buf);
263            let hint = self.with_buffer(|dst, op| op.run(&mut src, dst));
264            let bytes_read = src.pos;
265
266            // eprintln!(
267            //     "Write Hint: {:?}\n src: {:?}\n dst: {:?}",
268            //     hint, src, self.buffer
269            // );
270
271            self.offset = 0;
272            let hint = hint?;
273
274            if hint == 0 {
275                self.finished_frame = true;
276            }
277
278            // As we said, as soon as we've consumed something, return.
279            if bytes_read > 0 || buf.is_empty() {
280                // println!("Returning {}", bytes_read);
281                return Ok(bytes_read);
282            }
283        }
284    }
285
286    fn flush(&mut self) -> io::Result<()> {
287        let mut finished = self.finished;
288        loop {
289            // If the output is blocked or has an error, return now.
290            self.write_from_offset()?;
291
292            if finished {
293                break;
294            }
295
296            let hint = self.with_buffer(|dst, op| op.flush(dst));
297
298            self.offset = 0;
299            let hint = hint?;
300
301            finished = hint == 0;
302        }
303
304        self.panicked = true;
305        let result = self.writer.flush();
306        self.panicked = false;
307        result
308    }
309}
310
311#[cfg(test)]
312mod tests {
313    use super::Writer;
314    use std::io::Write;
315
316    #[test]
317    fn test_noop() {
318        use crate::stream::raw::NoOp;
319
320        let input = b"AbcdefghAbcdefgh.";
321
322        // Test writer
323        let mut output = Vec::new();
324        {
325            let mut writer = Writer::new(&mut output, NoOp);
326            writer.write_all(input).unwrap();
327            writer.finish().unwrap();
328        }
329        assert_eq!(&output, input);
330    }
331
332    #[test]
333    fn test_compress() {
334        use crate::stream::raw::Encoder;
335
336        let input = b"AbcdefghAbcdefgh.";
337
338        // Test writer
339        let mut output = Vec::new();
340        {
341            let mut writer =
342                Writer::new(&mut output, Encoder::new(1).unwrap());
343            writer.write_all(input).unwrap();
344            writer.finish().unwrap();
345        }
346        // println!("Output: {:?}", output);
347        let decoded = crate::decode_all(&output[..]).unwrap();
348        assert_eq!(&decoded, input);
349    }
350
351    #[test]
352    fn test_compress_with_capacity() {
353        use crate::stream::raw::Encoder;
354
355        let input = b"AbcdefghAbcdefgh.";
356
357        // Test writer
358        let mut output = Vec::new();
359        {
360            let mut writer = Writer::new_with_capacity(
361                &mut output,
362                Encoder::new(1).unwrap(),
363                64,
364            );
365            assert_eq!(writer.buffer.capacity(), 64);
366            writer.write_all(input).unwrap();
367            writer.finish().unwrap();
368        }
369        let decoded = crate::decode_all(&output[..]).unwrap();
370        assert_eq!(&decoded, input);
371    }
372
373    #[test]
374    fn test_decompress() {
375        use crate::stream::raw::Decoder;
376
377        let input = b"AbcdefghAbcdefgh.";
378        let compressed = crate::encode_all(&input[..], 1).unwrap();
379
380        // Test writer
381        let mut output = Vec::new();
382        {
383            let mut writer = Writer::new(&mut output, Decoder::new().unwrap());
384            writer.write_all(&compressed).unwrap();
385            writer.finish().unwrap();
386        }
387        // println!("Output: {:?}", output);
388        assert_eq!(&output, input);
389    }
390
391    #[test]
392    fn test_decompress_with_capacity() {
393        use crate::stream::raw::Decoder;
394
395        let input = b"AbcdefghAbcdefgh.";
396        let compressed = crate::encode_all(&input[..], 1).unwrap();
397
398        // Test writer
399        let mut output = Vec::new();
400        {
401            let mut writer = Writer::new_with_capacity(
402                &mut output,
403                Decoder::new().unwrap(),
404                64,
405            );
406            assert_eq!(writer.buffer.capacity(), 64);
407            writer.write_all(&compressed).unwrap();
408            writer.finish().unwrap();
409        }
410        assert_eq!(&output, input);
411    }
412}