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}