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    ($arg:expr) => {{
69        $crate::tag!($arg, 7)
70    }};
71    (close, $arg:expr) => {{
72        $crate::tag!(close, $arg, 7)
73    }};
74    ($arg:expr, $color:literal) => {{
75        format!(
76            "{}{}{}",
77            $crate::color::fore("<", $color),
78            $crate::color::auto($arg),
79            $crate::color::fore(">", $color),
80        )
81    }};
82    (close, $arg:expr, $color:literal) => {{
83        format!(
84            "{}{}{}",
85            $crate::color::fore("</", $color),
86            $arg,
87            $crate::color::fore(">", $color),
88        )
89    }};
90}
91
92/// colorful alternative to [std::dbg]
93#[macro_export]
94macro_rules! dbg {
95    ($arg:expr $(,)? ) => {{
96        eprintln!("{}", $crate::format_dbg_location!($arg));
97        $arg
98    }};
99    ($( $arg:expr ),* $(,)? ) => {{
100        eprintln!("{}", $crate::format_dbg_location!($($arg),*));
101    }};
102}
103
104#[macro_export]
105macro_rules! format_dbg {
106    ($arg:expr $(,)? ) => {{
107        $crate::indent!(
108                format!(
109                    "{} = {}\n",
110                    $crate::color::auto(stringify!(&$arg)),
111                    $crate::color::auto(format!("{:#?}", &$arg))))
112
113    }};
114    ($( $arg:expr ),* $(,)? ) => {{
115        [$($crate::format_dbg!($arg)),*].join("\n")
116    }};
117}
118#[macro_export]
119macro_rules! format_dbg_location {
120    ($arg:expr $(,)? ) => {{
121        format!("{}", $crate::color::reset([$crate::location!(begin), $crate::format_dbg!($arg), $crate::location!(end)].join("\n")))
122    }};
123    ($( $arg:expr ),* $(,)? ) => {{
124        [$crate::location!(begin), $($crate::format_dbg!($arg)),*, $crate::location!(end)].join("\n")
125    }};
126}
127
128/// indents an implementor of [std::fmt::Display]
129#[macro_export]
130macro_rules! indent {
131    ($indentation:literal, $obj:expr) => {{
132        format!("{}", $obj)
133            .lines()
134            .map(|line| format!("{}{}", " ".repeat($indentation), line))
135            .collect::<Vec<String>>()
136            .join("\n")
137    }};
138    ($obj:expr) => {{
139        $crate::indent!(4, $obj)
140    }};
141}
142/// indents an implementor of [std::fmt::Debug]
143#[macro_export]
144macro_rules! indent_objdump {
145    ($indentation:literal, $obj:expr) => {{
146        format!("{:#?}", $obj)
147            .lines()
148            .map(|line| format!("{}{}", " ".repeat($indentation), line))
149            .collect::<Vec<String>>()
150            .join("\n")
151    }};
152    ($obj:expr) => {{
153        $crate::indent_objdump!(4, $obj)
154    }};
155}
156
157/// returns a [String] with the name of the function calling the macro
158#[macro_export]
159macro_rules! function_name {
160    () => {{
161        fn f() {}
162        fn type_name_of<T>(_: T) -> &'static str {
163            std::any::type_name::<T>()
164        }
165        let name = type_name_of(f);
166        let name = name
167            .strip_suffix("::f")
168            .unwrap()
169            .replace(format!("{}::", module_path!()).as_str(), "");
170        name
171    }};
172}
173
174/// colorfully steps through code
175#[macro_export]
176macro_rules! step {
177    ($text:expr $(,)?) => {{
178        $crate::step!(length=$crate::color::term_cols(), $text)
179    }};
180    (fg=$fg:expr, $text:expr $(,)?) => {{
181        $crate::step!(bg=$fg, fg=$crate::color::invert_bw($fg), length=$crate::color::term_cols(), $text)
182    }};
183    (bg=$bg:expr, fg=$fg:expr, $text:expr $(,)?) => {{
184        $crate::step!(bg=$bg, fg=$fg, length=$crate::color::term_cols(), $text)
185    }};
186    (length=$length:expr, $text:expr $(,)?) => {{
187        let (bg, fg) = $crate::color::couple(line!() as usize);
188        let text = $text.to_string();
189        let bar = $crate::color::ansi(
190            " ".repeat($length),
191            fg.into(),
192            bg.into(),
193        );
194        eprintln!(
195            "\n{}",
196            [
197                bar.clone(),
198                $crate::color::ansi(
199                    $crate::color::pad_columns(
200                        [
201                            $crate::function_name!(),
202                            [
203                                file!().to_string(),
204                                line!().to_string(),
205                            ].join(":")
206                        ].join(" ").to_string()
207                    ),
208                    fg.into(),
209                    bg.into(),
210                ),
211                $crate::color::ansi(
212                    $crate::color::pad_columns(
213                        if text.is_empty() { String::new() } else { format!("{}", text) }
214                    ),
215                    bg.into(),
216                    fg.into(),
217                ),
218                bar.clone(),
219            ].join("\n")
220        );
221
222    }};
223    (bg=$bg:expr, fg=$fg:expr, length=$length:expr, $text:expr $(,)?) => {{
224        let text = $text.to_string();
225        let bar = $crate::color::ansi(
226            " ".repeat($length),
227            $fg as usize,
228            $bg as usize,
229        );
230        eprintln!(
231            "\n{}",
232            [
233                bar.clone(),
234                $crate::color::ansi(
235                    $crate::color::pad_columns(
236                        [
237                            $crate::function_name!(),
238                            [
239                                file!().to_string(),
240                                line!().to_string(),
241                            ].join(":")
242                        ].join(" ").to_string()
243                    ),
244                    $fg as usize,
245                    $bg as usize,
246                ),
247                $crate::color::ansi(
248                    $crate::color::pad_columns(
249                        if text.is_empty() { String::new() } else { format!("{}", text) }
250                    ),
251                    $bg as usize,
252                    $fg as usize,
253                ),
254                bar.clone(),
255            ].join("\n")
256        );
257    }};
258    (length=$length:expr, $text:expr, $( $arg:expr ),* $(,)? ) => {{
259        $crate::step!(length=$length, format_args!($text, $($arg,)*))
260    }};
261    () => {{
262        $crate::step!("")
263    }};
264}
265
266/// colorfully prints an admonition
267#[macro_export]
268macro_rules! admonition {
269    ($color:literal, $message:expr) => {
270        $crate::admonition!($color, "{}", $message);
271    };
272    ($color:literal, $title:literal, $message:expr) => {
273        $crate::admonition!($color, title=$title, $message);
274    };
275
276    ($color:literal, title=$title:literal, $message:expr) => {
277        $crate::admonition!($color, title=$title, "{}", $message);
278    };
279    ($color:literal, title=$title:literal, $format:literal, $($arg:expr),* $(,)?) => {{
280        use crate::color;
281        eprintln!(
282            "\n{}",
283            [
284                color::ansi(
285                    format!("{}:{} {}", crate::function_name!(), line!(), $title),
286                    color::invert_bw($color).into(),
287                    $color,
288                ),
289                color::ansi(
290                    format!($format, $($arg),*),
291                    $color,
292                    color::invert_bw($color).into(),
293                )
294            ]
295            .join(" ")
296        );
297    }};
298    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {{
299        use crate::color;
300        eprintln!(
301            "\n{}",
302            [
303                color::ansi(
304                    format!("{}:{}", crate::function_name!(), line!()),
305                    color::invert_bw($color).into(),
306                    $color,
307                ),
308                color::ansi(
309                    format!($format, $($arg),*),
310                    $color,
311                    color::invert_bw($color).into(),
312                )
313            ]
314            .join(" ")
315        );
316    }};
317}
318
319/// colorfully prints a "WARN" admonition
320#[macro_export]
321macro_rules! warn {
322    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
323        $crate::admonition!($color, title="WARNING", $format, $($arg),*);
324    };
325    ($color:literal, $message:expr) => {
326        $crate::admonition!($color, title="WARNING", $message);
327    };
328    ($message:expr) => {
329        $crate::warn!(220, $message);
330    };
331}
332
333/// colorfully prints an "INFO" admonition
334#[macro_export]
335macro_rules! info {
336    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
337        $crate::admonition!($color, title="INFO", $format, $($arg),*);
338    };
339    ($color:literal, $message:expr) => {
340        $crate::admonition!($color, title="INFO", $message);
341    };
342    ($message:expr) => {
343        $crate::info!(74, $message);
344    };
345}
346
347/// colorfully formats a [u8] as hex => binary => decimal (=> char (if ascii))
348#[macro_export]
349macro_rules! format_byte {
350    (hex_only, $byte:expr $(,)? ) => {{
351        use $crate::color::{auto, fore, from_byte, pad};
352        let color = $crate::color::from_byte($byte);
353        $crate::color::fore(format!("0x{:02x}", $byte), color.into())
354    }};
355    (hex, $byte:expr $(,)? ) => {{
356        use $crate::color::{auto, fore, from_bytes, pad};
357        let color = $crate::color::from_bytes(&[$byte]);
358        [
359            $crate::color::fore(format!("0x{:02x}", $byte), color.into()),
360            if $byte < 127 {
361                $crate::color::fore(
362                    format!("{:#?}", char::from($byte).to_string()),
363                    color.into(),
364                )
365            } else {
366                String::new()
367            },
368        ]
369        .iter()
370        .filter(|c| !c.is_empty())
371        .map(String::from)
372        .collect::<Vec<String>>()
373        .join(" => ")
374    }};
375    (bin, $byte:expr $(,)? ) => {{
376        use $crate::color::{auto, fore, from_bytes, pad};
377        let color = $crate::color::from_bytes(&[$byte]);
378        [
379            $crate::color::fore(format!("0b{:08b}", $byte), color.into()),
380            if $byte < 127 {
381                $crate::color::fore(
382                    format!("{:#?}", char::from($byte).to_string()),
383                    color.into(),
384                )
385            } else {
386                String::new()
387            },
388        ]
389        .iter()
390        .filter(|c| !c.is_empty())
391        .map(String::from)
392        .collect::<Vec<String>>()
393        .join(" => ")
394    }};
395    ($byte:expr $(,)? ) => {{
396        use $crate::color::{auto, fore, from_bytes, pad};
397        let color = $crate::color::from_bytes(&[$byte]);
398        [
399            $crate::color::fore(format!("0x{:02x}", $byte), color.into()),
400            $crate::color::fore(format!("0b{:08b}", $byte), color.into()),
401            $crate::color::fore(format!("{:#?}", $byte), color.into()),
402            if $byte < 127 {
403                $crate::color::fore(
404                    format!("{:#?}", char::from($byte).to_string()),
405                    color.into(),
406                )
407            } else {
408                String::new()
409            },
410        ]
411        .iter()
412        .filter(|c| !c.is_empty())
413        .map(String::from)
414        .collect::<Vec<String>>()
415        .join(" => ")
416    }};
417}
418/// [std::dbg] equivalent for u8 which uses [format_byte] to display the byte
419#[macro_export]
420macro_rules! dbg_byte {
421    ($byte:expr $(,)? ) => {{
422        use $crate::color::{auto, fore, from_display};
423        let color = $crate::color::from_display($byte);
424        eprintln!(
425            "\n{} = {}",
426            $crate::color::auto(stringify!($byte)),
427            [$crate::format_byte!($byte), $crate::location!(),].join("\t"),
428        );
429        $byte
430    }};
431}
432
433/// [std::dbg] equivalent for `&[u8]` which uses [format_bytes] to display the byte slice
434#[macro_export]
435macro_rules! dbg_bytes {
436    ($slice:expr $(,)? ) => {{
437        use $crate::color::{auto, back, fore, from_display, pad};
438        use $crate::indent;
439        eprintln!(
440            "\n{} = {}",
441            $crate::color::auto(stringify!($slice)),
442            [$crate::format_bytes!($slice), $crate::location!(),].join(" => ")
443        );
444        $slice
445    }};
446}
447/// [std::dbg] equivalent for `&[u8]` which uses [format_bytes] to display the byte slice in base 16 and string
448#[macro_export]
449macro_rules! dbg_bytes_str {
450    ($slice:expr $(,)? ) => {{
451        use $crate::color::{auto, back, fore, from_display, pad};
452        use $crate::indent;
453        eprintln!(
454            "\n{}",
455            [
456                $crate::location!(begin),
457                String::new(),
458                $crate::color::auto(stringify!($slice)),
459                $crate::format_bytes_str!($slice),
460                String::new(),
461                $crate::location!(end),
462            ]
463            .join("\n")
464        );
465        $slice
466    }};
467}
468/// colorfully formats a slice or vector of [u8] as hex => binary => decimal (=> char (if ascii))
469#[macro_export]
470macro_rules! format_bytes {
471    ($slice:expr $(,)? ) => {
472        $crate::format_bytes!($slice, " => ");
473    };
474    (hex, $slice:expr $(,)? ) => {
475        $crate::format_bytes!(hex, $slice, " => ");
476    };
477    (bin, $slice:expr $(,)? ) => {
478        $crate::format_bytes!(bin, $slice, " => ");
479    };
480    ($slice:expr, $sep:literal $(,)? ) => {{
481        [
482            format!(
483                "[\n{}]",
484                $slice
485                    .iter()
486                    .map(Clone::clone)
487                    .map(|byte| format!(
488                        "{}, // {}\n",
489                        $crate::indent!($crate::format_byte!(byte)),
490                        $crate::color::fore(format!("{:#?}", char::from(byte).to_string()), 237),
491                    ))
492                    .collect::<Vec<String>>()
493                    .join("")
494            ),
495            format!("{} bytes", $slice.len()),
496            std::str::from_utf8($slice)
497                .map(|s| {
498                    let chars = s.chars().collect::<Vec<char>>();
499                    format!(
500                        "\"{s}\" => {} chars => [{}]",
501                        chars.len(),
502                        chars
503                            .iter()
504                            .map(|c| format!("{c:?}"))
505                            .collect::<Vec<String>>()
506                            .join(", ")
507                    )
508                })
509                .unwrap_or_default(),
510        ]
511        .iter()
512        .filter(|c| !c.is_empty())
513        .map(String::from)
514        .collect::<Vec<String>>()
515        .join($sep.to_string().as_str())
516    }};
517    (hex, $slice:expr, $sep:literal $(,)? ) => {{
518        [
519            format!(
520                "[\n{}]",
521                $slice
522                    .iter()
523                    .map(Clone::clone)
524                    .map(|byte| format!(
525                        "{}, // {}\n",
526                        $crate::indent!($crate::format_byte!(hex, byte)),
527                        $crate::color::fore(format!("{:#?}", char::from(byte).to_string()), 237),
528                    ))
529                    .collect::<Vec<String>>()
530                    .join("")
531            ),
532            std::str::from_utf8($slice)
533                .map(|s| format!("{s:#?}"))
534                .unwrap_or_default(),
535        ]
536        .iter()
537        .filter(|c| !c.is_empty())
538        .map(String::from)
539        .collect::<Vec<String>>()
540        .join($sep.to_string().as_str())
541    }};
542    (bin, $slice:expr, $sep:literal $(,)? ) => {{
543        [
544            format!(
545                "[\n{}]",
546                $slice
547                    .iter()
548                    .map(Clone::clone)
549                    .map(|byte| format!(
550                        "{}, // {}\n",
551                        $crate::indent!($crate::format_byte!(bin, byte)),
552                        $crate::color::fore(format!("{:#?}", char::from(byte).to_string()), 237),
553                    ))
554                    .collect::<Vec<String>>()
555                    .join("")
556            ),
557            std::str::from_utf8($slice)
558                .map(|s| format!("{s:#?}"))
559                .unwrap_or_default(),
560        ]
561        .iter()
562        .filter(|c| !c.is_empty())
563        .map(String::from)
564        .collect::<Vec<String>>()
565        .join($sep.to_string().as_str())
566    }};
567}
568
569/// colorfully formats a slice or vector of [u8] as hex
570#[macro_export]
571macro_rules! format_bytes_str {
572    ($slice:expr $(,)? ) => {
573        $crate::format_bytes_str!($slice, " => ");
574    };
575    ($slice:expr, $sep:literal $(,)? ) => {{
576        [
577            format!(
578                "[{}]",
579                $slice
580                    .iter()
581                    .map(Clone::clone)
582                    .map(|byte| $crate::format_byte!(hex_only, byte))
583                    .collect::<Vec<String>>()
584                    .join(", ")
585            ),
586            std::str::from_utf8($slice)
587                .map(|s| format!("{s:#?}"))
588                .unwrap_or_default(),
589        ]
590        .iter()
591        .filter(|c| !c.is_empty())
592        .map(String::from)
593        .collect::<Vec<String>>()
594        .join($sep.to_string().as_str())
595    }};
596}