1#[macro_export]
2macro_rules! exit_with_msg {
3 (
4 ok $json_printer:expr => $($x:expr),*
5 ) => {{
6 print_at_output_channel!($json_printer.output_channel() => $($x),*);
7 print_field_if_json!($json_printer, "error : null");
8 $json_printer.print_close_bracket();
9 return 0;
10 }};
11 (
12 usr $json_printer:expr => $($x:expr),*
13 ) => {{
14 if $json_printer.json_enabled() {
15 print_json_field!($json_printer.output_channel() => "error", format!($($x),*), false, $json_printer.first_item());
16 } else {
17 println_at_output_channel!($json_printer.output_channel() => $($x),*);
18 }
19 $json_printer.print_close_bracket();
20 return 1;
21 }};
22 (
23 op $json_printer:expr => $($x:expr),*
24 ) => {{
25 if $json_printer.json_enabled() {
26 print_json_field!($json_printer.output_channel() => "error", format!($($x),*), false, $json_printer.first_item());
27 } else {
28 println_at_output_channel!($json_printer.output_channel() => $($x),*);
29 }
30 $json_printer.print_close_bracket();
31 return 2;
32 }}
33}
34
35macro_rules! exit_if_file {
36 (
37 exists $file:expr => $force_write:expr => $json_printer:expr => $($x:expr),*
38 ) => {{
39 use crate::file_utils;
40 if file_utils::check_if_file_exists($file)
41 && !$force_write
42 {
43 exit_with_msg!(usr $json_printer => $($x),*);
44 }
45 }};
46 (
47 does_not_exist $file:expr => $json_printer:expr => $($x:expr),*
48 ) => {{
49 use crate::file_utils;
50 if !file_utils::check_if_file_exists($file) {
51 exit_with_msg!(usr $json_printer => $($x),*);
52 }
53 }};
54 (
55 is_dir $file:expr => $json_printer:expr => $($x:expr),*
56 ) => {{
57 use crate::file_utils;
58 if file_utils::check_if_file_is_dir($file) {
59 exit_with_msg!(usr $json_printer => $($x),*);
60 }
61 }};
62 (
63 is_not_file $file:expr => $json_printer:expr => $($x:expr),*
64 ) => {{
65 use crate::file_utils;
66 if !file_utils::check_if_file_is_file($file) {
67 exit_with_msg!(usr $json_printer => $($x),*);
68 }
69 }};
70 (
71 has_no_file_name_part $file:expr => $json_printer:expr => $($x:expr),*
72 ) => {{
73 use crate::file_utils;
74 if let None = file_utils::get_file_name_part_of_path($file) {
75 exit_with_msg!(usr $json_printer => $($x),*);
76 }
77 }}
78}
79
80macro_rules! get_pr_verbosity_level {
81 (
82 $matches:expr, $json_printer:expr
83 ) => {{
84 use crate::progress_report;
85 use crate::progress_report::PRVerbosityLevel;
86
87 match $matches.value_of("pr_verbosity_level") {
88 None => if get_json_enabled!($matches) { PRVerbosityLevel::L0 } else { PRVerbosityLevel::L2 },
89 Some(x) => match progress_report::string_to_verbosity_level(x) {
90 Ok(x) => x,
91 Err(_) => exit_with_msg!(usr $json_printer => "Invalid progress report verbosity level")
92 }
93 }
94 }}
95}
96
97macro_rules! get_from_pos {
98 (
99 $matches:expr, $json_printer:expr
100 ) => {{
101 use std::str::FromStr;
102
103 match $matches.value_of("from_pos") {
104 None => None,
105 Some(x) => match u64::from_str(x) {
106 Ok(x) => Some(x),
107 Err(_) => exit_with_msg!(usr $json_printer => "Invalid from position")
108 }
109 }
110 }}
111}
112
113macro_rules! get_to_pos {
114 (
115 $matches:expr, $json_printer:expr
116 ) => {{
117 use std::str::FromStr;
118 use crate::misc_utils::RangeEnd;
119
120 match ($matches.value_of("to_pos_inc"), $matches.value_of("to_pos_exc")) {
121 (None, None ) => None,
122 (Some(x), None ) =>
123 match u64::from_str(x) {
124 Ok(x) => Some(RangeEnd::Inc(x)),
125 Err(_) => exit_with_msg!(usr $json_printer => "Invalid to inc position")
126 },
127 (None, Some(x)) =>
128 match u64::from_str(x) {
129 Ok(x) => Some(RangeEnd::Exc(x)),
130 Err(_) => exit_with_msg!(usr $json_printer => "Invalid to exc position")
131 },
132 (Some(_), Some(_)) =>
133 unreachable!(),
134 }
135 }}
136}
137
138macro_rules! get_guess_burst_from_pos {
139 (
140 $matches:expr, $json_printer:expr
141 ) => {{
142 use std::str::FromStr;
143
144 match $matches.value_of("guess_burst_from_pos") {
145 None => None,
146 Some(x) => match u64::from_str(x) {
147 Ok(x) => Some(x),
148 Err(_) => exit_with_msg!(usr $json_printer => "Invalid guess burst from position")
149 }
150 }
151 }}
152}
153
154macro_rules! get_ref_from_pos {
155 (
156 $matches:expr, $json_printer:expr
157 ) => {{
158 use std::str::FromStr;
159
160 match $matches.value_of("ref_from_pos") {
161 None => None,
162 Some(x) => match u64::from_str(x) {
163 Ok(x) => Some(x),
164 Err(_) => exit_with_msg!(usr $json_printer => "Invalid ref from position")
165 }
166 }
167 }}
168}
169
170macro_rules! get_ref_to_pos {
171 (
172 $matches:expr, $json_printer:expr
173 ) => {{
174 use std::str::FromStr;
175 use crate::misc_utils::RangeEnd;
176
177 match ($matches.value_of("ref_to_pos_inc"), $matches.value_of("ref_to_pos_exc")) {
178 (None, None ) => None,
179 (Some(x), None ) =>
180 match u64::from_str(x) {
181 Ok(x) => Some(RangeEnd::Inc(x)),
182 Err(_) => exit_with_msg!(usr $json_printer => "Invalid ref to inc position")
183 },
184 (None, Some(x)) =>
185 match u64::from_str(x) {
186 Ok(x) => Some(RangeEnd::Exc(x)),
187 Err(_) => exit_with_msg!(usr $json_printer => "Invalid ref to exc position")
188 },
189 (Some(_), Some(_)) =>
190 unreachable!()
191 }
192 }}
193}
194
195macro_rules! get_in_file {
196 (
197 $matches:expr, $json_printer:expr
198 ) => {{
199 let in_file = $matches.value_of("in_file").unwrap();
200
201 exit_if_file!(does_not_exist in_file
202 => $json_printer
203 => "File \"{}\" does not exist", in_file);
204
205 exit_if_file!(has_no_file_name_part in_file
206 => $json_printer
207 => "File name \"{}\"does not have a file name component", in_file);
208
209 exit_if_file!(is_dir in_file
210 => $json_printer
211 => "File \"{}\" is a directory", in_file);
212
213 in_file
214 }};
215 (
216 accept_stdin $matches:expr, $json_printer:expr
217 ) => {{
218 use crate::file_utils;
219 let in_file = $matches.value_of("in_file").unwrap();
220 if !file_utils::check_if_file_is_stdin(in_file) {
221 exit_if_file!(does_not_exist in_file
222 => $json_printer
223 => "File \"{}\" does not exist", in_file);
224
225 exit_if_file!(has_no_file_name_part in_file
226 => $json_printer
227 => "File name \"{}\"does not have a file name component", in_file);
228
229 exit_if_file!(is_dir in_file
230 => $json_printer
231 => "File \"{}\" is a directory", in_file);
232 }
233 in_file
234 }};
235}
236
237macro_rules! get_data_or_parity_shards {
238 (
239 data => $matches:expr, $version:expr, $json_printer:expr
240 ) => {{
241 get_data_or_parity_shards!("rs_data", "data", $matches, $version, $json_printer)
242 }};
243 (
244 parity => $matches:expr, $version:expr, $json_printer:expr
245 ) => {{
246 get_data_or_parity_shards!("rs_parity", "parity", $matches, $version, $json_printer)
247 }};
248 (
249 $match_val:expr, $data_or_par:expr, $matches:expr, $version:expr, $json_printer:expr
250 ) => {{
251 use crate::sbx_specs::ver_to_usize;
252
253 let ver_usize = ver_to_usize($version);
254
255 match $matches.value_of($match_val) {
256 None => {
257 exit_with_msg!(usr $json_printer => "Reed-Solomon erasure code {} shard count must be specified for version {}", $data_or_par, ver_usize);
258 },
259 Some(x) => {
260 match usize::from_str(&x) {
261 Ok(x) => x,
262 Err(_) => {
263 exit_with_msg!(usr $json_printer => "Failed to parse Reed-Solomon erasure code {} shard count", $data_or_par);
264 }
265 }
266 }
267 }
268 }}
269}
270
271macro_rules! get_data_shards {
272 (
273 $matches:expr, $version:expr, $json_printer:expr
274 ) => {{
275 get_data_or_parity_shards!(data => $matches, $version, $json_printer)
276 }}
277}
278
279macro_rules! get_parity_shards {
280 (
281 $matches:expr, $version:expr, $json_printer:expr
282 ) => {{
283 get_data_or_parity_shards!(parity => $matches, $version, $json_printer)
284 }}
285}
286
287macro_rules! get_ver_and_data_par_burst_w_defaults {
288 (
289 $matches:expr, $json_printer:expr
290 ) => {{
291 use crate::sbx_specs::string_to_ver;
292 use crate::encode_defaults;
293
294 match $matches.value_of("sbx_version") {
295 None => {
296 if let Some(_) = $matches.value_of("rs_data") {
297 exit_with_msg!(usr $json_printer => "Please state the SBX version explicitly if you want to use a custom Reed-Solomon data shard count");
298 }
299 if let Some(_) = $matches.value_of("rs_parity") {
300 exit_with_msg!(usr $json_printer => "Please state the SBX version explicitly if you want to use a custom Reed-Solomon parity shard count");
301 }
302 if let Some(_) = $matches.value_of("burst") {
303 exit_with_msg!(usr $json_printer => "Please state the SBX version explicitly if you want to use a custom burst error resistance level");
304 }
305
306 (encode_defaults::VERSION, Some(encode_defaults::DATA_PAR_BURST))
307 },
308 Some(x) => {
309 let version =
310 match string_to_ver(&x) {
311 Ok(v) => v,
312 Err(()) => {
313 exit_with_msg!(usr $json_printer => "Invalid SBX version");
314 }
315 };
316
317 let data_par_burst = if ver_uses_rs(version) {
318 let data_shards = get_data_shards!($matches, version, $json_printer);
320 let parity_shards = get_parity_shards!($matches, version, $json_printer);
321
322 check_data_parity_shards!(data_shards, parity_shards, $json_printer);
323
324 let burst = get_burst_or_zero!($matches, $json_printer);
325
326 Some((data_shards, parity_shards, burst))
327 } else {
328 None
329 };
330
331 (version, data_par_burst)
332 }
333 }
334 }}
335}
336
337macro_rules! check_data_parity_shards {
338 (
339 $data_shards:expr, $parity_shards:expr, $json_printer:expr
340 ) => {{
341 use reed_solomon_erasure::galois_8::ReedSolomon;
342 use reed_solomon_erasure::Error;
343
344 match ReedSolomon::new($data_shards, $parity_shards) {
345 Ok(_) => {},
346 Err(Error::TooFewDataShards) => {
347 exit_with_msg!(usr $json_printer => "Too few data shards for Reed-Solomon erasure code");
348 },
349 Err(Error::TooFewParityShards) => {
350 exit_with_msg!(usr $json_printer => "Too few parity shards for Reed-Solomon erasure code");
351 },
352 Err(Error::TooManyShards) => {
353 exit_with_msg!(usr $json_printer => "Too many shards for Reed-Solomon erasure code");
354 },
355 Err(_) => { panic!(); }
356 }
357 }}
358}
359
360macro_rules! get_burst_or_zero {
361 (
362 $matches:expr, $json_printer:expr
363 ) => {{
364 match $matches.value_of("burst") {
365 None => 0,
366 Some(x) => {
367 match usize::from_str(x) {
368 Ok(x) => x,
369 Err(_) => {
370 exit_with_msg!(usr $json_printer => "Failed to parse burst error resistance level");
371 }
372 }
373 }
374 }
375 }}
376}
377
378macro_rules! ask_if_wish_to_continue {
379 (
380 ) => {{
381 use std::io::{stdin, stdout, Read, Write};
382
383 print!("Do you wish to continue? [y/N] ");
384
385 stdout().flush().unwrap();
386
387 let mut ans: [u8; 1] = [0; 1];
388
389 let _ = stdin().read(&mut ans).unwrap();
390
391 if ans != *b"y" {
392 return 0;
393 }
394 }};
395}
396
397macro_rules! get_burst_opt {
398 (
399 $matches:expr, $json_printer:expr
400 ) => {{
401 use std::str::FromStr;
402
403 match $matches.value_of("burst") {
404 None => None,
405 Some(x) => {
406 match usize::from_str(x) {
407 Ok(x) => Some(x),
408 Err(_) => {
409 exit_with_msg!(usr $json_printer => "Failed to parse burst error resistance level");
410 }
411 }
412 }
413 }
414 }}
415}
416
417macro_rules! parse_uid {
418 (
419 $buf:expr, $uid:expr, $json_printer:expr
420 ) => {{
421 use crate::misc_utils::HexError;
422 use crate::misc_utils;
423 use crate::sbx_specs::SBX_FILE_UID_LEN;
424
425 match misc_utils::hex_string_to_bytes($uid) {
426 Ok(x) => {
427 if x.len() != SBX_FILE_UID_LEN {
428 exit_with_msg!(usr $json_printer => "UID provided does not have the correct number of hex digits, provided : {}, need : {}",
429 $uid.len(),
430 SBX_FILE_UID_LEN * 2);
431 }
432
433 $buf.copy_from_slice(&x);
434 },
435 Err(HexError::InvalidHexString) => {
436 exit_with_msg!(usr $json_printer => "UID provided is not a valid hex string");
437 },
438 Err(HexError::InvalidLen) => {
439 exit_with_msg!(usr $json_printer => "UID provided does not have the correct number of hex digits, provided : {}, need : {}",
440 $uid.len(),
441 SBX_FILE_UID_LEN * 2);
442 }
443 }
444 }}
445}
446
447macro_rules! get_uid {
448 (
449 $matches:expr, $buf:expr, $json_printer:expr
450 ) => {{
451 match $matches.value_of("uid") {
452 None => None,
453 Some(uid) => {
454 parse_uid!($buf, uid, $json_printer);
455 Some(&$buf)
456 }
457 }
458 }};
459}
460
461macro_rules! get_ref_block_choice {
462 (
463 $matches:expr
464 ) => {{
465 use crate::block_utils::RefBlockChoice::*;
466 use crate::sbx_block::BlockType;
467
468 if $matches.is_present("no_meta") {
469 Any
470 } else {
471 Prefer(BlockType::Meta)
472 }
473 }};
474}
475
476macro_rules! get_meta_enabled {
477 (
478 $matches:expr
479 ) => {{
480 !$matches.is_present("no_meta")
481 }};
482}
483
484macro_rules! get_json_enabled {
485 (
486 $matches:expr
487 ) => {{
488 $matches.is_present("json")
489 }};
490}
491
492macro_rules! get_json_printer {
493 (
494 $matches:expr
495 ) => {{
496 use crate::json_printer::JSONPrinter;
497 use crate::output_channel::OutputChannel;
498 use std::sync::Arc;
499
500 Arc::new(JSONPrinter::new(
501 $matches.is_present("json"),
502 OutputChannel::Stdout,
503 ))
504 }};
505}
506
507#[macro_export]
508macro_rules! print_at_output_channel {
509 (
510 $channel:expr => $($x:expr),*
511 ) => {{
512 use crate::output_channel::OutputChannel;
513
514 match $channel {
515 OutputChannel::Stdout => print!($($x),*),
516 OutputChannel::Stderr => eprint!($($x),*),
517 }
518 }}
519}
520
521#[macro_export]
522macro_rules! println_at_output_channel {
523 (
524 $channel:expr => $($x:expr),*
525 ) => {{
526 use crate::output_channel::OutputChannel;
527
528 match $channel {
529 OutputChannel::Stdout => println!($($x),*),
530 OutputChannel::Stderr => eprintln!($($x),*),
531 }
532 }}
533}
534
535macro_rules! get_multi_pass {
536 (
537 $matches:expr, $json_printer:expr
538 ) => {{
539 use crate::misc_utils::MultiPassType;
540
541 match (
542 $matches.is_present("multi_pass"),
543 $matches.is_present("multi_pass_no_skip"),
544 ) {
545 (false, false) => None,
546 (true, false) => Some(MultiPassType::SkipGood),
547 (false, true) => Some(MultiPassType::OverwriteAll),
548 (true, true) => unreachable!(),
549 }
550 }};
551}