compression_codecs/lzma/
params.rs

1//! Clone-able structs to build the non-clone-ables in liblzma
2
3use std::convert::TryFrom;
4#[cfg(feature = "xz-parallel")]
5use std::num::NonZeroU32;
6
7/// Used to control how the LZMA stream is created.
8#[derive(Debug, Clone)]
9pub enum LzmaEncoderParams {
10    Easy {
11        preset: u32,
12        check: liblzma::stream::Check,
13    },
14    Lzma {
15        options: LzmaOptions,
16    },
17    Raw {
18        filters: LzmaFilters,
19    },
20    Stream {
21        filters: LzmaFilters,
22        check: liblzma::stream::Check,
23    },
24
25    #[cfg(feature = "xz-parallel")]
26    MultiThread {
27        builder: MtStreamBuilder,
28    },
29}
30
31impl TryFrom<&LzmaEncoderParams> for liblzma::stream::Stream {
32    type Error = liblzma::stream::Error;
33
34    fn try_from(value: &LzmaEncoderParams) -> Result<Self, Self::Error> {
35        let stream = match value {
36            LzmaEncoderParams::Easy { preset, check } => Self::new_easy_encoder(*preset, *check)?,
37            LzmaEncoderParams::Lzma { options } => {
38                let options = liblzma::stream::LzmaOptions::try_from(options)?;
39                Self::new_lzma_encoder(&options)?
40            }
41            LzmaEncoderParams::Raw { filters } => {
42                let filters = liblzma::stream::Filters::try_from(filters)?;
43                Self::new_raw_encoder(&filters)?
44            }
45            LzmaEncoderParams::Stream { filters, check } => {
46                let filters = liblzma::stream::Filters::try_from(filters)?;
47                Self::new_stream_encoder(&filters, *check)?
48            }
49
50            #[cfg(feature = "xz-parallel")]
51            LzmaEncoderParams::MultiThread { builder } => {
52                let builder = liblzma::stream::MtStreamBuilder::try_from(builder)?;
53                builder.encoder()?
54            }
55        };
56
57        Ok(stream)
58    }
59}
60
61/// Directly translate to how the stream is constructed
62#[derive(Clone, Debug)]
63pub enum LzmaDecoderParams {
64    Auto {
65        mem_limit: u64,
66        flags: u32,
67    },
68    Lzip {
69        mem_limit: u64,
70        flags: u32,
71    },
72    Lzma {
73        mem_limit: u64,
74    },
75    Raw {
76        filters: LzmaFilters,
77    },
78    Stream {
79        mem_limit: u64,
80        flags: u32,
81    },
82
83    #[cfg(feature = "xz-parallel")]
84    MultiThread {
85        builder: MtStreamBuilder,
86    },
87}
88
89impl TryFrom<&LzmaDecoderParams> for liblzma::stream::Stream {
90    type Error = liblzma::stream::Error;
91
92    fn try_from(value: &LzmaDecoderParams) -> Result<Self, Self::Error> {
93        let stream = match value {
94            LzmaDecoderParams::Auto { mem_limit, flags } => {
95                Self::new_auto_decoder(*mem_limit, *flags)?
96            }
97            LzmaDecoderParams::Lzip { mem_limit, flags } => {
98                Self::new_lzip_decoder(*mem_limit, *flags)?
99            }
100            LzmaDecoderParams::Lzma { mem_limit } => Self::new_lzma_decoder(*mem_limit)?,
101            LzmaDecoderParams::Stream { mem_limit, flags } => {
102                Self::new_stream_decoder(*mem_limit, *flags)?
103            }
104            LzmaDecoderParams::Raw { filters } => {
105                let filters = liblzma::stream::Filters::try_from(filters)?;
106                Self::new_raw_decoder(&filters)?
107            }
108            #[cfg(feature = "xz-parallel")]
109            LzmaDecoderParams::MultiThread { builder } => {
110                let builder = liblzma::stream::MtStreamBuilder::try_from(builder)?;
111                builder.decoder()?
112            }
113        };
114
115        Ok(stream)
116    }
117}
118
119/// Clone-able `liblzma::Filters`.
120#[derive(Default, Clone, Debug)]
121pub struct LzmaFilters {
122    filters: Vec<LzmaFilter>,
123}
124
125impl LzmaFilters {
126    /// Add `LzmaFilter` to the collection
127    pub fn add_filter(mut self, filter: LzmaFilter) -> Self {
128        self.filters.push(filter);
129        self
130    }
131}
132
133/// An individual filter directly corresponding to liblzma Filters method calls
134#[derive(Debug, Clone)]
135pub enum LzmaFilter {
136    Arm(Option<Vec<u8>>),
137    Arm64(Option<Vec<u8>>),
138    ArmThumb(Option<Vec<u8>>),
139    Delta(Option<Vec<u8>>),
140    Ia64(Option<Vec<u8>>),
141    Lzma1(LzmaOptions),
142    Lzma1Properties(Vec<u8>),
143    Lzma2(LzmaOptions),
144    Lzma2Properties(Vec<u8>),
145    PowerPc(Option<Vec<u8>>),
146    Sparc(Option<Vec<u8>>),
147    X86(Option<Vec<u8>>),
148}
149
150impl TryFrom<&LzmaFilters> for liblzma::stream::Filters {
151    type Error = liblzma::stream::Error;
152
153    fn try_from(value: &LzmaFilters) -> Result<Self, Self::Error> {
154        let mut filters = liblzma::stream::Filters::new();
155        for f in value.filters.iter() {
156            match f {
157                LzmaFilter::Arm(Some(p)) => filters.arm_properties(p)?,
158                LzmaFilter::Arm(None) => filters.arm(),
159                LzmaFilter::Arm64(Some(p)) => filters.arm64_properties(p)?,
160                LzmaFilter::Arm64(None) => filters.arm64(),
161                LzmaFilter::ArmThumb(Some(p)) => filters.arm_thumb_properties(p)?,
162                LzmaFilter::ArmThumb(None) => filters.arm_thumb(),
163                LzmaFilter::Delta(Some(p)) => filters.delta_properties(p)?,
164                LzmaFilter::Delta(None) => filters.delta(),
165                LzmaFilter::Ia64(Some(p)) => filters.ia64_properties(p)?,
166                LzmaFilter::Ia64(None) => filters.ia64(),
167                LzmaFilter::Lzma1(opts) => {
168                    let opts = liblzma::stream::LzmaOptions::try_from(opts)?;
169                    filters.lzma1(&opts)
170                }
171                LzmaFilter::Lzma1Properties(p) => filters.lzma1_properties(p)?,
172                LzmaFilter::Lzma2(opts) => {
173                    let opts = liblzma::stream::LzmaOptions::try_from(opts)?;
174                    filters.lzma2(&opts)
175                }
176                LzmaFilter::Lzma2Properties(p) => filters.lzma2_properties(p)?,
177                LzmaFilter::PowerPc(Some(p)) => filters.powerpc_properties(p)?,
178                LzmaFilter::PowerPc(None) => filters.powerpc(),
179                LzmaFilter::Sparc(Some(p)) => filters.sparc_properties(p)?,
180                LzmaFilter::Sparc(None) => filters.sparc(),
181                LzmaFilter::X86(Some(p)) => filters.x86_properties(p)?,
182                LzmaFilter::X86(None) => filters.x86(),
183            };
184        }
185
186        Ok(filters)
187    }
188}
189
190/// A builder for liblzma::LzmaOptions, so that it can be cloned
191#[derive(Default, Clone)]
192pub struct LzmaOptions {
193    preset: Option<u32>,
194    depth: Option<u32>,
195    dict_size: Option<u32>,
196    literal_context_bits: Option<u32>,
197    literal_position_bits: Option<u32>,
198    match_finder: Option<liblzma::stream::MatchFinder>,
199    mode: Option<liblzma::stream::Mode>,
200    nice_len: Option<u32>,
201    position_bits: Option<u32>,
202}
203
204impl std::fmt::Debug for LzmaOptions {
205    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206        let match_finder = self.match_finder.map(|m| match m {
207            liblzma::stream::MatchFinder::HashChain3 => "HashChain3",
208            liblzma::stream::MatchFinder::HashChain4 => "HashChain4",
209            liblzma::stream::MatchFinder::BinaryTree2 => "BTree2",
210            liblzma::stream::MatchFinder::BinaryTree3 => "BTree3",
211            liblzma::stream::MatchFinder::BinaryTree4 => "BTree4",
212        });
213
214        let mode = self.mode.map(|m| match m {
215            liblzma::stream::Mode::Fast => "Fast",
216            liblzma::stream::Mode::Normal => "Normal",
217        });
218
219        f.debug_struct("LzmaOptions")
220            .field("preset", &self.preset)
221            .field("depth", &self.depth)
222            .field("dict_size", &self.dict_size)
223            .field("literal_context_bits", &self.literal_context_bits)
224            .field("literal_position_bits", &self.literal_position_bits)
225            .field("match_finder", &match_finder)
226            .field("mode", &mode)
227            .field("nice_len", &self.nice_len)
228            .field("position_bits", &self.position_bits)
229            .finish()
230    }
231}
232
233impl LzmaOptions {
234    pub fn preset(mut self, value: u32) -> Self {
235        self.preset = Some(value);
236        self
237    }
238    pub fn depth(mut self, value: u32) -> Self {
239        self.depth = Some(value);
240        self
241    }
242    pub fn dict_size(mut self, value: u32) -> Self {
243        self.dict_size = Some(value);
244        self
245    }
246    pub fn literal_context_bits(mut self, value: u32) -> Self {
247        self.literal_context_bits = Some(value);
248        self
249    }
250    pub fn literal_position_bits(mut self, value: u32) -> Self {
251        self.literal_position_bits = Some(value);
252        self
253    }
254    pub fn match_finder(mut self, value: liblzma::stream::MatchFinder) -> Self {
255        self.match_finder = Some(value);
256        self
257    }
258    pub fn mode(mut self, value: liblzma::stream::Mode) -> Self {
259        self.mode = Some(value);
260        self
261    }
262    pub fn nice_len(mut self, value: u32) -> Self {
263        self.nice_len = Some(value);
264        self
265    }
266    pub fn position_bits(mut self, value: u32) -> Self {
267        self.position_bits = Some(value);
268        self
269    }
270}
271
272impl TryFrom<&LzmaOptions> for liblzma::stream::LzmaOptions {
273    type Error = liblzma::stream::Error;
274
275    fn try_from(value: &LzmaOptions) -> Result<Self, Self::Error> {
276        let mut s = match value.preset {
277            Some(preset) => liblzma::stream::LzmaOptions::new_preset(preset)?,
278            None => liblzma::stream::LzmaOptions::new(),
279        };
280        if let Some(depth) = value.depth {
281            s.depth(depth);
282        }
283        if let Some(dict_size) = value.dict_size {
284            s.dict_size(dict_size);
285        }
286        if let Some(bits) = value.literal_context_bits {
287            s.literal_context_bits(bits);
288        }
289        if let Some(bits) = value.literal_position_bits {
290            s.literal_position_bits(bits);
291        }
292        if let Some(mf) = value.match_finder {
293            s.match_finder(mf);
294        }
295        if let Some(mode) = value.mode {
296            s.mode(mode);
297        }
298        if let Some(len) = value.nice_len {
299            s.nice_len(len);
300        }
301
302        if let Some(bits) = value.position_bits {
303            s.position_bits(bits);
304        }
305
306        Ok(s)
307    }
308}
309
310#[cfg(feature = "xz-parallel")]
311#[derive(Default, Clone)]
312/// Used to build a clonable mt stream builder
313pub struct MtStreamBuilder {
314    block_size: Option<u64>,
315    preset: Option<u32>,
316    check: Option<liblzma::stream::Check>,
317    filters: Option<LzmaFilters>,
318    mem_limit_stop: Option<u64>,
319    mem_limit_threading: Option<u64>,
320    threads: Option<NonZeroU32>,
321    timeout_ms: Option<u32>,
322}
323
324#[cfg(feature = "xz-parallel")]
325impl std::fmt::Debug for MtStreamBuilder {
326    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
327        let check = self.check.map(|s| match s {
328            liblzma::stream::Check::None => "None",
329            liblzma::stream::Check::Crc32 => "Crc32",
330            liblzma::stream::Check::Crc64 => "Crc64",
331            liblzma::stream::Check::Sha256 => "Sha256",
332        });
333        f.debug_struct("MtStreamBuilder")
334            .field("block_size", &self.block_size)
335            .field("preset", &self.preset)
336            .field("check", &check)
337            .field("filters", &self.filters)
338            .field("mem_limit_stop", &self.mem_limit_stop)
339            .field("mem_limit_threading", &self.mem_limit_threading)
340            .field("threads", &self.threads)
341            .field("timeout_ms", &self.timeout_ms)
342            .finish()
343    }
344}
345
346#[cfg(feature = "xz-parallel")]
347impl MtStreamBuilder {
348    pub fn block_size(&mut self, block_size: u64) -> &mut Self {
349        self.block_size = Some(block_size);
350        self
351    }
352    pub fn preset(&mut self, preset: u32) -> &mut Self {
353        self.preset = Some(preset);
354        self
355    }
356    pub fn check(&mut self, check: liblzma::stream::Check) -> &mut Self {
357        self.check = Some(check);
358        self
359    }
360
361    pub fn filters(&mut self, filters: LzmaFilters) -> &mut Self {
362        self.filters = Some(filters);
363        self
364    }
365    pub fn mem_limit_stop(&mut self, mem_limit_stop: u64) -> &mut Self {
366        self.mem_limit_stop = Some(mem_limit_stop);
367        self
368    }
369    pub fn mem_limit_threading(&mut self, mem_limit_threading: u64) -> &mut Self {
370        self.mem_limit_threading = Some(mem_limit_threading);
371        self
372    }
373    pub fn threads(&mut self, threads: NonZeroU32) -> &mut Self {
374        self.threads = Some(threads);
375        self
376    }
377    pub fn timeout_ms(&mut self, timeout_ms: u32) -> &mut Self {
378        self.timeout_ms = Some(timeout_ms);
379        self
380    }
381}
382
383#[cfg(feature = "xz-parallel")]
384impl TryFrom<&MtStreamBuilder> for liblzma::stream::MtStreamBuilder {
385    type Error = liblzma::stream::Error;
386
387    fn try_from(value: &MtStreamBuilder) -> Result<Self, Self::Error> {
388        let mut mt = liblzma::stream::MtStreamBuilder::new();
389        if let Some(block_size) = value.block_size {
390            mt.block_size(block_size);
391        }
392        if let Some(preset) = value.preset {
393            mt.preset(preset);
394        }
395        if let Some(check) = value.check {
396            mt.check(check);
397        }
398        if let Some(filters) = &value.filters {
399            let filters = liblzma::stream::Filters::try_from(filters)?;
400            mt.filters(filters);
401        }
402        if let Some(memlimit) = value.mem_limit_stop {
403            mt.memlimit_stop(memlimit);
404        }
405        if let Some(memlimit) = value.mem_limit_threading {
406            mt.memlimit_threading(memlimit);
407        }
408        if let Some(threads) = value.threads {
409            mt.threads(threads.get());
410        }
411        if let Some(timeout) = value.timeout_ms {
412            mt.timeout_ms(timeout);
413        }
414        Ok(mt)
415    }
416}