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    ($byte:expr $(,)? ) => {{
351        use $crate::color::{auto, fore, from_bytes, pad};
352        let color = $crate::color::from_bytes(&[$byte]);
353        [
354            $crate::color::fore(format!("0x{:02x}", $byte), color.into()),
355            $crate::color::fore(format!("0b{:08b}", $byte), color.into()),
356            $crate::color::fore(format!("{:#?}", $byte), color.into()),
357            if $byte < 127 {
358                $crate::color::fore(
359                    format!("{:#?}", char::from($byte).to_string()),
360                    color.into(),
361                )
362            } else {
363                String::new()
364            },
365        ]
366        .iter()
367        .filter(|c| !c.is_empty())
368        .map(String::from)
369        .collect::<Vec<String>>()
370        .join(" => ")
371    }};
372}
373/// [std::dbg] equivalent for u8 which uses [format_byte] to display the byte
374#[macro_export]
375macro_rules! dbg_byte {
376    ($byte:expr $(,)? ) => {{
377        use $crate::color::{auto, fore, from_display};
378        let color = $crate::color::from_display($byte);
379        eprintln!(
380            "\n{} = {}",
381            $crate::color::auto(stringify!($byte)),
382            [$crate::format_byte!($byte), $crate::location!(),].join("\t"),
383        );
384        $byte
385    }};
386}
387
388/// [std::dbg] equivalent for u8 which uses [format_bytes] to display the byte slice
389#[macro_export]
390macro_rules! dbg_bytes {
391    ($slice:expr $(,)? ) => {{
392        use $crate::color::{auto, back, fore, from_display, pad};
393        use $crate::indent;
394        eprintln!(
395            "\n{} = {}",
396            $crate::color::auto(stringify!($slice)),
397            [$crate::format_bytes!($slice), $crate::location!(),].join(" => ")
398        );
399        $slice
400    }};
401}
402/// colorfully formats a slice or vector of [u8] as hex => binary => decimal (=> char (if ascii))
403#[macro_export]
404macro_rules! format_bytes {
405    ($slice:expr $(,)? ) => {
406        $crate::format_bytes!($slice, " => ");
407    };
408    ($slice:expr, $sep:literal $(,)? ) => {{
409        [
410            format!(
411                "[\n{}]",
412                $slice
413                    .iter()
414                    .map(Clone::clone)
415                    .map(|byte| format!(
416                        "{}, // {}\n",
417                        $crate::indent!($crate::format_byte!(byte)),
418                        $crate::color::fore(format!("{:#?}", char::from(byte).to_string()), 237),
419                    ))
420                    .collect::<Vec<String>>()
421                    .join("")
422            ),
423            std::str::from_utf8($slice)
424                .map(|s| format!("{s:#?}"))
425                .unwrap_or_default(),
426        ]
427        .iter()
428        .filter(|c| !c.is_empty())
429        .map(String::from)
430        .collect::<Vec<String>>()
431        .join($sep.to_string().as_str())
432    }};
433}