1#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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}