async_compression/codec/bzip2/
encoder.rs

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