Skip to main content

async_compression_issue_150_workaround/codec/bzip2/
encoder.rs

1use crate::{codec::Encode, util::PartialBuffer};
2use std::fmt;
3use std::io::{Error, ErrorKind, Result};
4
5use bzip2::{Action, Compress, Compression, Status};
6
7pub struct BzEncoder {
8    compress: Compress,
9}
10
11impl fmt::Debug for BzEncoder {
12    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13        write!(
14            f,
15            "BzEncoder {{total_in: {}, total_out: {}}}",
16            self.compress.total_in(),
17            self.compress.total_out()
18        )
19    }
20}
21
22impl BzEncoder {
23    /// Creates a new stream prepared for compression.
24    ///
25    /// The `work_factor` parameter controls how the compression phase behaves
26    /// when presented with worst case, highly repetitive, input data. If
27    /// compression runs into difficulties caused by repetitive data, the
28    /// library switches from the standard sorting algorithm to a fallback
29    /// algorithm. The fallback is slower than the standard algorithm by perhaps
30    /// a factor of three, but always behaves reasonably, no matter how bad the
31    /// input.
32    ///
33    /// Lower values of `work_factor` reduce the amount of effort the standard
34    /// algorithm will expend before resorting to the fallback. You should set
35    /// this parameter carefully; too low, and many inputs will be handled by
36    /// the fallback algorithm and so compress rather slowly, too high, and your
37    /// average-to-worst case compression times can become very large. The
38    /// default value of 30 gives reasonable behaviour over a wide range of
39    /// circumstances.
40    ///
41    /// Allowable values range from 0 to 250 inclusive. 0 is a special case,
42    /// equivalent to using the default value of 30.
43    pub(crate) fn new(level: Compression, work_factor: u32) -> Self {
44        Self {
45            compress: Compress::new(level, work_factor),
46        }
47    }
48
49    fn encode(
50        &mut self,
51        input: &mut PartialBuffer<impl AsRef<[u8]>>,
52        output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
53        action: Action,
54    ) -> Result<Status> {
55        let prior_in = self.compress.total_in();
56        let prior_out = self.compress.total_out();
57
58        let status = self
59            .compress
60            .compress(input.unwritten(), output.unwritten_mut(), action)
61            .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
62
63        input.advance((self.compress.total_in() - prior_in) as usize);
64        output.advance((self.compress.total_out() - prior_out) as usize);
65
66        Ok(status)
67    }
68}
69
70impl Encode for BzEncoder {
71    fn encode(
72        &mut self,
73        input: &mut PartialBuffer<impl AsRef<[u8]>>,
74        output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
75    ) -> Result<()> {
76        match self.encode(input, output, Action::Run)? {
77            // Decompression went fine, nothing much to report.
78            Status::Ok => Ok(()),
79
80            // The Flush action on a compression went ok.
81            Status::FlushOk => unreachable!(),
82
83            // The Run action on compression went ok.
84            Status::RunOk => Ok(()),
85
86            // The Finish action on compression went ok.
87            Status::FinishOk => unreachable!(),
88
89            // The stream's end has been met, meaning that no more data can be input.
90            Status::StreamEnd => unreachable!(),
91
92            // There was insufficient memory in the input or output buffer to complete
93            // the request, but otherwise everything went normally.
94            Status::MemNeeded => Err(Error::new(ErrorKind::Other, "out of memory")),
95        }
96    }
97
98    fn flush(
99        &mut self,
100        output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
101    ) -> Result<bool> {
102        match self.encode(&mut PartialBuffer::new(&[][..]), output, Action::Flush)? {
103            // Decompression went fine, nothing much to report.
104            Status::Ok => unreachable!(),
105
106            // The Flush action on a compression went ok.
107            Status::FlushOk => Ok(false),
108
109            // The Run action on compression went ok.
110            Status::RunOk => Ok(true),
111
112            // The Finish action on compression went ok.
113            Status::FinishOk => unreachable!(),
114
115            // The stream's end has been met, meaning that no more data can be input.
116            Status::StreamEnd => unreachable!(),
117
118            // There was insufficient memory in the input or output buffer to complete
119            // the request, but otherwise everything went normally.
120            Status::MemNeeded => Err(Error::new(ErrorKind::Other, "out of memory")),
121        }
122    }
123
124    fn finish(
125        &mut self,
126        output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
127    ) -> Result<bool> {
128        match self.encode(&mut PartialBuffer::new(&[][..]), output, Action::Finish)? {
129            // Decompression went fine, nothing much to report.
130            Status::Ok => Ok(false),
131
132            // The Flush action on a compression went ok.
133            Status::FlushOk => unreachable!(),
134
135            // The Run action on compression went ok.
136            Status::RunOk => unreachable!(),
137
138            // The Finish action on compression went ok.
139            Status::FinishOk => Ok(false),
140
141            // The stream's end has been met, meaning that no more data can be input.
142            Status::StreamEnd => Ok(true),
143
144            // There was insufficient memory in the input or output buffer to complete
145            // the request, but otherwise everything went normally.
146            Status::MemNeeded => Err(Error::new(ErrorKind::Other, "out of memory")),
147        }
148    }
149}