/rust/registry/src/index.crates.io-1949cf8c6b5b557f/bzip2-0.4.4/src/write.rs
Line | Count | Source |
1 | | //! Writer-based compression/decompression streams |
2 | | |
3 | | use std::io; |
4 | | use std::io::prelude::*; |
5 | | |
6 | | #[cfg(feature = "tokio")] |
7 | | use futures::Poll; |
8 | | #[cfg(feature = "tokio")] |
9 | | use tokio_io::{AsyncRead, AsyncWrite}; |
10 | | |
11 | | use {Action, Compress, Compression, Decompress, Status}; |
12 | | |
13 | | /// A compression stream which will have uncompressed data written to it and |
14 | | /// will write compressed data to an output stream. |
15 | | pub struct BzEncoder<W: Write> { |
16 | | data: Compress, |
17 | | obj: Option<W>, |
18 | | buf: Vec<u8>, |
19 | | done: bool, |
20 | | } |
21 | | |
22 | | /// A compression stream which will have compressed data written to it and |
23 | | /// will write uncompressed data to an output stream. |
24 | | pub struct BzDecoder<W: Write> { |
25 | | data: Decompress, |
26 | | obj: Option<W>, |
27 | | buf: Vec<u8>, |
28 | | done: bool, |
29 | | } |
30 | | |
31 | | impl<W: Write> BzEncoder<W> { |
32 | | /// Create a new compression stream which will compress at the given level |
33 | | /// to write compress output to the give output stream. |
34 | 3.66k | pub fn new(obj: W, level: Compression) -> BzEncoder<W> { |
35 | 3.66k | BzEncoder { |
36 | 3.66k | data: Compress::new(level, 30), |
37 | 3.66k | obj: Some(obj), |
38 | 3.66k | buf: Vec::with_capacity(32 * 1024), |
39 | 3.66k | done: false, |
40 | 3.66k | } |
41 | 3.66k | } Unexecuted instantiation: <bzip2::write::BzEncoder<_>>::new <bzip2::write::BzEncoder<zip::write::MaybeEncrypted<std::io::cursor::Cursor<&mut [u8]>>>>::new Line | Count | Source | 34 | 3.66k | pub fn new(obj: W, level: Compression) -> BzEncoder<W> { | 35 | 3.66k | BzEncoder { | 36 | 3.66k | data: Compress::new(level, 30), | 37 | 3.66k | obj: Some(obj), | 38 | 3.66k | buf: Vec::with_capacity(32 * 1024), | 39 | 3.66k | done: false, | 40 | 3.66k | } | 41 | 3.66k | } |
|
42 | | |
43 | 10.9k | fn dump(&mut self) -> io::Result<()> { |
44 | 14.6k | while self.buf.len() > 0 { |
45 | 3.68k | let n = match self.obj.as_mut().unwrap().write(&self.buf) { |
46 | 3.68k | Ok(n) => n, |
47 | 0 | Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue, |
48 | 0 | Err(err) => return Err(err), |
49 | | }; |
50 | 3.68k | self.buf.drain(..n); |
51 | | } |
52 | 10.9k | Ok(()) |
53 | 10.9k | } Unexecuted instantiation: <bzip2::write::BzEncoder<_>>::dump <bzip2::write::BzEncoder<zip::write::MaybeEncrypted<std::io::cursor::Cursor<&mut [u8]>>>>::dump Line | Count | Source | 43 | 10.9k | fn dump(&mut self) -> io::Result<()> { | 44 | 14.6k | while self.buf.len() > 0 { | 45 | 3.68k | let n = match self.obj.as_mut().unwrap().write(&self.buf) { | 46 | 3.68k | Ok(n) => n, | 47 | 0 | Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue, | 48 | 0 | Err(err) => return Err(err), | 49 | | }; | 50 | 3.68k | self.buf.drain(..n); | 51 | | } | 52 | 10.9k | Ok(()) | 53 | 10.9k | } |
|
54 | | |
55 | | /// Acquires a reference to the underlying writer. |
56 | 0 | pub fn get_ref(&self) -> &W { |
57 | 0 | self.obj.as_ref().unwrap() |
58 | 0 | } |
59 | | |
60 | | /// Acquires a mutable reference to the underlying writer. |
61 | | /// |
62 | | /// Note that mutating the output/input state of the stream may corrupt this |
63 | | /// object, so care must be taken when using this method. |
64 | 0 | pub fn get_mut(&mut self) -> &mut W { |
65 | 0 | self.obj.as_mut().unwrap() |
66 | 0 | } |
67 | | |
68 | | /// Attempt to finish this output stream, writing out final chunks of data. |
69 | | /// |
70 | | /// Note that this function can only be used once data has finished being |
71 | | /// written to the output stream. After this function is called then further |
72 | | /// calls to `write` may result in a panic. |
73 | | /// |
74 | | /// # Panics |
75 | | /// |
76 | | /// Attempts to write data to this stream may result in a panic after this |
77 | | /// function is called. |
78 | 3.66k | pub fn try_finish(&mut self) -> io::Result<()> { |
79 | 3.66k | while !self.done { |
80 | 3.66k | self.dump()?; |
81 | 3.66k | let res = self.data.compress_vec(&[], &mut self.buf, Action::Finish); |
82 | 3.66k | if res == Ok(Status::StreamEnd) { |
83 | 3.66k | self.done = true; |
84 | 3.66k | break; |
85 | 0 | } |
86 | | } |
87 | 3.66k | self.dump() |
88 | 3.66k | } Unexecuted instantiation: <bzip2::write::BzEncoder<_>>::try_finish <bzip2::write::BzEncoder<zip::write::MaybeEncrypted<std::io::cursor::Cursor<&mut [u8]>>>>::try_finish Line | Count | Source | 78 | 3.66k | pub fn try_finish(&mut self) -> io::Result<()> { | 79 | 3.66k | while !self.done { | 80 | 3.66k | self.dump()?; | 81 | 3.66k | let res = self.data.compress_vec(&[], &mut self.buf, Action::Finish); | 82 | 3.66k | if res == Ok(Status::StreamEnd) { | 83 | 3.66k | self.done = true; | 84 | 3.66k | break; | 85 | 0 | } | 86 | | } | 87 | 3.66k | self.dump() | 88 | 3.66k | } |
|
89 | | |
90 | | /// Consumes this encoder, flushing the output stream. |
91 | | /// |
92 | | /// This will flush the underlying data stream and then return the contained |
93 | | /// writer if the flush succeeded. |
94 | | /// |
95 | | /// Note that this function may not be suitable to call in a situation where |
96 | | /// the underlying stream is an asynchronous I/O stream. To finish a stream |
97 | | /// the `try_finish` (or `shutdown`) method should be used instead. To |
98 | | /// re-acquire ownership of a stream it is safe to call this method after |
99 | | /// `try_finish` or `shutdown` has returned `Ok`. |
100 | 3.66k | pub fn finish(mut self) -> io::Result<W> { |
101 | 3.66k | self.try_finish()?; |
102 | 3.66k | Ok(self.obj.take().unwrap()) |
103 | 3.66k | } Unexecuted instantiation: <bzip2::write::BzEncoder<_>>::finish <bzip2::write::BzEncoder<zip::write::MaybeEncrypted<std::io::cursor::Cursor<&mut [u8]>>>>::finish Line | Count | Source | 100 | 3.66k | pub fn finish(mut self) -> io::Result<W> { | 101 | 3.66k | self.try_finish()?; | 102 | 3.66k | Ok(self.obj.take().unwrap()) | 103 | 3.66k | } |
|
104 | | |
105 | | /// Returns the number of bytes produced by the compressor |
106 | | /// |
107 | | /// Note that, due to buffering, this only bears any relation to |
108 | | /// `total_in()` after a call to `flush()`. At that point, |
109 | | /// `total_out() / total_in()` is the compression ratio. |
110 | 0 | pub fn total_out(&self) -> u64 { |
111 | 0 | self.data.total_out() |
112 | 0 | } Unexecuted instantiation: <bzip2::write::BzEncoder<_>>::total_out Unexecuted instantiation: <bzip2::write::BzEncoder<zip::write::MaybeEncrypted<std::io::cursor::Cursor<&mut [u8]>>>>::total_out |
113 | | |
114 | | /// Returns the number of bytes consumed by the compressor |
115 | | /// (e.g. the number of bytes written to this stream.) |
116 | 7.32k | pub fn total_in(&self) -> u64 { |
117 | 7.32k | self.data.total_in() |
118 | 7.32k | } Unexecuted instantiation: <bzip2::write::BzEncoder<_>>::total_in <bzip2::write::BzEncoder<zip::write::MaybeEncrypted<std::io::cursor::Cursor<&mut [u8]>>>>::total_in Line | Count | Source | 116 | 7.32k | pub fn total_in(&self) -> u64 { | 117 | 7.32k | self.data.total_in() | 118 | 7.32k | } |
|
119 | | } |
120 | | |
121 | | impl<W: Write> Write for BzEncoder<W> { |
122 | 3.66k | fn write(&mut self, data: &[u8]) -> io::Result<usize> { |
123 | | loop { |
124 | 3.66k | self.dump()?; |
125 | | |
126 | 3.66k | let total_in = self.total_in(); |
127 | 3.66k | self.data |
128 | 3.66k | .compress_vec(data, &mut self.buf, Action::Run) |
129 | 3.66k | .unwrap(); |
130 | 3.66k | let written = (self.total_in() - total_in) as usize; |
131 | | |
132 | 3.66k | if written > 0 || data.len() == 0 { |
133 | 3.66k | return Ok(written); |
134 | 0 | } |
135 | | } |
136 | 3.66k | } Unexecuted instantiation: <bzip2::write::BzEncoder<_> as std::io::Write>::write <bzip2::write::BzEncoder<zip::write::MaybeEncrypted<std::io::cursor::Cursor<&mut [u8]>>> as std::io::Write>::write Line | Count | Source | 122 | 3.66k | fn write(&mut self, data: &[u8]) -> io::Result<usize> { | 123 | | loop { | 124 | 3.66k | self.dump()?; | 125 | | | 126 | 3.66k | let total_in = self.total_in(); | 127 | 3.66k | self.data | 128 | 3.66k | .compress_vec(data, &mut self.buf, Action::Run) | 129 | 3.66k | .unwrap(); | 130 | 3.66k | let written = (self.total_in() - total_in) as usize; | 131 | | | 132 | 3.66k | if written > 0 || data.len() == 0 { | 133 | 3.66k | return Ok(written); | 134 | 0 | } | 135 | | } | 136 | 3.66k | } |
|
137 | | |
138 | 0 | fn flush(&mut self) -> io::Result<()> { |
139 | | loop { |
140 | 0 | self.dump()?; |
141 | 0 | let before = self.total_out(); |
142 | 0 | self.data |
143 | 0 | .compress_vec(&[], &mut self.buf, Action::Flush) |
144 | 0 | .unwrap(); |
145 | | |
146 | 0 | if before == self.total_out() { |
147 | 0 | break; |
148 | 0 | } |
149 | | } |
150 | 0 | self.obj.as_mut().unwrap().flush() |
151 | 0 | } Unexecuted instantiation: <bzip2::write::BzEncoder<_> as std::io::Write>::flush Unexecuted instantiation: <bzip2::write::BzEncoder<zip::write::MaybeEncrypted<std::io::cursor::Cursor<&mut [u8]>>> as std::io::Write>::flush |
152 | | } |
153 | | |
154 | | #[cfg(feature = "tokio")] |
155 | | impl<W: AsyncWrite> AsyncWrite for BzEncoder<W> { |
156 | | fn shutdown(&mut self) -> Poll<(), io::Error> { |
157 | | try_nb!(self.try_finish()); |
158 | | self.get_mut().shutdown() |
159 | | } |
160 | | } |
161 | | |
162 | | impl<W: Read + Write> Read for BzEncoder<W> { |
163 | 0 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
164 | 0 | self.get_mut().read(buf) |
165 | 0 | } |
166 | | } |
167 | | |
168 | | #[cfg(feature = "tokio")] |
169 | | impl<W: AsyncRead + AsyncWrite> AsyncRead for BzEncoder<W> {} |
170 | | |
171 | | impl<W: Write> Drop for BzEncoder<W> { |
172 | 3.66k | fn drop(&mut self) { |
173 | 3.66k | if self.obj.is_some() { |
174 | 0 | let _ = self.try_finish(); |
175 | 3.66k | } |
176 | 3.66k | } Unexecuted instantiation: <bzip2::write::BzEncoder<_> as core::ops::drop::Drop>::drop <bzip2::write::BzEncoder<zip::write::MaybeEncrypted<std::io::cursor::Cursor<&mut [u8]>>> as core::ops::drop::Drop>::drop Line | Count | Source | 172 | 3.66k | fn drop(&mut self) { | 173 | 3.66k | if self.obj.is_some() { | 174 | 0 | let _ = self.try_finish(); | 175 | 3.66k | } | 176 | 3.66k | } |
|
177 | | } |
178 | | |
179 | | impl<W: Write> BzDecoder<W> { |
180 | | /// Create a new decoding stream which will decompress all data written |
181 | | /// to it into `obj`. |
182 | 0 | pub fn new(obj: W) -> BzDecoder<W> { |
183 | 0 | BzDecoder { |
184 | 0 | data: Decompress::new(false), |
185 | 0 | obj: Some(obj), |
186 | 0 | buf: Vec::with_capacity(32 * 1024), |
187 | 0 | done: false, |
188 | 0 | } |
189 | 0 | } |
190 | | |
191 | | /// Acquires a reference to the underlying writer. |
192 | 0 | pub fn get_ref(&self) -> &W { |
193 | 0 | self.obj.as_ref().unwrap() |
194 | 0 | } |
195 | | |
196 | | /// Acquires a mutable reference to the underlying writer. |
197 | | /// |
198 | | /// Note that mutating the output/input state of the stream may corrupt this |
199 | | /// object, so care must be taken when using this method. |
200 | 0 | pub fn get_mut(&mut self) -> &mut W { |
201 | 0 | self.obj.as_mut().unwrap() |
202 | 0 | } |
203 | | |
204 | 0 | fn dump(&mut self) -> io::Result<()> { |
205 | 0 | while self.buf.len() > 0 { |
206 | 0 | let n = match self.obj.as_mut().unwrap().write(&self.buf) { |
207 | 0 | Ok(n) => n, |
208 | 0 | Err(ref err) if err.kind() == io::ErrorKind::Interrupted => continue, |
209 | 0 | Err(err) => return Err(err), |
210 | | }; |
211 | 0 | self.buf.drain(..n); |
212 | | } |
213 | 0 | Ok(()) |
214 | 0 | } |
215 | | |
216 | | /// Attempt to finish this output stream, writing out final chunks of data. |
217 | | /// |
218 | | /// Note that this function can only be used once data has finished being |
219 | | /// written to the output stream. After this function is called then further |
220 | | /// calls to `write` may result in a panic. |
221 | | /// |
222 | | /// # Panics |
223 | | /// |
224 | | /// Attempts to write data to this stream may result in a panic after this |
225 | | /// function is called. |
226 | 0 | pub fn try_finish(&mut self) -> io::Result<()> { |
227 | 0 | while !self.done { |
228 | 0 | self.write(&[])?; |
229 | | } |
230 | 0 | self.dump() |
231 | 0 | } |
232 | | |
233 | | /// Unwrap the underlying writer, finishing the compression stream. |
234 | | /// |
235 | | /// Note that this function may not be suitable to call in a situation where |
236 | | /// the underlying stream is an asynchronous I/O stream. To finish a stream |
237 | | /// the `try_finish` (or `shutdown`) method should be used instead. To |
238 | | /// re-acquire ownership of a stream it is safe to call this method after |
239 | | /// `try_finish` or `shutdown` has returned `Ok`. |
240 | 0 | pub fn finish(&mut self) -> io::Result<W> { |
241 | 0 | self.try_finish()?; |
242 | 0 | Ok(self.obj.take().unwrap()) |
243 | 0 | } |
244 | | |
245 | | /// Returns the number of bytes produced by the decompressor |
246 | | /// |
247 | | /// Note that, due to buffering, this only bears any relation to |
248 | | /// `total_in()` after a call to `flush()`. At that point, |
249 | | /// `total_in() / total_out()` is the compression ratio. |
250 | 0 | pub fn total_out(&self) -> u64 { |
251 | 0 | self.data.total_out() |
252 | 0 | } |
253 | | |
254 | | /// Returns the number of bytes consumed by the decompressor |
255 | | /// (e.g. the number of bytes written to this stream.) |
256 | 0 | pub fn total_in(&self) -> u64 { |
257 | 0 | self.data.total_in() |
258 | 0 | } |
259 | | } |
260 | | |
261 | | impl<W: Write> Write for BzDecoder<W> { |
262 | 0 | fn write(&mut self, data: &[u8]) -> io::Result<usize> { |
263 | 0 | if self.done { |
264 | 0 | return Ok(0); |
265 | 0 | } |
266 | | loop { |
267 | 0 | self.dump()?; |
268 | | |
269 | 0 | let before = self.total_in(); |
270 | 0 | let res = self.data.decompress_vec(data, &mut self.buf); |
271 | 0 | let written = (self.total_in() - before) as usize; |
272 | | |
273 | 0 | let res = res.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; |
274 | | |
275 | 0 | if res == Status::StreamEnd { |
276 | 0 | self.done = true; |
277 | 0 | } |
278 | 0 | if written > 0 || data.len() == 0 || self.done { |
279 | 0 | return Ok(written); |
280 | 0 | } |
281 | | } |
282 | 0 | } |
283 | | |
284 | 0 | fn flush(&mut self) -> io::Result<()> { |
285 | 0 | self.dump()?; |
286 | 0 | self.obj.as_mut().unwrap().flush() |
287 | 0 | } |
288 | | } |
289 | | |
290 | | #[cfg(feature = "tokio")] |
291 | | impl<W: AsyncWrite> AsyncWrite for BzDecoder<W> { |
292 | | fn shutdown(&mut self) -> Poll<(), io::Error> { |
293 | | try_nb!(self.try_finish()); |
294 | | self.get_mut().shutdown() |
295 | | } |
296 | | } |
297 | | |
298 | | impl<W: Read + Write> Read for BzDecoder<W> { |
299 | 0 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
300 | 0 | self.get_mut().read(buf) |
301 | 0 | } |
302 | | } |
303 | | |
304 | | #[cfg(feature = "tokio")] |
305 | | impl<W: AsyncRead + AsyncWrite> AsyncRead for BzDecoder<W> {} |
306 | | |
307 | | impl<W: Write> Drop for BzDecoder<W> { |
308 | 0 | fn drop(&mut self) { |
309 | 0 | if self.obj.is_some() { |
310 | 0 | let _ = self.try_finish(); |
311 | 0 | } |
312 | 0 | } |
313 | | } |
314 | | |
315 | | #[cfg(test)] |
316 | | mod tests { |
317 | | use super::{BzDecoder, BzEncoder}; |
318 | | use partial_io::{GenInterrupted, PartialWithErrors, PartialWrite}; |
319 | | use std::io::prelude::*; |
320 | | use std::iter::repeat; |
321 | | |
322 | | #[test] |
323 | | fn smoke() { |
324 | | let d = BzDecoder::new(Vec::new()); |
325 | | let mut c = BzEncoder::new(d, ::Compression::default()); |
326 | | c.write_all(b"12834").unwrap(); |
327 | | let s = repeat("12345").take(100000).collect::<String>(); |
328 | | c.write_all(s.as_bytes()).unwrap(); |
329 | | let data = c.finish().unwrap().finish().unwrap(); |
330 | | assert_eq!(&data[0..5], b"12834"); |
331 | | assert_eq!(data.len(), 500005); |
332 | | assert!(format!("12834{}", s).as_bytes() == &*data); |
333 | | } |
334 | | |
335 | | #[test] |
336 | | fn write_empty() { |
337 | | let d = BzDecoder::new(Vec::new()); |
338 | | let mut c = BzEncoder::new(d, ::Compression::default()); |
339 | | c.write(b"").unwrap(); |
340 | | let data = c.finish().unwrap().finish().unwrap(); |
341 | | assert_eq!(&data[..], b""); |
342 | | } |
343 | | |
344 | | #[test] |
345 | | fn qc() { |
346 | | ::quickcheck::quickcheck(test as fn(_) -> _); |
347 | | |
348 | | fn test(v: Vec<u8>) -> bool { |
349 | | let w = BzDecoder::new(Vec::new()); |
350 | | let mut w = BzEncoder::new(w, ::Compression::default()); |
351 | | w.write_all(&v).unwrap(); |
352 | | v == w.finish().unwrap().finish().unwrap() |
353 | | } |
354 | | } |
355 | | |
356 | | #[test] |
357 | | fn qc_partial() { |
358 | | quickcheck6::quickcheck(test as fn(_, _, _) -> _); |
359 | | |
360 | | fn test( |
361 | | v: Vec<u8>, |
362 | | encode_ops: PartialWithErrors<GenInterrupted>, |
363 | | decode_ops: PartialWithErrors<GenInterrupted>, |
364 | | ) -> bool { |
365 | | let w = BzDecoder::new(PartialWrite::new(Vec::new(), decode_ops)); |
366 | | let mut w = BzEncoder::new(PartialWrite::new(w, encode_ops), ::Compression::default()); |
367 | | w.write_all(&v).unwrap(); |
368 | | v == w |
369 | | .finish() |
370 | | .unwrap() |
371 | | .into_inner() |
372 | | .finish() |
373 | | .unwrap() |
374 | | .into_inner() |
375 | | } |
376 | | } |
377 | | } |