oom/
macros.rs

1#[macro_export]
2macro_rules! location {
3    () => {{
4        let location = format!(
5            "{}{}{}:{}",
6            crate::color::auto($crate::function_name!()),
7            crate::color::fore(" @ ", 220),
8            crate::color::auto($crate::filename!()),
9            crate::color::auto(line!().to_string())
10        );
11        location
12    }};
13    (begin) => {
14        $crate::tag!([crate::color::auto(format!("in function")), $crate::location!()].join(" "))
15    };
16    (end) => {
17        $crate::tag!([crate::color::auto(format!("from function")), $crate::location!()].join(" "))
18    };
19    (unexpected) => {
20        [
21            crate::color::fore(format!("<unexpected branch in function"), 160),
22            $crate::location!(),
23            crate::color::fore(format!(">"), 160),
24        ]
25        .join(" ")
26    };
27}
28#[macro_export]
29macro_rules! filename {
30    () => {{
31        let mut parts = file!()
32            .split(std::path::MAIN_SEPARATOR_STR)
33            .map(String::from)
34            .collect::<Vec<String>>();
35        let (folder, filename) = if parts.len() > 1 {
36            let last = crate::color::auto(parts.remove(parts.len() - 1));
37            let parts = parts.iter().map(|part| crate::color::auto(part)).collect::<Vec<String>>();
38            (parts, last)
39        } else {
40            (Vec::<String>::new(), crate::color::auto(parts[0].to_string()))
41        };
42        if folder.len() > 1 {
43            format!(
44                "{}{}{}",
45                crate::color::auto(filename),
46                crate::color::fore(" in ", 7),
47                folder.join(std::path::MAIN_SEPARATOR_STR)
48            )
49        } else {
50            crate::color::auto(filename)
51        }
52    }};
53}
54#[macro_export]
55macro_rules! tag {
56    ($arg:expr) => {{
57        $crate::tag!($arg, 7)
58    }};
59    (close, $arg:expr) => {{
60        $crate::tag!(close, $arg, 7)
61    }};
62    ($arg:expr, $color:literal) => {{
63        format!(
64            "{}{}{}",
65            crate::color::fore("<", $color),
66            crate::color::auto($arg),
67            crate::color::fore(">", $color),
68        )
69    }};
70    (close, $arg:expr, $color:literal) => {{
71        format!(
72            "{}{}{}",
73            crate::color::fore("</", $color),
74            $arg,
75            crate::color::fore(">", $color),
76        )
77    }};
78}
79#[macro_export]
80macro_rules! dbg {
81    ($( $arg:expr ),* $(,)? ) => {{
82        let obj = format!("{}", [$(
83            $crate::indent!(format!("{} = {:#?}", stringify!($arg), $arg)),
84        )*].iter().map(crate::color::reset).collect::<Vec<String>>().join("\n"));
85        eprintln!("{}", crate::color::reset([$crate::location!(begin), obj, $crate::location!(end)].join("\n")));
86    }};
87}
88#[macro_export]
89macro_rules! indent {
90    ($indentation:literal, $obj:expr) => {{
91        format!("{}", $obj)
92            .lines()
93            .map(|line| format!("{}{}", " ".repeat($indentation), line))
94            .collect::<Vec<String>>()
95            .join("\n")
96    }};
97    ($obj:expr) => {{
98        $crate::indent!(4, $obj)
99    }};
100}
101#[macro_export]
102macro_rules! indent_objdump {
103    ($indentation:literal, $obj:expr) => {{
104        format!("{:#?}", $obj)
105            .lines()
106            .map(|line| format!("{}{}", " ".repeat($indentation), line))
107            .collect::<Vec<String>>()
108            .join("\n")
109    }};
110    ($obj:expr) => {{
111        $crate::indent_objdump!(4, $obj)
112    }};
113}
114
115#[macro_export]
116macro_rules! function_name {
117    () => {{
118        fn f() {}
119        fn type_name_of<T>(_: T) -> &'static str {
120            std::any::type_name::<T>()
121        }
122        let name = type_name_of(f);
123        let name = name
124            .strip_suffix("::f")
125            .unwrap()
126            .replace(format!("{}::", module_path!()).as_str(), "");
127        name
128    }};
129}
130
131#[macro_export]
132macro_rules! unexpected {
133    ($( $arg:expr ),* ) => {{
134        $(
135            let obj = format!("{:#?}", $arg);
136            eprintln!("{}", crate::color::reset([obj, $crate::location!(unexpected)].join(" ")));
137        )*
138        std::process::exit(107);
139    }};
140    () => {
141        $crate::unexpected!("reach");
142    };
143}
144#[macro_export]
145macro_rules! caller {
146    () => {
147        $crate::Caller($crate::function_name!().to_string(), file!().to_string(), line!())
148    };
149}
150
151#[macro_export]
152macro_rules! with_caller {
153    ($error:expr) => {{
154        use crate::Traceback;
155        $error.with($crate::caller!())
156    }};
157}
158
159#[macro_export]
160macro_rules! map_call_to_result {
161    ($result:expr) => {
162        $result.map_err(|error| $crate::with_caller!(crate::Error::from(error)))
163    };
164}
165#[macro_export]
166macro_rules! try_result {
167    ($result:expr) => {
168        crate::map_call_to_result!($result)?
169    };
170}
171
172#[macro_export]
173macro_rules! unwrap_result {
174    ($result:expr) => {{
175        use crate::Traceback;
176        $crate::map_call_to_result!($result).unwrap()
177    }};
178}
179
180#[macro_export]
181macro_rules! impl_error {
182    ($name:ident, $type:ty) => {
183        #[derive(Clone, PartialEq, Eq)]
184        pub struct Error {
185            message: String,
186            ty: $type,
187            callers: Vec<crate::Caller>,
188            previous: Option<Box<Error>>,
189        }
190        impl Error {
191            pub fn new<T: std::fmt::Display>(message: T, ty: $type) -> Self {
192                Self::with_previous_error(message, ty, None)
193            }
194
195            pub fn with_previous_error<T: std::fmt::Display>(
196                message: T,
197                ty: $type,
198                previous: Option<Error>,
199            ) -> Self {
200                let message = message.to_string();
201                Error {
202                    message,
203                    ty,
204                    callers: Vec::new(),
205                    previous: previous.map(Box::new),
206                }
207            }
208        }
209        impl std::error::Error for $name {}
210
211        impl $crate::Traceback for $name {
212            fn message(&self) -> String {
213                self.message.to_string()
214            }
215
216            fn callers(&self) -> Vec<$crate::Caller> {
217                self.callers.to_vec()
218            }
219
220            fn with(&self, caller: $crate::Caller) -> Self {
221                let mut error = self.clone();
222                error.callers.insert(0, caller);
223                error
224            }
225
226            fn previous_as_debug(&self) -> String {
227                self.previous.clone().map(|error| format!("{:#?}", error)).unwrap_or_default()
228            }
229
230            fn previous_as_string(&self) -> String {
231                self.previous.clone().map(|error| format!("{}", error)).unwrap_or_default()
232            }
233        }
234        impl std::fmt::Display for Error {
235            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
236                write!(f, "{}\n\nreason: {}", self.ty, self.highlight_message())
237            }
238        }
239        impl std::fmt::Debug for Error {
240            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
241                let ty = self.ty.to_string();
242                let source = self.to_string();
243                write!(
244                    f,
245                    "{}{}",
246                    if ty == source {
247                        ty.to_string()
248                    } else {
249                        format!("{} in source:\n{}", ty, source)
250                    },
251                    if self.callers.len() > 0 {
252                        format!(
253                            "\n\nStacktrace:\n{}\n",
254                            [self.previous_as_debug(), self.callers_to_string(4)]
255                                .iter()
256                                .filter(|s| !s.trim().is_empty())
257                                .map(String::from)
258                                .collect::<Vec<String>>()
259                                .join("\n")
260                        )
261                    } else {
262                        String::new()
263                    }
264                )
265            }
266        }
267        pub type Result<T> = std::result::Result<T, Error>;
268        #[macro_export]
269        macro_rules! try_result {
270            ($result: expr) => {
271                $crate::map_call_to_result!($result)?
272            };
273        }
274        #[macro_export]
275        macro_rules! map_call_to_result {
276            ($result: expr) => {
277                use crate::Traceback;
278                $result.map_err(|error| crate::with_caller!(crate::Error::from(error)))
279            };
280        }
281    };
282}
283
284#[macro_export]
285macro_rules! format_to_str {
286    (&$lifetime:lifetime $text:literal, $( $arg:expr ),* $(,)? ) => {
287        std::borrow::Cow::from(format!($text, $($arg,)*).as_str())
288    };
289}
290
291#[macro_export]
292macro_rules! vec_deque {
293    ($( $arg:expr ),* $(,)? ) => {{
294        let mut deque = std::collections::VecDeque::new();
295        $(deque.push_back($arg);
296        )*
297        deque
298    }};
299}
300
301#[macro_export]
302macro_rules! step {
303    ($text:literal) => {{
304        $crate::step!(length=80, $text)
305    }};
306    (fg=$fg:literal, $text:literal) => {{
307        $crate::step!(bg=$fg, fg=crate::color::invert_bw($fg), length=80, $text)
308    }};
309    (bg=$bg:expr, fg=$fg:expr, $text:literal) => {{
310        $crate::step!(bg=$bg, fg=$fg, length=80, $text)
311    }};
312    (length=$length:literal, $text:expr) => {{
313        let (bg, fg) = crate::color::couple(line!() as usize);
314        let text = $text.to_string();
315        let bar = crate::color::ansi(
316            " ".repeat($length),
317            fg.into(),
318            bg.into(),
319        );
320        eprintln!(
321            "\n{}",
322            [
323                bar.clone(),
324                crate::color::ansi(
325                    if text.is_empty() { String::new() } else { format!("{}", text) },
326                    fg.into(),
327                    bg.into(),
328                ),
329            ].join("\n")
330        );
331
332    }};
333    (bg=$bg:expr, fg=$fg:expr, length=$length:literal, $text:expr) => {{
334        let text = $text.to_string();
335        let bar = crate::color::ansi(
336            " ".repeat($length),
337            $fg as usize,
338            $bg as usize,
339        );
340        eprintln!(
341            "\n{}",
342            [
343                bar.clone(),
344                crate::color::ansi(
345                    if text.is_empty() { String::new() } else { format!("{}", text) },
346                    $fg as usize,
347                    $bg as usize,
348                ),
349            ].join("\n")
350        );
351    }};
352    (length=$length:literal, $text:literal, $( $arg:expr ),* $(,)? ) => {{
353        $crate::step!(length=$length, format_args!($text, $($arg,)*))
354    }};
355    () => {{
356        $crate::step!("")
357    }};
358}
359#[macro_export]
360macro_rules! step_test {
361    ($text:literal) => {{
362        $crate::step!(length=80, $text)
363    }};
364    (length=$length:literal, $text:literal, $( $arg:expr ),* $(,)? ) => {{
365        $crate::step!(length=$length, format_args!($text, $($arg,)*))
366    }};
367    (length=$length:literal, $text:expr) => {{
368        let (bg, fg) = crate::color::couple(line!() as usize);
369        let text = $text.to_string();
370        let bar = crate::color::ansi(
371            " ".repeat($length),
372            fg.into(),
373            bg.into(),
374        );
375        eprintln!(
376            "\n{}",
377            [
378                bar.clone(),
379                crate::color::ansi(
380                    if text.is_empty() { String::new() } else { format!("{}", text) },
381                    bg.into(),
382                    fg.into(),
383                ),
384                bar.clone(),
385            ].join("\n")
386        );
387    }};
388    () => {{
389        $crate::step!("")
390    }};
391}
392
393#[macro_export]
394macro_rules! admonition {
395    ($color:literal, $message:expr) => {
396        $crate::admonition!($color, "{}", $message);
397    };
398    ($color:literal, $title:literal, $message:expr) => {
399        $crate::admonition!($color, title=$title, $message);
400    };
401
402    ($color:literal, title=$title:literal, $message:expr) => {
403        $crate::admonition!($color, title=$title, "{}", $message);
404    };
405    ($color:literal, title=$title:literal, $format:literal, $($arg:expr),* $(,)?) => {{
406        use crate::color;
407        eprintln!(
408            "\n{}",
409            [
410                color::ansi(
411                    format!("{}:{} {}", crate::function_name!(), line!(), $title),
412                    color::invert_bw($color).into(),
413                    $color,
414                ),
415                color::ansi(
416                    format!($format, $($arg),*),
417                    $color,
418                    color::invert_bw($color).into(),
419                )
420            ]
421            .join(" ")
422        );
423    }};
424    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {{
425        use crate::color;
426        eprintln!(
427            "\n{}",
428            [
429                color::ansi(
430                    format!("{}:{}", crate::function_name!(), line!()),
431                    color::invert_bw($color).into(),
432                    $color,
433                ),
434                color::ansi(
435                    format!($format, $($arg),*),
436                    $color,
437                    color::invert_bw($color).into(),
438                )
439            ]
440            .join(" ")
441        );
442    }};
443}
444
445#[macro_export]
446macro_rules! warn {
447    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
448        $crate::admonition!($color, title="WARNING", $format, $($arg),*);
449    };
450    ($color:literal, $message:expr) => {
451        $crate::admonition!($color, title="WARNING", $message);
452    };
453    ($message:expr) => {
454        $crate::warn!(220, $message);
455    };
456}
457
458#[macro_export]
459macro_rules! info {
460    ($color:literal, $format:literal, $($arg:expr),* $(,)?) => {
461        $crate::admonition!($color, title="INFO", $format, $($arg),*);
462    };
463    ($color:literal, $message:expr) => {
464        $crate::admonition!($color, title="INFO", $message);
465    };
466    ($message:expr) => {
467        $crate::info!(74, $message);
468    };
469}