compression_codecs/xz2/
encoder.rs1use compression_core::{
2 util::{PartialBuffer, WriteBuffer},
3 Level,
4};
5use liblzma::stream::{Action, Check, Stream};
6use std::{
7 convert::{TryFrom, TryInto},
8 fmt, io,
9};
10
11use crate::{
12 lzma::params::{LzmaEncoderParams, LzmaOptions},
13 xz2::process_stream,
14 EncodeV2, Xz2FileFormat,
15};
16
17pub struct Xz2Encoder {
19 stream: Stream,
20 params: LzmaEncoderParams,
21}
22
23impl fmt::Debug for Xz2Encoder {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 f.debug_struct("Xz2Encoder").finish_non_exhaustive()
26 }
27}
28
29impl TryFrom<LzmaEncoderParams> for Xz2Encoder {
30 type Error = liblzma::stream::Error;
31
32 fn try_from(params: LzmaEncoderParams) -> Result<Self, Self::Error> {
33 let stream = Stream::try_from(¶ms)?;
34 Ok(Self {
35 stream,
36 params: params.clone(),
37 })
38 }
39}
40
41fn xz2_level(level: Level) -> u32 {
42 match level {
43 Level::Fastest => 0,
44 Level::Best => 9,
45 Level::Precise(quality) => quality.try_into().unwrap_or(0).clamp(0, 9),
46 _ => 5,
47 }
48}
49
50impl Xz2Encoder {
51 pub fn new(format: Xz2FileFormat, level: Level) -> Self {
52 let preset = xz2_level(level);
53 let params = match format {
54 Xz2FileFormat::Xz => LzmaEncoderParams::Easy {
55 preset,
56 check: Check::Crc64,
57 },
58 Xz2FileFormat::Lzma => {
59 let options = LzmaOptions::default().preset(preset);
60 LzmaEncoderParams::Lzma { options }
61 }
62 };
63
64 Self::try_from(params).unwrap()
65 }
66
67 #[cfg(feature = "xz-parallel")]
68 pub fn xz_parallel(level: Level, threads: std::num::NonZeroU32) -> Self {
69 use crate::lzma::params::MtStreamBuilder;
70
71 let preset = xz2_level(level);
72 let mut builder = MtStreamBuilder::default();
73 builder
74 .threads(threads)
75 .timeout_ms(300)
76 .preset(preset)
77 .check(Check::Crc64);
78 let params = LzmaEncoderParams::MultiThread { builder };
79 Self::try_from(params).unwrap()
80 }
81}
82
83impl EncodeV2 for Xz2Encoder {
84 fn encode(
85 &mut self,
86 input: &mut PartialBuffer<&[u8]>,
87 output: &mut WriteBuffer<'_>,
88 ) -> io::Result<()> {
89 process_stream(&mut self.stream, input, output, Action::Run).map(|_| ())
90 }
91
92 fn flush(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool> {
93 let action = match &self.params {
94 #[cfg(feature = "xz-parallel")]
96 LzmaEncoderParams::MultiThread { builder: _ } => Action::FullFlush,
97 _ => Action::SyncFlush,
98 };
99
100 process_stream(
101 &mut self.stream,
102 &mut PartialBuffer::new(&[]),
103 output,
104 action,
105 )
106 }
107
108 fn finish(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool> {
109 process_stream(
110 &mut self.stream,
111 &mut PartialBuffer::new(&[]),
112 output,
113 Action::Finish,
114 )
115 }
116}