1use std::fmt::{Display, Write};
15use std::sync::Arc;
16
17use super::formatters::format_as_hexdump;
18use super::mediator::Mediator;
19
20pub struct DebugTrace {}
22
23impl DebugTrace {
24 #[inline(always)]
26 pub fn print<T: Display>(text: T) {
27 let mediator: Arc<Mediator> = Mediator::current();
28
29 if mediator.debug_output {
30 mediator.debug_print(text);
31 }
32 }
33
34 #[inline(always)]
36 pub fn print_data(description: &str, offset: u64, data: &[u8], data_size: usize, group: bool) {
37 let mediator: Arc<Mediator> = Mediator::current();
38
39 if mediator.debug_output {
40 mediator.debug_print(format!(
41 "{} data of size: {} at offset: {} (0x{:08x})\n",
42 description, data_size, offset, offset
43 ));
44 mediator.debug_print(format_as_hexdump(data, group));
45 }
46 }
47
48 #[inline(always)]
50 pub fn print_data_field(identifier: &str, data: &[u8]) {
51 let mediator: Arc<Mediator> = Mediator::current();
52
53 if mediator.debug_output {
54 mediator.debug_print(format!(" {}\n", identifier));
55 mediator.debug_print(format_as_hexdump(data, true));
56 }
57 }
58
59 #[inline(always)]
61 pub fn print_end() {
62 let mediator: Arc<Mediator> = Mediator::current();
63
64 if mediator.debug_output {
65 mediator.debug_print("}\n\n");
66 }
67 }
68
69 #[inline(always)]
71 pub fn print_field<V: Display>(identifier: &str, value: V) {
72 let mediator: Arc<Mediator> = Mediator::current();
73
74 if mediator.debug_output {
75 mediator.debug_print(format!(" {}: {},\n", identifier, value));
76 }
77 }
78
79 #[inline(always)]
81 pub fn print_start(identifier: &str) {
82 let mediator: Arc<Mediator> = Mediator::current();
83
84 if mediator.debug_output {
85 mediator.debug_print(format!("{} {{\n", identifier));
86 }
87 }
88
89 #[inline(always)]
91 pub fn print_structure(debug_read_data: fn(&[u8]) -> String, data: &[u8]) {
92 let mediator: Arc<Mediator> = Mediator::current();
93
94 if mediator.debug_output {
95 mediator.debug_print(debug_read_data(data));
96 }
97 }
98
99 #[inline(always)]
101 pub fn print_value<V: Display>(description: &str, value: V) {
102 let mediator: Arc<Mediator> = Mediator::current();
103
104 if mediator.debug_output {
105 mediator.debug_print(format!("{}: {}\n", description, value));
106 }
107 }
108
109 #[inline]
111 pub fn scope<F, R, E>(function: F) -> Result<R, E>
112 where
113 F: FnOnce(&mut DebugTraceScope) -> Result<R, E>,
114 {
115 let mediator = Mediator::current();
116 let debug_output: bool = mediator.debug_output;
117
118 let mut scope = DebugTraceScope {
119 mediator: &mediator,
120 debug_output,
121 output: if debug_output {
122 String::with_capacity(1024)
123 } else {
124 String::new()
125 },
126 };
127 let result = function(&mut scope);
128
129 if debug_output && !scope.output.is_empty() {
130 scope.mediator.debug_print(scope.output);
131 }
132 result
133 }
134
135 #[inline]
137 pub fn static_scope<F>(function: F)
138 where
139 F: FnOnce(&DebugTraceStaticScope),
140 {
141 let mediator = Mediator::current();
142
143 if mediator.debug_output {
144 let scope = DebugTraceStaticScope {
145 mediator: &mediator,
146 };
147 function(&scope);
148 }
149 }
150}
151
152pub struct DebugTraceScope<'a> {
154 mediator: &'a Mediator,
156
157 pub debug_output: bool,
159
160 pub output: String,
162}
163
164impl<'a> DebugTraceScope<'a> {
165 #[inline(always)]
167 pub fn print<T: Display>(&mut self, text: T) {
168 if self.debug_output {
169 _ = write!(self.output, "{}", text);
170 }
171 }
172
173 #[inline(always)]
175 pub fn print_data(
176 &mut self,
177 description: &str,
178 offset: u64,
179 data: &[u8],
180 data_size: usize,
181 group: bool,
182 ) {
183 if self.debug_output {
184 _ = writeln!(
185 self.output,
186 "{} data of size: {} at offset: {} (0x{:08x})",
187 description, data_size, offset, offset
188 );
189 self.output
190 .push_str(format_as_hexdump(data, group).as_str());
191 }
192 }
193
194 #[inline(always)]
196 pub fn print_data_field(&mut self, identifier: &str, data: &[u8]) {
197 if self.debug_output {
198 _ = writeln!(self.output, " {}", identifier);
199 self.output.push_str(format_as_hexdump(data, true).as_str());
200 }
201 }
202
203 #[inline(always)]
205 pub fn print_end(&mut self) {
206 if self.debug_output {
207 _ = write!(self.output, "}}\n\n");
208 }
209 }
210
211 #[inline(always)]
213 pub fn print_field<V: Display>(&mut self, identifier: &str, value: V) {
214 if self.debug_output {
215 _ = writeln!(self.output, " {}: {},", identifier, value);
216 }
217 }
218
219 #[inline(always)]
221 pub fn print_start(&mut self, identifier: &str) {
222 if self.debug_output {
223 _ = writeln!(self.output, "{} {{", identifier);
224 }
225 }
226
227 #[inline(always)]
229 pub fn print_structure(&mut self, debug_read_data: fn(&[u8]) -> String, data: &[u8]) {
230 if self.debug_output {
231 self.output.push_str(&debug_read_data(data));
232 }
233 }
234
235 #[inline(always)]
237 pub fn print_value<V: Display>(&mut self, description: &str, value: V) {
238 if self.debug_output {
239 _ = writeln!(self.output, "{}: {}", description, value);
240 }
241 }
242}
243
244pub struct DebugTraceStaticScope<'a> {
246 mediator: &'a Mediator,
248}
249
250impl<'a> DebugTraceStaticScope<'a> {
251 #[inline(always)]
253 pub fn print<T: Display>(&self, text: T) {
254 self.mediator.debug_print(text);
255 }
256
257 #[inline(always)]
259 pub fn print_data(
260 &self,
261 description: &str,
262 offset: u64,
263 data: &[u8],
264 data_size: usize,
265 group: bool,
266 ) {
267 self.mediator.debug_print(format!(
268 "{} data of size: {} at offset: {} (0x{:08x})\n",
269 description, data_size, offset, offset
270 ));
271 self.mediator.debug_print(format_as_hexdump(data, group));
272 }
273
274 #[inline(always)]
276 pub fn print_data_field(&self, identifier: &str, data: &[u8]) {
277 self.mediator.debug_print(format!(" {}\n", identifier));
278 self.mediator.debug_print(format_as_hexdump(data, true));
279 }
280
281 #[inline(always)]
283 pub fn print_end(&self) {
284 self.mediator.debug_print("}\n\n");
285 }
286
287 #[inline(always)]
289 pub fn print_field<V: Display>(&self, identifier: &str, value: V) {
290 self.mediator
291 .debug_print(format!(" {}: {},\n", identifier, value));
292 }
293
294 #[inline(always)]
296 pub fn print_start(&self, identifier: &str) {
297 self.mediator.debug_print(format!("{} {{\n", identifier));
298 }
299
300 #[inline(always)]
302 pub fn print_structure(&self, debug_read_data: fn(&[u8]) -> String, data: &[u8]) {
303 self.mediator.debug_print(debug_read_data(data));
304 }
305
306 #[inline(always)]
308 pub fn print_value<V: Display>(&self, description: &str, value: V) {
309 self.mediator
310 .debug_print(format!("{}: {}\n", description, value));
311 }
312}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317
318 use std::cell::Cell;
319 use std::sync::Arc;
320
321 use crate::errors::ErrorTrace;
322 use crate::formatters::format_as_hexdump;
323
324 fn get_test_data() -> Vec<u8> {
325 vec![
326 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
327 0xbe, 0xef,
328 ]
329 }
330
331 fn test_debug_read_data(data: &[u8]) -> String {
332 format!("structure (size: {})", data.len())
333 }
334
335 #[test]
336 fn test_print_with_debug_output_enabled() {
337 Mediator::new(true).make_current();
338
339 DebugTrace::print("test\n");
340 DebugTrace::print(String::from("test\n"));
341 DebugTrace::print(42);
342 }
343
344 #[test]
345 fn test_print_with_debug_output_disabled() {
346 DebugTrace::print("test\n");
347 DebugTrace::print(String::from("test\n"));
348 DebugTrace::print(42);
349 }
350
351 #[test]
352 fn test_print_data_with_debug_output_enabled() {
353 Mediator::new(true).make_current();
354
355 let test_data: Vec<u8> = get_test_data();
356 DebugTrace::print_data("test", 0, &test_data, 16, false);
357 DebugTrace::print_data("test", 0, &test_data, 16, true);
358 }
359
360 #[test]
361 fn test_print_data_with_debug_output_disabled() {
362 let test_data: Vec<u8> = get_test_data();
363 DebugTrace::print_data("test", 0, &test_data, 16, false);
364 DebugTrace::print_data("test", 0, &test_data, 16, true);
365 }
366
367 #[test]
368 fn test_print_data_field_with_debug_output_enabled() {
369 Mediator::new(true).make_current();
370
371 let test_data: Vec<u8> = get_test_data();
372 DebugTrace::print_data_field("test", &test_data);
373 }
374
375 #[test]
376 fn test_print_data_field_with_debug_output_disabled() {
377 let test_data: Vec<u8> = get_test_data();
378 DebugTrace::print_data_field("test", &test_data);
379 }
380
381 #[test]
382 fn test_print_end_with_debug_output_enabled() {
383 Mediator::new(true).make_current();
384
385 DebugTrace::print_end();
386 }
387
388 #[test]
389 fn test_print_end_with_debug_output_disabled() {
390 DebugTrace::print_end();
391 }
392
393 #[test]
394 fn test_print_field_with_debug_output_enabled() {
395 Mediator::new(true).make_current();
396
397 DebugTrace::print_field("identifier", "value");
398 DebugTrace::print_field("identifier", 42);
399 }
400
401 #[test]
402 fn test_print_field_with_debug_output_disabled() {
403 DebugTrace::print_field("identifier", "value");
404 DebugTrace::print_field("identifier", 42);
405 }
406
407 #[test]
408 fn test_print_start_with_debug_output_enabled() {
409 Mediator::new(true).make_current();
410
411 DebugTrace::print_start("test");
412 }
413
414 #[test]
415 fn test_print_start_with_debug_output_disabled() {
416 DebugTrace::print_start("test");
417 }
418
419 #[test]
420 fn test_print_structure_with_debug_output_enabled() {
421 Mediator::new(true).make_current();
422
423 let test_data: Vec<u8> = get_test_data();
424 DebugTrace::print_structure(test_debug_read_data, &test_data);
425 }
426
427 #[test]
428 fn test_print_structure_with_debug_output_disabled() {
429 let test_data: Vec<u8> = get_test_data();
430 DebugTrace::print_structure(test_debug_read_data, &test_data);
431 }
432
433 #[test]
434 fn test_print_value_with_debug_output_enabled() {
435 Mediator::new(true).make_current();
436
437 DebugTrace::print_value("test", "value");
438 DebugTrace::print_value("test", 42);
439 }
440
441 #[test]
442 fn test_print_value_with_debug_output_disabled() {
443 DebugTrace::print_value("test", "value");
444 DebugTrace::print_value("test", 42);
445 }
446
447 #[test]
448 fn test_scope_with_debug_output_enabled() -> Result<(), ErrorTrace> {
449 Mediator::new(true).make_current();
450
451 let result: u64 = DebugTrace::scope(
452 |scope: &mut DebugTraceScope<'_>| -> Result<u64, ErrorTrace> {
453 scope.print_start("test");
454 scope.print_field("value", 42);
455 scope.print_end();
456 Ok(42)
457 },
458 )?;
459 assert_eq!(result, 42);
460
461 let result: u64 = DebugTrace::scope(
462 |scope: &mut DebugTraceScope<'_>| -> Result<u64, ErrorTrace> {
463 let _ = scope;
464 Ok(0)
465 },
466 )?;
467 assert_eq!(result, 0);
468
469 Ok(())
470 }
471
472 #[test]
473 fn test_scope_with_debug_output_disabled() -> Result<(), ErrorTrace> {
474 let result: u64 = DebugTrace::scope(
475 |scope: &mut DebugTraceScope<'_>| -> Result<u64, ErrorTrace> {
476 assert!(!scope.debug_output);
477 scope.print_start("test");
478 assert_eq!(scope.output, "");
479 Ok(42)
480 },
481 )?;
482 assert_eq!(result, 42);
483
484 Ok(())
485 }
486
487 #[test]
488 fn test_scope_with_error() -> Result<(), ErrorTrace> {
489 Mediator::new(true).make_current();
490
491 let error: ErrorTrace = DebugTrace::scope(
492 |scope: &mut DebugTraceScope<'_>| -> Result<u64, ErrorTrace> {
493 scope.print("error\n");
494 Err(ErrorTrace::new(String::from("test error")))
495 },
496 )
497 .unwrap_err();
498
499 assert_eq!(error.to_string(), "#0 test error");
500
501 Ok(())
502 }
503
504 #[test]
505 fn test_trace_scope_with_debug_output_enabled() -> Result<(), ErrorTrace> {
506 Mediator::new(true).make_current();
507
508 let mediator: Arc<Mediator> = Mediator::current();
509 let debug_output: bool = mediator.debug_output;
510
511 let mut scope = DebugTraceScope {
512 mediator: &mediator,
513 debug_output,
514 output: if debug_output {
515 String::with_capacity(1024)
516 } else {
517 String::new()
518 },
519 };
520 assert!(scope.debug_output);
521 assert_eq!(scope.output, "");
522
523 scope.print_start("test");
524 assert_eq!(scope.output, "test {\n");
525
526 scope.print_field("identifier", "value");
527 assert_eq!(scope.output, "test {\n identifier: value,\n");
528
529 scope.print_field("identifier", 42);
530 assert_eq!(
531 scope.output,
532 "test {\n identifier: value,\n identifier: 42,\n"
533 );
534
535 scope.print_value("identifier", 42);
536 assert_eq!(
537 scope.output,
538 "test {\n identifier: value,\n identifier: 42,\nidentifier: 42\n"
539 );
540
541 scope.print("test\n");
542 assert_eq!(
543 scope.output,
544 "test {\n identifier: value,\n identifier: 42,\nidentifier: 42\ntest\n"
545 );
546
547 let test_data: Vec<u8> = get_test_data();
548 let test_data_hexdump: String = format_as_hexdump(&test_data, true);
549 let mut expected_string: String = String::from(
550 "test {\n identifier: value,\n identifier: 42,\nidentifier: 42\ntest\n",
551 );
552
553 scope.print_data("test data", 0, &test_data, 16, true);
554 expected_string.push_str("test data data of size: 16 at offset: 0 (0x00000000)\n");
555 expected_string.push_str(&test_data_hexdump);
556 assert_eq!(scope.output, expected_string);
557
558 scope.print_data_field("test data", &test_data);
559 expected_string.push_str(" test data\n");
560 expected_string.push_str(&test_data_hexdump);
561 assert_eq!(scope.output, expected_string);
562
563 let structure_string: String = test_debug_read_data(&test_data);
564
565 scope.print_structure(test_debug_read_data, &test_data);
566 expected_string.push_str(&structure_string);
567 assert_eq!(scope.output, expected_string);
568
569 scope.print_end();
570 expected_string.push_str("}\n\n");
571 assert_eq!(scope.output, expected_string);
572
573 Ok(())
574 }
575
576 #[test]
577 fn test_trace_scope_with_debug_output_disabled() -> Result<(), ErrorTrace> {
578 let mediator: Arc<Mediator> = Mediator::current();
579
580 let mut scope = DebugTraceScope {
581 mediator: &mediator,
582 debug_output: false,
583 output: String::new(),
584 };
585 assert!(!scope.debug_output);
586
587 scope.print("test\n");
588 assert_eq!(scope.output, "");
589
590 scope.print_start("test");
591 assert_eq!(scope.output, "");
592
593 scope.print_end();
594 assert_eq!(scope.output, "");
595
596 scope.print_field("identifier", "value");
597 assert_eq!(scope.output, "");
598
599 scope.print_value("identifier", 42);
600 assert_eq!(scope.output, "");
601
602 let test_data: Vec<u8> = get_test_data();
603
604 scope.print_data("test data", 0, &test_data, 16, true);
605 assert_eq!(scope.output, "");
606
607 scope.print_data_field("test data", &test_data);
608 assert_eq!(scope.output, "");
609
610 scope.print_structure(test_debug_read_data, &test_data);
611 assert_eq!(scope.output, "");
612
613 Ok(())
614 }
615
616 #[test]
617 fn test_static_scope_with_debug_output_enabled() {
618 Mediator::new(true).make_current();
619
620 DebugTrace::static_scope(|scope: &DebugTraceStaticScope<'_>| {
621 scope.print_start("test");
622 scope.print_field("value", 42);
623 scope.print_end();
624 });
625 }
626
627 #[test]
628 fn test_static_scope_with_debug_output_disabled() {
629 let was_called: Cell<bool> = Cell::new(false);
630
631 DebugTrace::static_scope(|scope: &DebugTraceStaticScope<'_>| {
632 _ = scope;
633 was_called.set(true);
634 });
635 assert!(!was_called.get());
636 }
637
638 #[test]
639 fn test_static_scope_print() {
640 Mediator::new(true).make_current();
641
642 DebugTrace::static_scope(|scope: &DebugTraceStaticScope<'_>| {
643 scope.print("test\n");
644 scope.print(String::from("test\n"));
645 scope.print(42);
646 });
647 }
648
649 #[test]
650 fn test_static_scope_print_data() {
651 Mediator::new(true).make_current();
652
653 let test_data: Vec<u8> = get_test_data();
654
655 DebugTrace::static_scope(|scope: &DebugTraceStaticScope<'_>| {
656 scope.print_data("test data", 0, &test_data, 16, false);
657 scope.print_data("test data", 0, &test_data, 16, true);
658 });
659 }
660
661 #[test]
662 fn test_static_scope_print_data_field() {
663 Mediator::new(true).make_current();
664
665 let test_data: Vec<u8> = get_test_data();
666
667 DebugTrace::static_scope(|scope: &DebugTraceStaticScope<'_>| {
668 scope.print_data_field("test data", &test_data);
669 });
670 }
671
672 #[test]
673 fn test_static_scope_print_structure() {
674 Mediator::new(true).make_current();
675
676 let test_data: Vec<u8> = get_test_data();
677
678 DebugTrace::static_scope(|scope: &DebugTraceStaticScope<'_>| {
679 scope.print_structure(test_debug_read_data, &test_data);
680 });
681 }
682
683 #[test]
684 fn test_static_scope_print_value() {
685 Mediator::new(true).make_current();
686
687 DebugTrace::static_scope(|scope: &DebugTraceStaticScope<'_>| {
688 scope.print_value("test", "value");
689 scope.print_value("test", 42);
690 });
691 }
692}