Skip to main content

zstd/stream/zio/
reader.rs

1use std::io::{self, BufRead, Read};
2
3use crate::stream::raw::{InBuffer, Operation, OutBuffer};
4
5// [ reader -> zstd ] -> output
6/// Implements the [`Read`] API around an [`Operation`].
7///
8/// This can be used to wrap a raw in-memory operation in a read-focused API.
9///
10/// It can wrap either a compression or decompression operation, and pulls
11/// input data from a wrapped `Read`.
12pub struct Reader<R, D> {
13    reader: R,
14    operation: D,
15
16    state: State,
17
18    single_frame: bool,
19    finished_frame: bool,
20}
21
22enum State {
23    // Still actively reading from the inner `Read`
24    Reading,
25    // We reached EOF from the inner `Read`, now flushing.
26    PastEof,
27    // We are fully done, nothing can be read.
28    Finished,
29}
30
31impl<R, D> Reader<R, D> {
32    /// Creates a new `Reader`.
33    ///
34    /// `reader` will be used to pull input data for the given operation.
35    pub fn new(reader: R, operation: D) -> Self {
36        Reader {
37            reader,
38            operation,
39            state: State::Reading,
40            single_frame: false,
41            finished_frame: false,
42        }
43    }
44
45    /// Sets `self` to stop after the first decoded frame.
46    pub fn set_single_frame(&mut self) {
47        self.single_frame = true;
48    }
49
50    /// Returns a mutable reference to the underlying operation.
51    pub fn operation_mut(&mut self) -> &mut D {
52        &mut self.operation
53    }
54
55    /// Returns a mutable reference to the underlying reader.
56    pub fn reader_mut(&mut self) -> &mut R {
57        &mut self.reader
58    }
59
60    /// Returns a reference to the underlying reader.
61    pub fn reader(&self) -> &R {
62        &self.reader
63    }
64
65    /// Returns the inner reader.
66    pub fn into_inner(self) -> R {
67        self.reader
68    }
69
70    /// Flush any internal buffer.
71    ///
72    /// For encoders, this ensures all input consumed so far is compressed.
73    pub fn flush(&mut self, output: &mut [u8]) -> io::Result<usize>
74    where
75        D: Operation,
76    {
77        self.operation.flush(&mut OutBuffer::around(output))
78    }
79}
80
81impl<R, D> Reader<R, D>
82where
83    R: BufRead,
84    D: Operation,
85{
86    /// Consume the rest of the current frame from the underlying reader.
87    ///
88    /// Once all the decoded data has been read, zstd may still not have
89    /// consumed the tail of the frame: it can produce the last of the output
90    /// before reading the frame epilogue. The underlying reader is then left
91    /// pointing somewhere inside the frame rather than just after it.
92    ///
93    /// This feeds zstd the input it still needs, with no room for output, so
94    /// the reader ends up positioned exactly at the end of the frame.
95    ///
96    /// It stops there: it will not start decoding whatever follows, so a
97    /// stream of concatenated frames keeps its remaining frames, and trailing
98    /// non-zstd data is left untouched.
99    ///
100    /// This is a no-op if the current frame is already complete, so it will
101    /// not read from the underlying reader in that case.
102    pub fn finish_frame(&mut self) -> io::Result<()> {
103        // Only pull on the reader if zstd is actually waiting for the rest of
104        // a frame. Otherwise this could block on a stream - a socket, say -
105        // that has nothing more to give.
106        if self.finished_frame || !matches!(self.state, State::Reading) {
107            return Ok(());
108        }
109
110        loop {
111            let bytes_read = {
112                let input = fill_buf(&mut self.reader)?;
113                if input.is_empty() {
114                    return Ok(());
115                }
116
117                let mut src = InBuffer::around(input);
118                // No output space: zstd will only consume the input backing
119                // the output it has already handed us, and stops at the end of
120                // the frame rather than starting the next one.
121                let mut dst = OutBuffer::around(&mut [][..]);
122
123                let hint = self.operation.run(&mut src, &mut dst)?;
124                if hint == 0 {
125                    self.finished_frame = true;
126                }
127
128                src.pos()
129            };
130
131            self.reader.consume(bytes_read);
132
133            // Either we reached the end of the frame, or we cannot make any
134            // more progress without somewhere to put the output.
135            if self.finished_frame || bytes_read == 0 {
136                return Ok(());
137            }
138        }
139    }
140}
141// Read and retry on Interrupted errors.
142fn fill_buf<R>(reader: &mut R) -> io::Result<&[u8]>
143where
144    R: BufRead,
145{
146    // This doesn't work right now because of the borrow-checker.
147    // When it can be made to compile, it would allow Reader to automatically
148    // retry on `Interrupted` error.
149    /*
150    loop {
151        match reader.fill_buf() {
152            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
153            otherwise => return otherwise,
154        }
155    }
156    */
157
158    // Workaround for now
159    let res = reader.fill_buf()?;
160
161    // eprintln!("Filled buffer: {:?}", res);
162
163    Ok(res)
164}
165
166impl<R, D> Read for Reader<R, D>
167where
168    R: BufRead,
169    D: Operation,
170{
171    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
172        // `Read::read` is specified to return `Ok(0)` for an empty buffer.
173        // Without this, the loop below would keep asking the operation to write
174        // into no space at all, until zstd gives up with a "no progress" error.
175        if buf.is_empty() {
176            return Ok(0);
177        }
178
179        // Keep trying until _something_ has been written.
180        let mut first = true;
181        loop {
182            match self.state {
183                State::Reading => {
184                    let (bytes_read, bytes_written) = {
185                        // Start with a fresh pool of un-processed data.
186                        // This is the only line that can return an interruption error.
187                        let input = if first {
188                            // eprintln!("First run, no input coming.");
189                            b""
190                        } else {
191                            fill_buf(&mut self.reader)?
192                        };
193
194                        // eprintln!("Input = {:?}", input);
195
196                        // It's possible we don't have any new data to read.
197                        // (In this case we may still have zstd's own buffer to clear.)
198                        if !first && input.is_empty() {
199                            self.state = State::PastEof;
200                            continue;
201                        }
202                        first = false;
203
204                        let mut src = InBuffer::around(input);
205                        let mut dst = OutBuffer::around(buf);
206
207                        // We don't want empty input (from first=true) to cause a frame
208                        // re-initialization.
209                        if self.finished_frame && !input.is_empty() {
210                            // eprintln!("!! Reigniting !!");
211                            self.operation.reinit()?;
212                            self.finished_frame = false;
213                        }
214
215                        // Phase 1: feed input to the operation
216                        let hint = self.operation.run(&mut src, &mut dst)?;
217                        // eprintln!(
218                        //     "Hint={} Just run our operation:\n In={:?}\n Out={:?}",
219                        //     hint, src, dst
220                        // );
221
222                        if hint == 0 {
223                            // In practice this only happens when decoding, when we just finished
224                            // reading a frame.
225                            self.finished_frame = true;
226                            if self.single_frame {
227                                self.state = State::Finished;
228                            }
229                        }
230
231                        // eprintln!("Output: {:?}", dst);
232
233                        (src.pos(), dst.pos())
234                    };
235
236                    self.reader.consume(bytes_read);
237
238                    if bytes_written > 0 {
239                        return Ok(bytes_written);
240                    }
241
242                    // We need more data! Try again!
243                }
244                State::PastEof => {
245                    let mut dst = OutBuffer::around(buf);
246
247                    // We already sent all the input we could get to zstd. Time to flush out the
248                    // buffer and be done with it.
249
250                    // Phase 2: flush out the operation's buffer
251                    // Keep calling `finish()` until the buffer is empty.
252                    let hint = self
253                        .operation
254                        .finish(&mut dst, self.finished_frame)?;
255                    // eprintln!("Hint: {} ; Output: {:?}", hint, dst);
256                    if hint == 0 {
257                        // This indicates that the footer is complete.
258                        // This is the only way to terminate the stream cleanly.
259                        self.state = State::Finished;
260                    }
261
262                    return Ok(dst.pos());
263                }
264                State::Finished => {
265                    return Ok(0);
266                }
267            }
268        }
269    }
270}
271
272#[cfg(test)]
273mod tests {
274    use super::Reader;
275    use std::io::{Cursor, Read};
276
277    #[test]
278    fn test_noop() {
279        use crate::stream::raw::NoOp;
280
281        let input = b"AbcdefghAbcdefgh.";
282
283        // Test reader
284        let mut output = Vec::new();
285        {
286            let mut reader = Reader::new(Cursor::new(input), NoOp);
287            reader.read_to_end(&mut output).unwrap();
288        }
289        assert_eq!(&output, input);
290    }
291
292    #[test]
293    fn test_compress() {
294        use crate::stream::raw::Encoder;
295
296        let input = b"AbcdefghAbcdefgh.";
297
298        // Test reader
299        let mut output = Vec::new();
300        {
301            let mut reader =
302                Reader::new(Cursor::new(input), Encoder::new(1).unwrap());
303            reader.read_to_end(&mut output).unwrap();
304        }
305        // eprintln!("{:?}", output);
306        let decoded = crate::decode_all(&output[..]).unwrap();
307        assert_eq!(&decoded, input);
308    }
309}