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::ansi(" @ ", 220, 16),
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        let fg=$crate::color::wrap($fg as usize) as usize;
371        $crate::step!(bg=fg, fg=$crate::color::invert_ansi(fg), length=$crate::color::term_cols(), $text)
372    }};
373    (bg=$bg:expr, fg=$fg:expr, $text:expr $(,)?) => {{
374        let bg=$crate::color::wrap($bg as usize) as usize;
375        let fg=$crate::color::wrap($fg as usize) as usize;
376        $crate::step!(bg=bg, fg=fg, length=$crate::color::term_cols(), $text)
377    }};
378    (length=$length:expr, $text:expr $(,)?) => {{
379        let (bg, fg) = $crate::color::couple(line!() as usize);
380        $crate::step!(bg=bg, fg=fg, length=$length, $text)
381    }};
382    (bg=$bg:expr, fg=$fg:expr, length=$length:expr, $text:expr $(,)?) => {{
383        let bg = $crate::color::wrap($bg as usize) as usize;
384        let fg = $crate::color::wrap($fg as usize) as usize;
385
386        let text = $text.to_string();
387        let bar = $crate::color::ansi(
388            " ".repeat($length),
389            $fg as usize,
390            $bg as usize,
391        );
392        eprintln!(
393            "\n{}",
394            [
395                bar.clone(),
396                $crate::color::ansi(
397                    $crate::color::pad_columns(
398                        [
399                            $crate::function_name!(),
400                            [
401                                file!().to_string(),
402                                line!().to_string(),
403                            ].join(":")
404                        ].join(" ").to_string()
405                    ),
406                    $fg as usize,
407                    $bg as usize,
408                ),
409                $crate::color::ansi(
410                    $crate::color::pad_columns(
411                        if text.is_empty() { String::new() } else { format!("{}", text) }
412                    ),
413                    $bg as usize,
414                    $fg as usize,
415                ),
416                bar.clone(),
417            ].join("\n")
418        );
419    }};
420    (length=$length:expr, $text:expr, $( $arg:expr ),* $(,)? ) => {{
421        $crate::step!(length=$length, format_args!($text, $($arg,)*))
422    }};
423    () => {{
424        $crate::step!("")
425    }};
426}
427/// colorfully steps through code debugging given expressions
428#[macro_export]
429macro_rules! step_dbg {
430    (bg=$bg:expr, fg=$fg:expr, length=$length:expr, $($arg:expr),* $(,)?) => {{
431        let bg=$crate::color::wrap($bg as usize);
432        let fg=$crate::color::wrap($fg as usize);
433        let text = format!("{}{}", $crate::reset(""), [
434            $($crate::indent!(format!("{} = {}", $crate::color::auto(stringify!($arg)), $crate::color::auto(format!("{:#?}", $arg))))),*
435        ].join("\n"));
436        $crate::step!(bg=bg, fg=fg, length=$length, text);
437    }};
438    (bg=$bg:expr, fg=$fg:expr, $($arg:expr),* $(,)?) => {{
439        let bg=$crate::color::wrap($bg as usize);
440        let fg=$crate::color::wrap($fg as usize);
441        $crate::step_dbg!(bg=bg, fg=fg, length=$crate::color::term_cols(), $($arg),*)
442    }};
443    (fg=$fg:expr, $($arg:expr),* $(,)?) => {{
444        let fg=$crate::color::wrap($fg as usize) as usize;
445        $crate::step_dbg!(bg=fg, fg=$crate::color::invert_ansi(fg), length=$crate::color::term_cols(), $($arg),*)
446    }};
447    ($($arg:expr),* $(,)?) => {{
448        let fg=$crate::color::wrap(line!() as usize) as usize;
449        $crate::step_dbg!(bg=fg, fg=$crate::color::invert_ansi(fg), length=$crate::color::term_cols(), $($arg),*)
450    }};
451    () => {{
452        $crate::step!("")
453    }};
454}
455
456/// colorfully prints an admonition
457#[macro_export]
458macro_rules! admonition {
459    ($color:literal, $message:expr) => {
460        $crate::admonition!($color, "{}", $message);
461    };
462    ($color:literal, $title:literal, $message:expr) => {
463        $crate::admonition!($color, title=$title, $message);
464    };
465
466    ($color:literal, title=$title:literal, $message:expr) => {
467        $crate::admonition!($color, title=$title, "{}", $message);
468    };
469    ($color:literal, title=$title:literal, $format:literal, $($arg:expr),* $(,)?) => {{
470        use crate::color;
471        eprintln!(
472            "\n{}",
473            [
474                color::ansi(
475                    format!("{}:{} {}", crate::function_name!(), line!(), $title),
476                    color::invert_ansi($color).into(),
477                    $color,
478                ),
479                color::ansi(
480                    format!($format, $($arg),*),
481                    $color,
482                    color::invert_ansi($color).into(),
483                )
484            ]
485            .join(" ")
486        );
487    }};
488    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {{
489        use crate::color;
490        eprintln!(
491            "\n{}",
492            [
493                color::ansi(
494                    format!("{}:{}", crate::function_name!(), line!()),
495                    color::invert_ansi($color).into(),
496                    $color,
497                ),
498                color::ansi(
499                    format!($format, $($arg),*),
500                    $color,
501                    color::invert_ansi($color).into(),
502                )
503            ]
504            .join(" ")
505        );
506    }};
507}
508
509/// colorfully prints a "WARN" admonition
510#[macro_export]
511macro_rules! warn {
512    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
513        $crate::admonition!($color, title="WARNING", $format, $($arg),*);
514    };
515    ($color:literal, $message:expr) => {
516        $crate::admonition!($color, title="WARNING", $message);
517    };
518    ($message:expr) => {
519        $crate::warn!(220, $message);
520    };
521}
522
523/// colorfully prints an "INFO" admonition
524#[macro_export]
525macro_rules! info {
526    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
527        $crate::admonition!($color, title="INFO", $format, $($arg),*);
528    };
529    ($color:literal, $message:expr) => {
530        $crate::admonition!($color, title="INFO", $message);
531    };
532    ($message:expr) => {
533        $crate::info!(74, $message);
534    };
535}
536
537/// colorfully formats a [u8] as hex => binary => decimal (=> char (if ascii))
538#[macro_export]
539macro_rules! format_byte {
540    (hex_only, $byte:expr $(,)? ) => {{
541        use $crate::color::{auto, fore, from_byte, pad};
542        let color = $crate::color::from_byte($byte);
543        $crate::color::fore(format!("0x{:02x}", $byte), color.into())
544    }};
545    (hex, $byte:expr $(,)? ) => {{
546        use $crate::color::{auto, fore, from_bytes, pad};
547        let color = $crate::color::from_bytes(&[$byte]);
548        [
549            $crate::color::fore(format!("0x{:02x}", $byte), color.into()),
550            if $byte < 127 {
551                $crate::color::fore(
552                    format!("{:#?}", char::from($byte).to_string()),
553                    color.into(),
554                )
555            } else {
556                String::new()
557            },
558        ]
559        .iter()
560        .filter(|c| !c.is_empty())
561        .map(String::from)
562        .collect::<Vec<String>>()
563        .join(" => ")
564    }};
565    (bin, $byte:expr $(,)? ) => {{
566        use $crate::color::{auto, fore, from_bytes, pad};
567        let color = $crate::color::from_bytes(&[$byte]);
568        [
569            $crate::color::fore(format!("0b{:08b}", $byte), color.into()),
570            if $byte < 127 {
571                $crate::color::fore(
572                    format!("{:#?}", char::from($byte).to_string()),
573                    color.into(),
574                )
575            } else {
576                String::new()
577            },
578        ]
579        .iter()
580        .filter(|c| !c.is_empty())
581        .map(String::from)
582        .collect::<Vec<String>>()
583        .join(" => ")
584    }};
585    ($byte:expr $(,)? ) => {{
586        use $crate::color::{auto, fore, from_bytes, pad};
587        let color = $crate::color::from_bytes(&[$byte]);
588        [
589            $crate::color::fore(format!("0x{:02x}", $byte), color.into()),
590            $crate::color::fore(format!("0b{:08b}", $byte), color.into()),
591            $crate::color::fore(format!("{:#?}", $byte), color.into()),
592            if $byte < 127 {
593                $crate::color::fore(
594                    format!("{:#?}", char::from($byte).to_string()),
595                    color.into(),
596                )
597            } else {
598                String::new()
599            },
600        ]
601        .iter()
602        .filter(|c| !c.is_empty())
603        .map(String::from)
604        .collect::<Vec<String>>()
605        .join(" => ")
606    }};
607}
608/// [std::dbg] equivalent for u8 which uses [format_byte] to display the byte
609#[macro_export]
610macro_rules! dbg_byte {
611    ($byte:expr $(,)? ) => {{
612        use $crate::color::{auto, fore, from_display};
613        let color = $crate::color::from_display($byte);
614        $crate::step!(format!(
615            "{} = {}",
616            $crate::color::auto(stringify!($byte)),
617            $crate::format_byte!($byte)
618        ));
619        $byte
620    }};
621}
622
623/// [std::dbg] equivalent for `&[u8]` which uses [format_bytes] to display the byte slice
624#[macro_export]
625macro_rules! dbg_bytes {
626    ($slice:expr $(,)? ) => {{
627        use $crate::color::{auto, back, fore, from_display, pad};
628        $crate::step!($crate::indent!(format!(
629            "{} = {}",
630            $crate::color::auto(stringify!($slice)),
631            $crate::format_bytes!($slice)
632        )));
633        $slice
634    }};
635}
636/// [std::dbg] equivalent for `&[u8]` which uses [format_bytes] to display the byte slice in base 16 and string
637#[macro_export]
638macro_rules! dbg_bytes_str {
639    ($slice:expr $(,)? ) => {{
640        use $crate::color::{auto, back, fore, from_display, pad};
641        use $crate::indent;
642        eprintln!(
643            "\n{}",
644            [
645                $crate::location!(begin),
646                String::new(),
647                $crate::color::auto(stringify!($slice)),
648                $crate::format_bytes_str!($slice),
649                String::new(),
650                $crate::location!(end),
651            ]
652            .join("\n")
653        );
654        $slice
655    }};
656}
657/// [std::dbg_bytes_str] equivalent which only displays debug message if the given bytes are valid UTF-8
658#[macro_export]
659macro_rules! dbg_bytes_if_str {
660    ($slice:expr $(,)? ) => {
661        if let Ok(c) = std::str::from_utf8($slice) {
662            $crate::dbg_bytes!($slice)
663        } else {
664            $slice
665        }
666    };
667}
668/// colorfully formats a slice or vector of [u8] as hex => binary => decimal (=> char (if ascii))
669#[macro_export]
670macro_rules! format_bytes {
671    ($slice:expr $(,)? ) => {
672        $crate::format_bytes!($slice, " => ");
673    };
674    (hex, $slice:expr $(,)? ) => {
675        $crate::format_bytes!(hex, $slice, " => ");
676    };
677    (bin, $slice:expr $(,)? ) => {
678        $crate::format_bytes!(bin, $slice, " => ");
679    };
680    ($slice:expr, $sep:literal $(,)? ) => {{
681        [
682            format!(
683                "[\n{}]",
684                $slice
685                    .iter()
686                    .map(Clone::clone)
687                    .map(|byte| format!(
688                        "{}, // {}\n",
689                        $crate::indent!($crate::format_byte!(byte)),
690                        $crate::color::fore(format!("{:#?}", char::from(byte).to_string()), 237),
691                    ))
692                    .collect::<Vec<String>>()
693                    .join("")
694            ),
695            format!("{} bytes", $slice.len()),
696            std::str::from_utf8($slice)
697                .map(|s| {
698                    let chars = s.chars().collect::<Vec<char>>();
699                    format!(
700                        "\"{s}\" => {} chars => [{}]",
701                        chars.len(),
702                        chars
703                            .iter()
704                            .map(|c| format!("{c:?}"))
705                            .collect::<Vec<String>>()
706                            .join(", ")
707                    )
708                })
709                .unwrap_or_default(),
710        ]
711        .iter()
712        .filter(|c| !c.is_empty())
713        .map(String::from)
714        .collect::<Vec<String>>()
715        .join($sep.to_string().as_str())
716    }};
717    (hex, $slice:expr, $sep:literal $(,)? ) => {{
718        [
719            format!(
720                "[\n{}]",
721                $slice
722                    .iter()
723                    .map(Clone::clone)
724                    .map(|byte| format!(
725                        "{}, // {}\n",
726                        $crate::indent!($crate::format_byte!(hex, byte)),
727                        $crate::color::fore(format!("{:#?}", char::from(byte).to_string()), 237),
728                    ))
729                    .collect::<Vec<String>>()
730                    .join("")
731            ),
732            std::str::from_utf8($slice)
733                .map(|s| format!("{s:#?}"))
734                .unwrap_or_default(),
735        ]
736        .iter()
737        .filter(|c| !c.is_empty())
738        .map(String::from)
739        .collect::<Vec<String>>()
740        .join($sep.to_string().as_str())
741    }};
742    (bin, $slice:expr, $sep:literal $(,)? ) => {{
743        [
744            format!(
745                "[\n{}]",
746                $slice
747                    .iter()
748                    .map(Clone::clone)
749                    .map(|byte| format!(
750                        "{}, // {}\n",
751                        $crate::indent!($crate::format_byte!(bin, byte)),
752                        $crate::color::fore(format!("{:#?}", char::from(byte).to_string()), 237),
753                    ))
754                    .collect::<Vec<String>>()
755                    .join("")
756            ),
757            std::str::from_utf8($slice)
758                .map(|s| format!("{s:#?}"))
759                .unwrap_or_default(),
760        ]
761        .iter()
762        .filter(|c| !c.is_empty())
763        .map(String::from)
764        .collect::<Vec<String>>()
765        .join($sep.to_string().as_str())
766    }};
767}
768
769/// colorfully formats a slice or vector of [u8] as hex
770#[macro_export]
771macro_rules! format_bytes_str {
772    ($slice:expr $(,)? ) => {
773        $crate::format_bytes_str!($slice, " => ");
774    };
775    ($slice:expr, $sep:literal $(,)? ) => {{
776        [
777            format!(
778                "[{}]",
779                $slice
780                    .iter()
781                    .map(Clone::clone)
782                    .map(|byte| $crate::format_byte!(hex_only, byte))
783                    .collect::<Vec<String>>()
784                    .join(", ")
785            ),
786            std::str::from_utf8($slice)
787                .map(|s| format!("{s:#?}"))
788                .unwrap_or_default(),
789        ]
790        .iter()
791        .filter(|c| !c.is_empty())
792        .map(String::from)
793        .collect::<Vec<String>>()
794        .join($sep.to_string().as_str())
795    }};
796}