1#![forbid(unsafe_code)]
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum Strategy {
6 Fast,
8 DFast,
10}
11
12#[derive(Debug, Clone, Copy)]
14pub struct LdmParams {
15 pub hash_log: u32,
16 pub bucket_size_log: u32,
17 pub min_match_length: u32,
18 pub hash_rate_log: u32,
19}
20
21impl LdmParams {
22 pub fn default_for_window_log(window_log: u32) -> Self {
23 let hash_log = 20u32.min(window_log.saturating_sub(1));
24 let hash_rate_log = window_log.saturating_sub(hash_log).max(7);
25 Self {
26 hash_log,
27 bucket_size_log: 4,
28 min_match_length: 64,
29 hash_rate_log,
30 }
31 }
32}
33
34#[derive(Debug, Clone, Copy)]
39pub struct LevelParams {
40 pub strategy: Strategy,
41 pub window_log: u32,
42 pub hash_log: u32,
43 pub chain_log: u32,
45 pub search_log: u32,
46 pub min_match: u32,
47 pub target_length: u32,
48 pub search_strength: u32,
49 pub force_raw_literals: bool,
50 #[cfg(feature = "ldm")]
51 pub ldm_params: Option<LdmParams>,
52}
53
54impl LevelParams {
55 #[must_use]
56 pub fn with_window_log(mut self, window_log: u32) -> Self {
57 self.window_log = window_log;
58 self
59 }
60
61 #[cfg(feature = "ldm")]
62 #[must_use]
63 pub fn with_ldm(mut self, params: LdmParams) -> Self {
64 self.ldm_params = Some(params);
65 self
66 }
67}
68
69pub const DEFAULT_LEVEL: i32 = 1;
71
72pub fn level_params(level: i32) -> Option<LevelParams> {
77 level_params_for_size(level, usize::MAX)
78}
79
80pub fn level_params_for_size(level: i32, src_len: usize) -> Option<LevelParams> {
86 let mut params = level_params_inner(level)?;
87 params.hash_log = params.hash_log.clamp(HASH_LOG_MIN, HASH_LOG_MAX);
88 params.chain_log = params.chain_log.clamp(HASH_LOG_MIN, HASH_LOG_MAX);
89 if (2..usize::MAX).contains(&src_len) {
90 let src_log = 32 - ((src_len as u32) - 1).leading_zeros();
91 params.hash_log = params.hash_log.min(src_log).max(HASH_LOG_MIN);
92 params.chain_log = params.chain_log.min(src_log).max(HASH_LOG_MIN);
93 params.window_log = params.window_log.min(src_log);
94 }
95 Some(params)
96}
97
98pub const HASH_LOG_MIN: u32 = 6;
99pub const HASH_LOG_MAX: u32 = 30;
100
101pub fn apply_raw_literals_size_override(params: &mut LevelParams, input_len: usize) {
102 if params.strategy != Strategy::Fast || params.force_raw_literals {
103 return;
104 }
105 let threshold = match params.target_length {
106 7.. => 16384,
107 6 => 8192,
108 5 => 4096,
109 4 => 2048,
110 3 => 1024,
111 _ => 0,
112 };
113 if input_len <= threshold {
114 params.force_raw_literals = true;
115 }
116}
117
118pub fn max_hash_log(level: i32) -> Option<u32> {
121 let p = level_params_inner(level)?;
122 Some(p.hash_log.max(p.chain_log))
123}
124
125fn level_params_inner(level: i32) -> Option<LevelParams> {
126 Some(match level {
127 0 => return level_params_inner(DEFAULT_LEVEL),
128 -8 => LevelParams {
129 strategy: Strategy::Fast,
130 window_log: 19,
131 hash_log: 13,
132 chain_log: 13,
133 search_log: 0,
134 min_match: 5,
135 target_length: 7,
136 search_strength: 7,
137 force_raw_literals: true,
138 #[cfg(feature = "ldm")]
139 ldm_params: None,
140 },
141 -7 => LevelParams {
142 strategy: Strategy::Fast,
143 window_log: 19,
144 hash_log: 13,
145 chain_log: 13,
146 search_log: 0,
147 min_match: 5,
148 target_length: 7,
149 search_strength: 7,
150 force_raw_literals: false,
151 #[cfg(feature = "ldm")]
152 ldm_params: None,
153 },
154 -6 => LevelParams {
155 strategy: Strategy::Fast,
156 window_log: 19,
157 hash_log: 13,
158 chain_log: 13,
159 search_log: 0,
160 min_match: 5,
161 target_length: 6,
162 search_strength: 7,
163 force_raw_literals: false,
164 #[cfg(feature = "ldm")]
165 ldm_params: None,
166 },
167 -5 => LevelParams {
168 strategy: Strategy::Fast,
169 window_log: 19,
170 hash_log: 13,
171 chain_log: 13,
172 search_log: 0,
173 min_match: 5,
174 target_length: 5,
175 search_strength: 7,
176 force_raw_literals: false,
177 #[cfg(feature = "ldm")]
178 ldm_params: None,
179 },
180 -4 => LevelParams {
181 strategy: Strategy::Fast,
182 window_log: 19,
183 hash_log: 13,
184 chain_log: 13,
185 search_log: 0,
186 min_match: 5,
187 target_length: 4,
188 search_strength: 7,
189 force_raw_literals: false,
190 #[cfg(feature = "ldm")]
191 ldm_params: None,
192 },
193 -3 => LevelParams {
194 strategy: Strategy::Fast,
195 window_log: 19,
196 hash_log: 13,
197 chain_log: 13,
198 search_log: 0,
199 min_match: 5,
200 target_length: 3,
201 search_strength: 7,
202 force_raw_literals: false,
203 #[cfg(feature = "ldm")]
204 ldm_params: None,
205 },
206 -2 => LevelParams {
207 strategy: Strategy::Fast,
208 window_log: 19,
209 hash_log: 13,
210 chain_log: 13,
211 search_log: 0,
212 min_match: 5,
213 target_length: 2,
214 search_strength: 7,
215 force_raw_literals: false,
216 #[cfg(feature = "ldm")]
217 ldm_params: None,
218 },
219 -1 => LevelParams {
220 strategy: Strategy::Fast,
221 window_log: 19,
222 hash_log: 13,
223 chain_log: 13,
224 search_log: 0,
225 min_match: 5,
226 target_length: 1,
227 search_strength: 7,
228 force_raw_literals: false,
229 #[cfg(feature = "ldm")]
230 ldm_params: None,
231 },
232 1 => LevelParams {
233 strategy: Strategy::Fast,
234 window_log: 19,
235 hash_log: 14,
236 chain_log: 14,
237 search_log: 0,
238 min_match: 4,
239 target_length: 1,
240 search_strength: 8,
241 force_raw_literals: false,
242 #[cfg(feature = "ldm")]
243 ldm_params: None,
244 },
245 2 => LevelParams {
246 strategy: Strategy::Fast,
247 window_log: 20,
248 hash_log: 17,
249 chain_log: 17,
250 search_log: 0,
251 min_match: 4,
252 target_length: 1,
253 search_strength: 8,
254 force_raw_literals: false,
255 #[cfg(feature = "ldm")]
256 ldm_params: None,
257 },
258 3 => LevelParams {
259 strategy: Strategy::DFast,
260 window_log: 21,
261 hash_log: 18,
262 chain_log: 18,
263 search_log: 1,
264 min_match: 4,
265 target_length: 1,
266 search_strength: 5,
267 force_raw_literals: false,
268 #[cfg(feature = "ldm")]
269 ldm_params: None,
270 },
271 4 => LevelParams {
272 strategy: Strategy::DFast,
273 window_log: 23,
274 hash_log: 19,
275 chain_log: 19,
276 search_log: 1,
277 min_match: 4,
278 target_length: 1,
279 search_strength: 6,
280 force_raw_literals: false,
281 #[cfg(feature = "ldm")]
282 ldm_params: None,
283 },
284 _ => return None,
285 })
286}
287
288#[derive(Debug, Clone, Default)]
293pub struct Options {
294 pub(crate) window_log: Option<u32>,
295 #[cfg_attr(not(feature = "ldm"), allow(dead_code))]
296 pub(crate) ldm: bool,
297}
298
299impl Options {
300 #[must_use]
301 pub fn window_log(mut self, log: u32) -> Self {
302 self.window_log = Some(log);
303 self
304 }
305
306 #[cfg(feature = "ldm")]
307 #[must_use]
308 pub fn ldm(mut self, enable: bool) -> Self {
309 self.ldm = enable;
310 self
311 }
312}
313
314pub fn apply_options(params: &mut LevelParams, opts: &Options) {
315 if let Some(wl) = opts.window_log {
316 params.window_log = wl;
317 }
318 #[cfg(feature = "ldm")]
319 if opts.ldm {
320 params.ldm_params = Some(LdmParams::default_for_window_log(params.window_log));
321 }
322}