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}