debug_et_diagnostics/
macros.rs

1/// colofully prints the "location" of the macro call (function name, filename and line number) in the code
2#[macro_export]
3macro_rules! location {
4    () => {{
5        let location = format!(
6            "{}{}{}:{}",
7            $crate::color::auto($crate::function_name!()),
8            $crate::color::fore(" @ ", 220),
9            $crate::filename!(),
10            $crate::color::auto(line!().to_string())
11        );
12        location
13    }};
14    (begin) => {
15        $crate::tag!([
16            $crate::color::auto(format!("in function")),
17            $crate::location!()
18        ]
19        .join(" "))
20    };
21    (end) => {
22        $crate::tag!([
23            $crate::color::auto(format!("from function")),
24            $crate::location!()
25        ]
26        .join(" "))
27    };
28    (unexpected) => {
29        [
30            $crate::color::fore(format!("<unexpected branch in function"), 160),
31            $crate::location!(),
32            $crate::color::fore(format!(">"), 160),
33        ]
34        .join(" ")
35    };
36}
37/// colofully prints the filename of the macro call
38#[macro_export]
39macro_rules! filename {
40    () => {{
41        let mut parts = file!()
42            .split(std::path::MAIN_SEPARATOR_STR)
43            .map(String::from)
44            .map(|part| $crate::color::auto(part.to_string()))
45            .collect::<Vec<String>>();
46        let (folder, filename) = if parts.len() > 1 {
47            let last = parts.remove(parts.len() - 1);
48            let parts = parts.iter().map(Clone::clone).collect::<Vec<String>>();
49            (parts, last)
50        } else {
51            (Vec::<String>::new(), parts[0].to_string())
52        };
53        if folder.len() > 1 {
54            format!(
55                "{}{}{}",
56                filename,
57                $crate::color::fore(" in ", 7),
58                folder.join(std::path::MAIN_SEPARATOR_STR)
59            )
60        } else {
61            filename
62        }
63    }};
64}
65/// colorfully wraps the given text in "<", ">": "<{text}>"
66#[macro_export]
67macro_rules! tag {
68
69    (@open, $arg:expr) => {{
70        $crate::tag!(@open, $arg, 7, @color=fore)
71    }};
72    (@open, $arg:expr, @color=auto) => {{
73        $crate::tag!(@open, $arg, 7, @color=auto)
74    }};
75    (@open, $arg:expr, @color=fore) => {{
76        $crate::tag!(@open, $arg, 7, @color=fore)
77    }};
78    (@open, $arg:expr, @color=$color:expr) => {{
79        $crate::tag!(@open, $arg, 7, @color=$color)
80    }};
81
82    (@open, $arg:expr, $color:expr) => {{
83        $crate::tag!(@open, $arg, $color, @color=$color)
84    }};
85    (@open, $arg:expr, $color:expr, @color=auto) => {{
86        let auto_color = $crate::color::from_display($arg) as usize;
87        format!(
88            "{}{}{}",
89            $crate::color::fore("<", $color),
90            $crate::color::fore($arg, auto_color),
91            $crate::color::fore(">", $color),
92        )
93    }};
94    (@open, $arg:expr, $color:expr, @color=fore) => {{
95        format!(
96            "{}{}{}",
97            $crate::color::fore("<", $color),
98            $crate::color::fore($arg, $color),
99            $crate::color::fore(">", $color),
100        )
101    }};
102    (@open, $arg:expr, $color:expr, @color=$fore:expr) => {{
103        format!(
104            "{}{}{}",
105            $crate::color::fore("<", $color),
106            $crate::color::fore($arg, $fore),
107            $crate::color::fore(">", $color),
108        )
109    }};
110
111    (@close, $arg:expr) => {{
112        $crate::tag!(@close, $arg, 7, @color=fore)
113    }};
114    (@close, $arg:expr, @color=auto) => {{
115        $crate::tag!(@close, $arg, 7, @color=auto)
116    }};
117    (@close, $arg:expr, @color=fore) => {{
118        $crate::tag!(@close, $arg, 7, @color=fore)
119    }};
120    (@close, $arg:expr, @color=$color:expr) => {{
121        $crate::tag!(@close, $arg, 7, @color=$color)
122    }};
123
124    (@close, $arg:expr, $color:expr) => {{
125        $crate::tag!(@close, $arg, $color, @color=$color)
126    }};
127    (@close, $arg:expr, $color:expr, @color=auto) => {{
128        let auto_color = $crate::color::from_display($arg) as usize;
129        format!(
130            "{}{}{}",
131            $crate::color::fore("</", $color),
132            $crate::color::fore($arg, auto_color),
133            $crate::color::fore(">", $color),
134        )
135    }};
136    (@close, $arg:expr, $color:expr, @color=fore) => {{
137        format!(
138            "{}{}{}",
139            $crate::color::fore("</", $color),
140            $crate::color::fore($arg, $color),
141            $crate::color::fore(">", $color),
142        )
143    }};
144    (@close, $arg:expr, $color:expr, @color=$fore:expr) => {{
145        format!(
146            "{}{}{}",
147            $crate::color::fore("</", $color),
148            $crate::color::fore($arg, $fore),
149            $crate::color::fore(">", $color),
150        )
151    }};
152
153
154    (@wrap, $tag:expr, $arg:expr) => {{
155        [
156            $crate::tag!(@open, $tag),
157            $crate::indent!($crate::color::fore($arg, 7)),
158            $crate::tag!(@close, $tag),
159        ].join("\n").to_string()
160    }};
161    (@wrap, $tag:expr, $arg:expr, @color=auto) => {{
162        [
163            $crate::tag!(@open, $tag, 7, @color=auto),
164            $crate::indent!($crate::color::auto($arg)),
165            $crate::tag!(@close, $tag, 7, @color=auto),
166        ].join("\n").to_string()
167
168    }};
169    (@wrap, $tag:expr, $arg:expr, @color=fore) => {{
170        [
171            $crate::tag!(@open, $tag, 7, @color=fore),
172            $crate::indent!($crate::color::fore($arg, 7)),
173            $crate::tag!(@close, $tag, 7, @color=fore),
174
175        ].join("\n").to_string()
176    }};
177    (@wrap, $tag:expr, $arg:expr, @color=$color:expr) => {{
178        [
179            $crate::tag!(@open, $arg, $color, @color=$color),
180            $crate::indent!($crate::color::fore($arg, $color)),
181            $crate::tag!(@close, $arg, $color, @color=$color),
182        ].join("\n").to_string()
183    }};
184
185    (@wrap, $tag:expr, $arg:expr, $color:expr) => {{
186        [
187            $crate::tag!(@open, $tag, $color, @color=$color),
188            $crate::indent!($crate::color::fore($arg, $color)),
189            $crate::tag!(@close, $tag, $color, @color=$color),
190        ].join("\n").to_string()
191    }};
192    (@wrap, $tag:expr, $arg:expr, $color:expr, @color=auto) => {{
193        let auto_tag_color = $crate::color::from_display($tag) as usize;
194        let auto_arg_color = $crate::color::from_display($arg) as usize;
195        [
196            $crate::tag!(@open, $tag, $color, @color=auto_tag_color),
197            $crate::indent!($crate::color::fore($arg, auto_arg_color)),
198            $crate::tag!(@close, $tag, $color, @color=auto_tag_color),
199        ].join("\n").to_string()
200    }};
201    (@wrap, $tag:expr, $arg:expr, $color:expr, @color=fore) => {{
202        [
203            $crate::tag!(@open, $tag, $color, @color=fore),
204            $crate::indent!($crate::color::fore($arg, $color)),
205            $crate::tag!(@close, $tag, $color, @color=fore),
206        ].join("\n").to_string()
207    }};
208    (@wrap, $tag:expr, $arg:expr, $color:expr, @color=$fore:expr) => {{
209        [
210            $crate::tag!(@open, $tag, $color, @color=$fore),
211            $crate::indent!($crate::color::fore($arg, $color)),
212            $crate::tag!(@close, $tag, $color, @color=$fore),
213        ].join("\n").to_string()
214    }};
215
216    // (@wrap, $tag:expr, $arg:expr) => {{
217    //     [
218    //         $crate::tag!(@open, $arg, 7, @color=fore)
219    //     ].join("")
220    // }};
221    // (@wrap, $tag:expr, $arg:expr, $color:expr) => {{
222    //     $crate::tag!(@wrap, $arg, $color, @color=$color)
223    // }};
224    // (@wrap, $tag:expr, $arg:expr, @color=auto) => {{
225    //     $crate::tag!(@wrap, $arg, 7, @color=auto)
226    // }};
227    // (@wrap, $tag:expr, $arg:expr, $color:expr, @color=auto) => {{
228    //     $crate::tag!(@wrap, $arg, $color, @color=auto)
229    // }};
230    // (@wrap, $tag:expr, $arg:expr, $color:expr, @color=auto) => {{
231    //     let auto_color = $crate::color::from_display($arg);
232    //     format!(
233    //         "{}{}{}",
234    //         $crate::color::fore("<", $color),
235    //         $crate::color::fore($arg, auto_color),
236    //         $crate::color::fore(">", $color),
237    //     )
238    // }};
239    // (@wrap, $tag:expr, $arg:expr, $color:expr, @color=fore) => {{
240    //     format!(
241    //         "{}{}{}",
242    //         $crate::color::fore("<", $color),
243    //         $crate::color::fore($arg, $color),
244    //         $crate::color::fore(">", $color),
245    //     )
246    // }};
247    // (@wrap, $tag:expr, $arg:expr, $color:expr, @color=$fore:expr) => {{
248    //     format!(
249    //         "{}{}{}",
250    //         $crate::color::fore("<", $color),
251    //         $crate::color::fore($arg, $fore),
252    //         $crate::color::fore(">", $color),
253    //     )
254    // }};
255
256
257
258
259
260    ($arg:expr) => {{
261        $crate::tag!(@open, $arg, 7)
262    }};
263    ($arg:expr, $color:expr) => {{
264        $crate::tag!(@open, $arg, $color)
265    }};
266    ($arg:expr, @color=auto) => {{
267        $crate::tag!(@open, $arg, 7, @color=auto)
268    }};
269    ($arg:expr, @color=fore) => {{
270        $crate::tag!(@open, $arg, 7, @color=fore)
271    }};
272    ($arg:expr, @color=$fore:expr) => {{
273        $crate::tag!(@open, $arg, 7, @color=$fore)
274    }};
275    ($arg:expr, $color:expr, @color=$fore:expr) => {{
276        $crate::tag!(@open, $arg, $color, @color=$fore)
277    }};
278
279}
280
281/// colorful alternative to [std::dbg]
282#[macro_export]
283macro_rules! dbg {
284    ($arg:expr $(,)? ) => {{
285        eprintln!("{}", $crate::format_dbg_location!($arg));
286        $arg
287    }};
288    ($( $arg:expr ),* $(,)? ) => {{
289        eprintln!("{}", $crate::format_dbg_location!($($arg),*));
290    }};
291}
292
293#[macro_export]
294macro_rules! format_dbg {
295    ($arg:expr $(,)? ) => {{
296        $crate::indent!(
297                format!(
298                    "{} = {}\n",
299                    $crate::color::auto(stringify!(&$arg)),
300                    $crate::color::auto(format!("{:#?}", &$arg))))
301
302    }};
303    ($( $arg:expr ),* $(,)? ) => {{
304        [$($crate::format_dbg!($arg)),*].join("\n")
305    }};
306}
307#[macro_export]
308macro_rules! format_dbg_location {
309    ($arg:expr $(,)? ) => {{
310        format!("{}", $crate::color::reset([$crate::location!(begin), $crate::format_dbg!($arg), $crate::location!(end)].join("\n")))
311    }};
312    ($( $arg:expr ),* $(,)? ) => {{
313        [$crate::location!(begin), $($crate::format_dbg!($arg)),*, $crate::location!(end)].join("\n")
314    }};
315}
316
317/// indents an implementor of [std::fmt::Display]
318#[macro_export]
319macro_rules! indent {
320    ($indentation:literal, $obj:expr) => {{
321        format!("{}", $obj)
322            .lines()
323            .map(|line| format!("{}{}", " ".repeat($indentation), line))
324            .collect::<Vec<String>>()
325            .join("\n")
326    }};
327    ($obj:expr) => {{
328        $crate::indent!(4, $obj)
329    }};
330}
331/// indents an implementor of [std::fmt::Debug]
332#[macro_export]
333macro_rules! indent_objdump {
334    ($indentation:literal, $obj:expr) => {{
335        format!("{:#?}", $obj)
336            .lines()
337            .map(|line| format!("{}{}", " ".repeat($indentation), line))
338            .collect::<Vec<String>>()
339            .join("\n")
340    }};
341    ($obj:expr) => {{
342        $crate::indent_objdump!(4, $obj)
343    }};
344}
345
346/// returns a [String] with the name of the function calling the macro
347#[macro_export]
348macro_rules! function_name {
349    () => {{
350        fn f() {}
351        fn type_name_of<T>(_: T) -> &'static str {
352            std::any::type_name::<T>()
353        }
354        let name = type_name_of(f);
355        let name = name
356            .strip_suffix("::f")
357            .unwrap()
358            .replace(format!("{}::", module_path!()).as_str(), "");
359        name
360    }};
361}
362
363/// colorfully steps through code
364#[macro_export]
365macro_rules! step {
366    ($text:expr $(,)?) => {{
367        $crate::step!(length=$crate::color::term_cols(), $text)
368    }};
369    (fg=$fg:expr, $text:expr $(,)?) => {{
370        $crate::step!(bg=$fg, fg=$crate::color::invert_bw($fg), length=$crate::color::term_cols(), $text)
371    }};
372    (bg=$bg:expr, fg=$fg:expr, $text:expr $(,)?) => {{
373        $crate::step!(bg=$bg, fg=$fg, length=$crate::color::term_cols(), $text)
374    }};
375    (length=$length:expr, $text:expr $(,)?) => {{
376        let (bg, fg) = $crate::color::couple(line!() as usize);
377        $crate::step!(bg=bg, fg=fg, length=$length, $text)
378    }};
379    (bg=$bg:expr, fg=$fg:expr, length=$length:expr, $text:expr $(,)?) => {{
380        let bg = $crate::color::wrap($bg as usize);
381        let fg = $crate::color::wrap($fg as usize);
382
383        let text = $text.to_string();
384        let bar = $crate::color::ansi(
385            " ".repeat($length),
386            $fg as usize,
387            $bg as usize,
388        );
389        eprintln!(
390            "\n{}",
391            [
392                bar.clone(),
393                $crate::color::ansi(
394                    $crate::color::pad_columns(
395                        [
396                            $crate::function_name!(),
397                            [
398                                file!().to_string(),
399                                line!().to_string(),
400                            ].join(":")
401                        ].join(" ").to_string()
402                    ),
403                    $fg as usize,
404                    $bg as usize,
405                ),
406                $crate::color::ansi(
407                    $crate::color::pad_columns(
408                        if text.is_empty() { String::new() } else { format!("{}", text) }
409                    ),
410                    $bg as usize,
411                    $fg as usize,
412                ),
413                bar.clone(),
414            ].join("\n")
415        );
416    }};
417    (length=$length:expr, $text:expr, $( $arg:expr ),* $(,)? ) => {{
418        $crate::step!(length=$length, format_args!($text, $($arg,)*))
419    }};
420    () => {{
421        $crate::step!("")
422    }};
423}
424/// colorfully steps through code debugging given expressions
425#[macro_export]
426macro_rules! step_dbg {
427    (bg=$bg:expr, fg=$fg:expr, length=$length:expr, $($arg:expr),* $(,)?) => {{
428        let text = format!("{}", [
429            $($crate::indent!(format!("{} = {}", $crate::color::auto(stringify!($arg)), $crate::color::auto(format!("{:#?}", $arg))))),*
430        ].join("\n"));
431        $crate::step!(bg=$bg, fg=$fg, length=$length, text);
432    }};
433    (bg=$bg:expr, fg=$fg:expr, $($arg:expr),* $(,)?) => {{
434        $crate::step_dbg!(bg=$bg, fg=$fg, length=$crate::color::term_cols(), $($arg),*)
435    }};
436    (fg=$fg:expr, $($arg:expr),* $(,)?) => {{
437        $crate::step_dbg!(bg=$fg, fg=$crate::color::invert_bw($fg), length=$crate::color::term_cols(), $($arg),*)
438    }};
439    ($($arg:expr),* $(,)?) => {{
440        let fg=$crate::color::wrap(line!() as usize);
441        $crate::step_dbg!(bg=fg, fg=$crate::color::invert_bw(fg), length=$crate::color::term_cols(), $($arg),*)
442    }};
443    () => {{
444        $crate::step!("")
445    }};
446}
447
448/// colorfully prints an admonition
449#[macro_export]
450macro_rules! admonition {
451    ($color:literal, $message:expr) => {
452        $crate::admonition!($color, "{}", $message);
453    };
454    ($color:literal, $title:literal, $message:expr) => {
455        $crate::admonition!($color, title=$title, $message);
456    };
457
458    ($color:literal, title=$title:literal, $message:expr) => {
459        $crate::admonition!($color, title=$title, "{}", $message);
460    };
461    ($color:literal, title=$title:literal, $format:literal, $($arg:expr),* $(,)?) => {{
462        use crate::color;
463        eprintln!(
464            "\n{}",
465            [
466                color::ansi(
467                    format!("{}:{} {}", crate::function_name!(), line!(), $title),
468                    color::invert_bw($color).into(),
469                    $color,
470                ),
471                color::ansi(
472                    format!($format, $($arg),*),
473                    $color,
474                    color::invert_bw($color).into(),
475                )
476            ]
477            .join(" ")
478        );
479    }};
480    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {{
481        use crate::color;
482        eprintln!(
483            "\n{}",
484            [
485                color::ansi(
486                    format!("{}:{}", crate::function_name!(), line!()),
487                    color::invert_bw($color).into(),
488                    $color,
489                ),
490                color::ansi(
491                    format!($format, $($arg),*),
492                    $color,
493                    color::invert_bw($color).into(),
494                )
495            ]
496            .join(" ")
497        );
498    }};
499}
500
501/// colorfully prints a "WARN" admonition
502#[macro_export]
503macro_rules! warn {
504    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
505        $crate::admonition!($color, title="WARNING", $format, $($arg),*);
506    };
507    ($color:literal, $message:expr) => {
508        $crate::admonition!($color, title="WARNING", $message);
509    };
510    ($message:expr) => {
511        $crate::warn!(220, $message);
512    };
513}
514
515/// colorfully prints an "INFO" admonition
516#[macro_export]
517macro_rules! info {
518    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
519        $crate::admonition!($color, title="INFO", $format, $($arg),*);
520    };
521    ($color:literal, $message:expr) => {
522        $crate::admonition!($color, title="INFO", $message);
523    };
524    ($message:expr) => {
525        $crate::info!(74, $message);
526    };
527}
528
529/// colorfully formats a [u8] as hex => binary => decimal (=> char (if ascii))
530#[macro_export]
531macro_rules! format_byte {
532    (hex_only, $byte:expr $(,)? ) => {{
533        use $crate::color::{auto, fore, from_byte, pad};
534        let color = $crate::color::from_byte($byte);
535        $crate::color::fore(format!("0x{:02x}", $byte), color.into())
536    }};
537    (hex, $byte:expr $(,)? ) => {{
538        use $crate::color::{auto, fore, from_bytes, pad};
539        let color = $crate::color::from_bytes(&[$byte]);
540        [
541            $crate::color::fore(format!("0x{:02x}", $byte), color.into()),
542            if $byte < 127 {
543                $crate::color::fore(
544                    format!("{:#?}", char::from($byte).to_string()),
545                    color.into(),
546                )
547            } else {
548                String::new()
549            },
550        ]
551        .iter()
552        .filter(|c| !c.is_empty())
553        .map(String::from)
554        .collect::<Vec<String>>()
555        .join(" => ")
556    }};
557    (bin, $byte:expr $(,)? ) => {{
558        use $crate::color::{auto, fore, from_bytes, pad};
559        let color = $crate::color::from_bytes(&[$byte]);
560        [
561            $crate::color::fore(format!("0b{:08b}", $byte), color.into()),
562            if $byte < 127 {
563                $crate::color::fore(
564                    format!("{:#?}", char::from($byte).to_string()),
565                    color.into(),
566                )
567            } else {
568                String::new()
569            },
570        ]
571        .iter()
572        .filter(|c| !c.is_empty())
573        .map(String::from)
574        .collect::<Vec<String>>()
575        .join(" => ")
576    }};
577    ($byte:expr $(,)? ) => {{
578        use $crate::color::{auto, fore, from_bytes, pad};
579        let color = $crate::color::from_bytes(&[$byte]);
580        [
581            $crate::color::fore(format!("0x{:02x}", $byte), color.into()),
582            $crate::color::fore(format!("0b{:08b}", $byte), color.into()),
583            $crate::color::fore(format!("{:#?}", $byte), color.into()),
584            if $byte < 127 {
585                $crate::color::fore(
586                    format!("{:#?}", char::from($byte).to_string()),
587                    color.into(),
588                )
589            } else {
590                String::new()
591            },
592        ]
593        .iter()
594        .filter(|c| !c.is_empty())
595        .map(String::from)
596        .collect::<Vec<String>>()
597        .join(" => ")
598    }};
599}
600/// [std::dbg] equivalent for u8 which uses [format_byte] to display the byte
601#[macro_export]
602macro_rules! dbg_byte {
603    ($byte:expr $(,)? ) => {{
604        use $crate::color::{auto, fore, from_display};
605        let color = $crate::color::from_display($byte);
606        $crate::step!(format!(
607            "{} = {}",
608            $crate::color::auto(stringify!($byte)),
609            $crate::format_byte!($byte)
610        ));
611        $byte
612    }};
613}
614
615/// [std::dbg] equivalent for `&[u8]` which uses [format_bytes] to display the byte slice
616#[macro_export]
617macro_rules! dbg_bytes {
618    ($slice:expr $(,)? ) => {{
619        use $crate::color::{auto, back, fore, from_display, pad};
620        $crate::step!($crate::indent!(format!(
621            "{} = {}",
622            $crate::color::auto(stringify!($slice)),
623            $crate::format_bytes!($slice)
624        )));
625        $slice
626    }};
627}
628/// [std::dbg] equivalent for `&[u8]` which uses [format_bytes] to display the byte slice in base 16 and string
629#[macro_export]
630macro_rules! dbg_bytes_str {
631    ($slice:expr $(,)? ) => {{
632        use $crate::color::{auto, back, fore, from_display, pad};
633        use $crate::indent;
634        eprintln!(
635            "\n{}",
636            [
637                $crate::location!(begin),
638                String::new(),
639                $crate::color::auto(stringify!($slice)),
640                $crate::format_bytes_str!($slice),
641                String::new(),
642                $crate::location!(end),
643            ]
644            .join("\n")
645        );
646        $slice
647    }};
648}
649/// [std::dbg_bytes_str] equivalent which only displays debug message if the given bytes are valid UTF-8
650#[macro_export]
651macro_rules! dbg_bytes_if_str {
652    ($slice:expr $(,)? ) => {
653        if let Ok(c) = std::str::from_utf8($slice) {
654            $crate::dbg_bytes!($slice)
655        } else {
656            $slice
657        }
658    };
659}
660/// colorfully formats a slice or vector of [u8] as hex => binary => decimal (=> char (if ascii))
661#[macro_export]
662macro_rules! format_bytes {
663    ($slice:expr $(,)? ) => {
664        $crate::format_bytes!($slice, " => ");
665    };
666    (hex, $slice:expr $(,)? ) => {
667        $crate::format_bytes!(hex, $slice, " => ");
668    };
669    (bin, $slice:expr $(,)? ) => {
670        $crate::format_bytes!(bin, $slice, " => ");
671    };
672    ($slice:expr, $sep:literal $(,)? ) => {{
673        [
674            format!(
675                "[\n{}]",
676                $slice
677                    .iter()
678                    .map(Clone::clone)
679                    .map(|byte| format!(
680                        "{}, // {}\n",
681                        $crate::indent!($crate::format_byte!(byte)),
682                        $crate::color::fore(format!("{:#?}", char::from(byte).to_string()), 237),
683                    ))
684                    .collect::<Vec<String>>()
685                    .join("")
686            ),
687            format!("{} bytes", $slice.len()),
688            std::str::from_utf8($slice)
689                .map(|s| {
690                    let chars = s.chars().collect::<Vec<char>>();
691                    format!(
692                        "\"{s}\" => {} chars => [{}]",
693                        chars.len(),
694                        chars
695                            .iter()
696                            .map(|c| format!("{c:?}"))
697                            .collect::<Vec<String>>()
698                            .join(", ")
699                    )
700                })
701                .unwrap_or_default(),
702        ]
703        .iter()
704        .filter(|c| !c.is_empty())
705        .map(String::from)
706        .collect::<Vec<String>>()
707        .join($sep.to_string().as_str())
708    }};
709    (hex, $slice:expr, $sep:literal $(,)? ) => {{
710        [
711            format!(
712                "[\n{}]",
713                $slice
714                    .iter()
715                    .map(Clone::clone)
716                    .map(|byte| format!(
717                        "{}, // {}\n",
718                        $crate::indent!($crate::format_byte!(hex, byte)),
719                        $crate::color::fore(format!("{:#?}", char::from(byte).to_string()), 237),
720                    ))
721                    .collect::<Vec<String>>()
722                    .join("")
723            ),
724            std::str::from_utf8($slice)
725                .map(|s| format!("{s:#?}"))
726                .unwrap_or_default(),
727        ]
728        .iter()
729        .filter(|c| !c.is_empty())
730        .map(String::from)
731        .collect::<Vec<String>>()
732        .join($sep.to_string().as_str())
733    }};
734    (bin, $slice:expr, $sep:literal $(,)? ) => {{
735        [
736            format!(
737                "[\n{}]",
738                $slice
739                    .iter()
740                    .map(Clone::clone)
741                    .map(|byte| format!(
742                        "{}, // {}\n",
743                        $crate::indent!($crate::format_byte!(bin, byte)),
744                        $crate::color::fore(format!("{:#?}", char::from(byte).to_string()), 237),
745                    ))
746                    .collect::<Vec<String>>()
747                    .join("")
748            ),
749            std::str::from_utf8($slice)
750                .map(|s| format!("{s:#?}"))
751                .unwrap_or_default(),
752        ]
753        .iter()
754        .filter(|c| !c.is_empty())
755        .map(String::from)
756        .collect::<Vec<String>>()
757        .join($sep.to_string().as_str())
758    }};
759}
760
761/// colorfully formats a slice or vector of [u8] as hex
762#[macro_export]
763macro_rules! format_bytes_str {
764    ($slice:expr $(,)? ) => {
765        $crate::format_bytes_str!($slice, " => ");
766    };
767    ($slice:expr, $sep:literal $(,)? ) => {{
768        [
769            format!(
770                "[{}]",
771                $slice
772                    .iter()
773                    .map(Clone::clone)
774                    .map(|byte| $crate::format_byte!(hex_only, byte))
775                    .collect::<Vec<String>>()
776                    .join(", ")
777            ),
778            std::str::from_utf8($slice)
779                .map(|s| format!("{s:#?}"))
780                .unwrap_or_default(),
781        ]
782        .iter()
783        .filter(|c| !c.is_empty())
784        .map(String::from)
785        .collect::<Vec<String>>()
786        .join($sep.to_string().as_str())
787    }};
788}