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 let obj = $crate::indent!(
97 format!(
98 "{} = {}\n",
99 $crate::color::auto(stringify!(&$arg)),
100 $crate::color::auto(format!("{:#?}", &$arg))));
101 eprintln!("{}", $crate::color::reset([$crate::location!(begin), obj, $crate::location!(end)].join("\n")));
102 $arg
103 }};
104 ($( $arg:expr ),* $(,)? ) => {{
105 $($crate::dbg!($arg))*
106 }};
107}
108
109#[macro_export]
111macro_rules! indent {
112 ($indentation:literal, $obj:expr) => {{
113 format!("{}", $obj)
114 .lines()
115 .map(|line| format!("{}{}", " ".repeat($indentation), line))
116 .collect::<Vec<String>>()
117 .join("\n")
118 }};
119 ($obj:expr) => {{
120 $crate::indent!(4, $obj)
121 }};
122}
123#[macro_export]
125macro_rules! indent_objdump {
126 ($indentation:literal, $obj:expr) => {{
127 format!("{:#?}", $obj)
128 .lines()
129 .map(|line| format!("{}{}", " ".repeat($indentation), line))
130 .collect::<Vec<String>>()
131 .join("\n")
132 }};
133 ($obj:expr) => {{
134 $crate::indent_objdump!(4, $obj)
135 }};
136}
137
138#[macro_export]
140macro_rules! function_name {
141 () => {{
142 fn f() {}
143 fn type_name_of<T>(_: T) -> &'static str {
144 std::any::type_name::<T>()
145 }
146 let name = type_name_of(f);
147 let name = name
148 .strip_suffix("::f")
149 .unwrap()
150 .replace(format!("{}::", module_path!()).as_str(), "");
151 name
152 }};
153}
154
155#[macro_export]
157macro_rules! step {
158 ($text:expr $(,)?) => {{
159 $crate::step!(length=$crate::color::term_cols(), $text)
160 }};
161 (fg=$fg:expr, $text:expr $(,)?) => {{
162 $crate::step!(bg=$fg, fg=$crate::color::invert_bw($fg), length=$crate::color::term_cols(), $text)
163 }};
164 (bg=$bg:expr, fg=$fg:expr, $text:expr $(,)?) => {{
165 $crate::step!(bg=$bg, fg=$fg, length=$crate::color::term_cols(), $text)
166 }};
167 (length=$length:expr, $text:expr $(,)?) => {{
168 let (bg, fg) = $crate::color::couple(line!() as usize);
169 let text = $text.to_string();
170 let bar = $crate::color::ansi(
171 " ".repeat($length),
172 fg.into(),
173 bg.into(),
174 );
175 eprintln!(
176 "\n{}",
177 [
178 bar.clone(),
179 $crate::color::ansi(
180 $crate::color::pad_columns(
181 [
182 $crate::function_name!(),
183 [
184 file!().to_string(),
185 line!().to_string(),
186 ].join(":")
187 ].join(" ").to_string()
188 ),
189 fg.into(),
190 bg.into(),
191 ),
192 $crate::color::ansi(
193 $crate::color::pad_columns(
194 if text.is_empty() { String::new() } else { format!("{}", text) }
195 ),
196 bg.into(),
197 fg.into(),
198 ),
199 bar.clone(),
200 ].join("\n")
201 );
202
203 }};
204 (bg=$bg:expr, fg=$fg:expr, length=$length:expr, $text:expr $(,)?) => {{
205 let text = $text.to_string();
206 let bar = $crate::color::ansi(
207 " ".repeat($length),
208 $fg as usize,
209 $bg as usize,
210 );
211 eprintln!(
212 "\n{}",
213 [
214 bar.clone(),
215 $crate::color::ansi(
216 $crate::color::pad_columns(
217 [
218 $crate::function_name!(),
219 [
220 file!().to_string(),
221 line!().to_string(),
222 ].join(":")
223 ].join(" ").to_string()
224 ),
225 $fg as usize,
226 $bg as usize,
227 ),
228 $crate::color::ansi(
229 $crate::color::pad_columns(
230 if text.is_empty() { String::new() } else { format!("{}", text) }
231 ),
232 $bg as usize,
233 $fg as usize,
234 ),
235 bar.clone(),
236 ].join("\n")
237 );
238 }};
239 (length=$length:expr, $text:expr, $( $arg:expr ),* $(,)? ) => {{
240 $crate::step!(length=$length, format_args!($text, $($arg,)*))
241 }};
242 () => {{
243 $crate::step!("")
244 }};
245}
246
247#[macro_export]
249macro_rules! admonition {
250 ($color:literal, $message:expr) => {
251 $crate::admonition!($color, "{}", $message);
252 };
253 ($color:literal, $title:literal, $message:expr) => {
254 $crate::admonition!($color, title=$title, $message);
255 };
256
257 ($color:literal, title=$title:literal, $message:expr) => {
258 $crate::admonition!($color, title=$title, "{}", $message);
259 };
260 ($color:literal, title=$title:literal, $format:literal, $($arg:expr),* $(,)?) => {{
261 use crate::color;
262 eprintln!(
263 "\n{}",
264 [
265 color::ansi(
266 format!("{}:{} {}", crate::function_name!(), line!(), $title),
267 color::invert_bw($color).into(),
268 $color,
269 ),
270 color::ansi(
271 format!($format, $($arg),*),
272 $color,
273 color::invert_bw($color).into(),
274 )
275 ]
276 .join(" ")
277 );
278 }};
279 ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {{
280 use crate::color;
281 eprintln!(
282 "\n{}",
283 [
284 color::ansi(
285 format!("{}:{}", crate::function_name!(), line!()),
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}
299
300#[macro_export]
302macro_rules! warn {
303 ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
304 $crate::admonition!($color, title="WARNING", $format, $($arg),*);
305 };
306 ($color:literal, $message:expr) => {
307 $crate::admonition!($color, title="WARNING", $message);
308 };
309 ($message:expr) => {
310 $crate::warn!(220, $message);
311 };
312}
313
314#[macro_export]
316macro_rules! info {
317 ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
318 $crate::admonition!($color, title="INFO", $format, $($arg),*);
319 };
320 ($color:literal, $message:expr) => {
321 $crate::admonition!($color, title="INFO", $message);
322 };
323 ($message:expr) => {
324 $crate::info!(74, $message);
325 };
326}
327
328#[macro_export]
330macro_rules! format_byte {
331 ($byte:expr $(,)? ) => {{
332 use $crate::color::{auto, fore, from_bytes, pad};
333 let color = $crate::color::from_bytes(&[$byte]);
334 [
335 $crate::color::fore(format!("0x{:02x}", $byte), color.into()),
336 $crate::color::fore(format!("0b{:08b}", $byte), color.into()),
337 $crate::color::fore(format!("{:#?}", $byte), color.into()),
338 if $byte < 127 {
339 $crate::color::fore(
340 format!("{:#?}", char::from($byte).to_string()),
341 color.into(),
342 )
343 } else {
344 String::new()
345 },
346 ]
347 .iter()
348 .filter(|c| !c.is_empty())
349 .map(String::from)
350 .collect::<Vec<String>>()
351 .join(" => ")
352 }};
353}
354#[macro_export]
356macro_rules! dbg_byte {
357 ($byte:expr $(,)? ) => {{
358 use $crate::color::{auto, fore, from_display};
359 let color = $crate::color::from_display($byte);
360 eprintln!(
361 "\n{} = {}",
362 $crate::color::auto(stringify!($byte)),
363 [$crate::format_byte!($byte), $crate::location!(),].join("\t"),
364 );
365 $byte
366 }};
367}
368
369#[macro_export]
371macro_rules! dbg_bytes {
372 ($slice:expr $(,)? ) => {{
373 use $crate::color::{auto, back, fore, from_display, pad};
374 use $crate::indent;
375 eprintln!(
376 "\n{} = {}",
377 $crate::color::auto(stringify!($slice)),
378 [$crate::format_bytes!($slice), $crate::location!(),].join(" => ")
379 );
380 $slice
381 }};
382}
383#[macro_export]
385macro_rules! format_bytes {
386 ($slice:expr $(,)? ) => {
387 $crate::format_bytes!($slice, " => ");
388 };
389 ($slice:expr, $sep:literal $(,)? ) => {{
390 [
391 format!(
392 "[\n{}]",
393 $slice
394 .iter()
395 .map(Clone::clone)
396 .map(|byte| format!(
397 "{}, // {}\n",
398 $crate::indent!($crate::format_byte!(byte)),
399 $crate::color::fore(format!("{:#?}", char::from(byte).to_string()), 237),
400 ))
401 .collect::<Vec<String>>()
402 .join("")
403 ),
404 std::str::from_utf8($slice)
405 .map(|s| format!("{s:#?}"))
406 .unwrap_or_default(),
407 ]
408 .iter()
409 .filter(|c| !c.is_empty())
410 .map(String::from)
411 .collect::<Vec<String>>()
412 .join($sep.to_string().as_str())
413 }};
414}