exarch_core/creation/compression.rs
1//! Compression level conversion utilities.
2//!
3//! This module provides unified conversion from the user-friendly compression
4//! level scale (1-9) to codec-specific compression level types.
5//!
6//! # Level Mapping
7//!
8//! User levels follow a consistent scale:
9//!
10//! - **1-3**: Fast compression (lower CPU usage, larger files)
11//! - **6**: Default compression (balanced)
12//! - **7-9**: Best compression (higher CPU usage, smaller files)
13//!
14//! Each codec maps these levels to its own internal scale.
15
16/// Converts user compression level (1-9) to flate2 compression level.
17///
18/// # Mapping
19///
20/// - `None` or `Some(6)`: Default compression
21/// - `1-3`: Fast compression
22/// - `7-9`: Best compression
23/// - Other values: Literal level (clamped to valid range)
24///
25/// # Examples
26///
27/// ```ignore
28/// use exarch_core::creation::compression::compression_level_to_flate2;
29///
30/// let default_level = compression_level_to_flate2(None);
31/// let fast_level = compression_level_to_flate2(Some(1));
32/// let best_level = compression_level_to_flate2(Some(9));
33/// ```
34#[must_use]
35pub fn compression_level_to_flate2(level: Option<u8>) -> flate2::Compression {
36 match level {
37 None | Some(6) => flate2::Compression::default(),
38 Some(1..=3) => flate2::Compression::fast(),
39 Some(7..=9) => flate2::Compression::best(),
40 Some(n) => flate2::Compression::new(u32::from(n)),
41 }
42}
43
44/// Converts user compression level (1-9) to bzip2 compression level.
45///
46/// # Mapping
47///
48/// - `None` or `Some(6)`: Default compression
49/// - `1`: Fast compression
50/// - `2-6`: Literal level
51/// - `7-9`: Best compression
52///
53/// # Examples
54///
55/// ```ignore
56/// use exarch_core::creation::compression::compression_level_to_bzip2;
57///
58/// let default_level = compression_level_to_bzip2(None);
59/// let fast_level = compression_level_to_bzip2(Some(1));
60/// let best_level = compression_level_to_bzip2(Some(9));
61/// ```
62#[must_use]
63pub fn compression_level_to_bzip2(level: Option<u8>) -> bzip2::Compression {
64 match level {
65 None | Some(6) => bzip2::Compression::default(),
66 Some(1) => bzip2::Compression::fast(),
67 Some(7..=9) => bzip2::Compression::best(),
68 Some(n @ 2..=6) => bzip2::Compression::new(u32::from(n)),
69 Some(n) => bzip2::Compression::new(u32::from(n.min(9))),
70 }
71}
72
73/// Converts user compression level (1-9) to xz compression level.
74///
75/// # Mapping
76///
77/// - `None` or `Some(6)`: Level 6 (default)
78/// - Other values: Literal level (0-9 range supported by xz)
79///
80/// # Examples
81///
82/// ```ignore
83/// use exarch_core::creation::compression::compression_level_to_xz;
84///
85/// let default_level = compression_level_to_xz(None);
86/// let fast_level = compression_level_to_xz(Some(1));
87/// let best_level = compression_level_to_xz(Some(9));
88/// ```
89#[must_use]
90pub fn compression_level_to_xz(level: Option<u8>) -> u32 {
91 match level {
92 None | Some(6) => 6,
93 Some(n) => u32::from(n),
94 }
95}
96
97/// Converts user compression level (1-9) to zstd compression level.
98///
99/// # Mapping
100///
101/// Zstd has a wider range (1-22) than our user scale (1-9).
102/// We map user levels to strategic zstd levels:
103///
104/// - `None` or `Some(6)`: Level 3 (default, fast with good compression)
105/// - `1`: Level 1 (fastest)
106/// - `2`: Level 2 (fast)
107/// - `7`: Level 10 (good compression)
108/// - `8`: Level 15 (better compression)
109/// - `9`: Level 19 (best compression)
110/// - Other values: Level 3 (default)
111///
112/// # Examples
113///
114/// ```ignore
115/// use exarch_core::creation::compression::compression_level_to_zstd;
116///
117/// let default_level = compression_level_to_zstd(None);
118/// assert_eq!(default_level, 3);
119///
120/// let fast_level = compression_level_to_zstd(Some(1));
121/// assert_eq!(fast_level, 1);
122///
123/// let best_level = compression_level_to_zstd(Some(9));
124/// assert_eq!(best_level, 19);
125/// ```
126#[allow(clippy::match_same_arms)] // Different semantic meanings for each level
127#[must_use]
128pub fn compression_level_to_zstd(level: Option<u8>) -> i32 {
129 match level {
130 // Default compression level
131 None | Some(6) => 3,
132 Some(1) => 1,
133 Some(2) => 2,
134 Some(7) => 10,
135 Some(8) => 15,
136 Some(9) => 19,
137 // All other levels (3-5, 0, 10+) map to default
138 _ => 3,
139 }
140}
141
142/// Unified compression level type.
143///
144/// This enum wraps codec-specific compression level types to provide
145/// a unified interface for compression level conversion.
146#[derive(Debug, Clone, Copy)]
147pub enum CompressionLevel {
148 /// Flate2 (gzip) compression level.
149 Flate2(flate2::Compression),
150
151 /// Bzip2 compression level.
152 Bzip2(bzip2::Compression),
153
154 /// Xz compression level (raw u32).
155 Xz(u32),
156
157 /// Zstd compression level (raw i32).
158 Zstd(i32),
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn test_compression_level_to_flate2() {
167 // Default
168 let level = compression_level_to_flate2(None);
169 assert_eq!(level, flate2::Compression::default());
170
171 let level = compression_level_to_flate2(Some(6));
172 assert_eq!(level, flate2::Compression::default());
173
174 // Fast
175 let level = compression_level_to_flate2(Some(1));
176 assert_eq!(level, flate2::Compression::fast());
177
178 // Best
179 let level = compression_level_to_flate2(Some(9));
180 assert_eq!(level, flate2::Compression::best());
181
182 // Specific level
183 let level = compression_level_to_flate2(Some(5));
184 assert_eq!(level, flate2::Compression::new(5));
185 }
186
187 #[test]
188 fn test_compression_level_to_bzip2() {
189 // Default
190 let level = compression_level_to_bzip2(None);
191 assert_eq!(level, bzip2::Compression::default());
192
193 // Fast
194 let level = compression_level_to_bzip2(Some(1));
195 assert_eq!(level, bzip2::Compression::fast());
196
197 // Best
198 let level = compression_level_to_bzip2(Some(9));
199 assert_eq!(level, bzip2::Compression::best());
200
201 // Specific level
202 let level = compression_level_to_bzip2(Some(4));
203 assert_eq!(level, bzip2::Compression::new(4));
204 }
205
206 #[test]
207 fn test_compression_level_to_xz() {
208 assert_eq!(compression_level_to_xz(None), 6);
209 assert_eq!(compression_level_to_xz(Some(6)), 6);
210 assert_eq!(compression_level_to_xz(Some(1)), 1);
211 assert_eq!(compression_level_to_xz(Some(9)), 9);
212 }
213
214 #[test]
215 fn test_compression_level_to_zstd() {
216 assert_eq!(compression_level_to_zstd(None), 3);
217 assert_eq!(compression_level_to_zstd(Some(6)), 3);
218 assert_eq!(compression_level_to_zstd(Some(1)), 1);
219 assert_eq!(compression_level_to_zstd(Some(2)), 2);
220 assert_eq!(compression_level_to_zstd(Some(7)), 10);
221 assert_eq!(compression_level_to_zstd(Some(8)), 15);
222 assert_eq!(compression_level_to_zstd(Some(9)), 19);
223 }
224}