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 max_hash_log(level: i32) -> Option<u32> {
104 let p = level_params_inner(level)?;
105 Some(p.hash_log.max(p.chain_log))
106}
107
108fn level_params_inner(level: i32) -> Option<LevelParams> {
109 Some(match level {
110 0 => return level_params_inner(DEFAULT_LEVEL),
111 -7 => LevelParams {
112 strategy: Strategy::Fast,
113 window_log: 19,
114 hash_log: 13,
115 chain_log: 13,
116 search_log: 0,
117 min_match: 5,
118 target_length: 7,
119 search_strength: 7,
120 force_raw_literals: true,
121 #[cfg(feature = "ldm")]
122 ldm_params: None,
123 },
124 -6 => LevelParams {
125 strategy: Strategy::Fast,
126 window_log: 19,
127 hash_log: 13,
128 chain_log: 13,
129 search_log: 0,
130 min_match: 5,
131 target_length: 7,
132 search_strength: 7,
133 force_raw_literals: false,
134 #[cfg(feature = "ldm")]
135 ldm_params: None,
136 },
137 -5 => LevelParams {
138 strategy: Strategy::Fast,
139 window_log: 19,
140 hash_log: 13,
141 chain_log: 13,
142 search_log: 0,
143 min_match: 5,
144 target_length: 6,
145 search_strength: 7,
146 force_raw_literals: false,
147 #[cfg(feature = "ldm")]
148 ldm_params: None,
149 },
150 -4 => LevelParams {
151 strategy: Strategy::Fast,
152 window_log: 19,
153 hash_log: 13,
154 chain_log: 13,
155 search_log: 0,
156 min_match: 5,
157 target_length: 5,
158 search_strength: 7,
159 force_raw_literals: false,
160 #[cfg(feature = "ldm")]
161 ldm_params: None,
162 },
163 -3 => LevelParams {
164 strategy: Strategy::Fast,
165 window_log: 19,
166 hash_log: 13,
167 chain_log: 13,
168 search_log: 0,
169 min_match: 5,
170 target_length: 4,
171 search_strength: 7,
172 force_raw_literals: false,
173 #[cfg(feature = "ldm")]
174 ldm_params: None,
175 },
176 -2 => LevelParams {
177 strategy: Strategy::Fast,
178 window_log: 19,
179 hash_log: 13,
180 chain_log: 13,
181 search_log: 0,
182 min_match: 5,
183 target_length: 3,
184 search_strength: 7,
185 force_raw_literals: false,
186 #[cfg(feature = "ldm")]
187 ldm_params: None,
188 },
189 -1 => LevelParams {
190 strategy: Strategy::Fast,
191 window_log: 19,
192 hash_log: 13,
193 chain_log: 13,
194 search_log: 0,
195 min_match: 5,
196 target_length: 2,
197 search_strength: 7,
198 force_raw_literals: false,
199 #[cfg(feature = "ldm")]
200 ldm_params: None,
201 },
202 1 => LevelParams {
203 strategy: Strategy::Fast,
204 window_log: 19,
205 hash_log: 14,
206 chain_log: 14,
207 search_log: 0,
208 min_match: 4,
209 target_length: 1,
210 search_strength: 8,
211 force_raw_literals: false,
212 #[cfg(feature = "ldm")]
213 ldm_params: None,
214 },
215 2 => LevelParams {
216 strategy: Strategy::Fast,
217 window_log: 20,
218 hash_log: 16,
219 chain_log: 16,
220 search_log: 0,
221 min_match: 4,
222 target_length: 1,
223 search_strength: 8,
224 force_raw_literals: false,
225 #[cfg(feature = "ldm")]
226 ldm_params: None,
227 },
228 3 => LevelParams {
229 strategy: Strategy::DFast,
230 window_log: 21,
231 hash_log: 18,
232 chain_log: 18,
233 search_log: 1,
234 min_match: 4,
235 target_length: 1,
236 search_strength: 5,
237 force_raw_literals: false,
238 #[cfg(feature = "ldm")]
239 ldm_params: None,
240 },
241 4 => LevelParams {
242 strategy: Strategy::DFast,
243 window_log: 23,
244 hash_log: 19,
245 chain_log: 19,
246 search_log: 1,
247 min_match: 4,
248 target_length: 1,
249 search_strength: 6,
250 force_raw_literals: false,
251 #[cfg(feature = "ldm")]
252 ldm_params: None,
253 },
254 _ => return None,
255 })
256}
257
258#[derive(Debug, Clone, Default)]
263pub struct Options {
264 pub(crate) window_log: Option<u32>,
265 #[cfg_attr(not(feature = "ldm"), allow(dead_code))]
266 pub(crate) ldm: bool,
267}
268
269impl Options {
270 #[must_use]
271 pub fn window_log(mut self, log: u32) -> Self {
272 self.window_log = Some(log);
273 self
274 }
275
276 #[cfg(feature = "ldm")]
277 #[must_use]
278 pub fn ldm(mut self, enable: bool) -> Self {
279 self.ldm = enable;
280 self
281 }
282}
283
284pub fn apply_options(params: &mut LevelParams, opts: &Options) {
285 if let Some(wl) = opts.window_log {
286 params.window_log = wl;
287 }
288 #[cfg(feature = "ldm")]
289 if opts.ldm {
290 params.ldm_params = Some(LdmParams::default_for_window_log(params.window_log));
291 }
292}