1pub use std::backtrace::Backtrace;
2use std::ops::Deref;
3
4pub use anyhow::{
5 anyhow,
6 bail,
7 ensure,
8};
9pub use paste::paste;
10pub use regex::{
11 Regex,
12 RegexBuilder,
13};
14pub use thiserror::Error;
15
16pub type EmptyResult = anyhow::Result<()>;
17
18pub const BUILD_DIR: &str = "/.build/";
19pub const RUSTC_DIR: &str = "/rustc/";
20pub const GLIBC: &str = "glibc";
21
22#[derive(Debug, Error)]
28#[error(transparent)]
29pub struct AnyhowError(#[from] anyhow::Error);
30
31impl Deref for AnyhowError {
32 type Target = anyhow::Error;
33
34 fn deref(&self) -> &Self::Target {
35 &self.0
36 }
37}
38
39#[macro_export]
42macro_rules! err_impl {
43 (@hidden $errtype:ident, $item:ident, String) => {
44 paste! {
45 pub(crate) fn [<$item:snake>](in_: &str) -> anyhow::Error {
46 anyhow!{$errtype::$item(in_.into())}
47 }
48 }
49 };
50
51 (@hidden $errtype:ident, $item:ident, $($dtype:tt)::+) => {
52 paste! {
53 pub(crate) fn [<$item:snake>](in_: &$($dtype)::+) -> anyhow::Error {
54 anyhow!{$errtype::$item(in_.clone())}
55 }
56 }
57 };
58
59 ($errtype:ident,
60 $(#[$errinfo:meta] $item:ident($($dtype:tt)::+),)+
61 ) => {
62 #[derive(Debug, Error)]
63 pub(crate) enum $errtype {
64 $(#[$errinfo] $item($($dtype)::+)),+
65 }
66
67 impl $errtype {
68 $(err_impl! {@hidden $errtype, $item, $($dtype)::+})+
69 }
70 };
71}
72
73#[macro_export]
84macro_rules! skerr {
85 (@hidden $err:ident, $msg:literal, $($args:expr),*) => {
86 let bt = $err.backtrace().to_string();
87 #[allow(clippy::regex_creation_in_loops)]
88 let re = RegexBuilder::new(r"^\s+(\d+)(?s:.*?)\s+at\s+.*:\d+$")
89 .multi_line(true)
90 .build()
91 .unwrap();
92 let bad_frame_index: i32 = -2;
93
94 let mut last_frame_index: i32 = -1;
96 let mut frame_index: i32 = 0;
97 let mut filtered_bt = re.captures_iter(&bt).fold(String::new(), |mut acc, frame_capture| {
98 let frame = frame_capture.get(0).unwrap().as_str();
100 let skipped_frames = frame_index - last_frame_index;
101 if !(frame.contains(BUILD_DIR) || frame.contains(RUSTC_DIR) || frame.contains (GLIBC)) && !frame.is_empty() {
102 frame_index = str::parse::<i32>(frame_capture.get(1).map_or("", |m| m.as_str())).unwrap_or(bad_frame_index);
103 let skipped_frame_count = frame_index - last_frame_index - 1;
105 let skipped_frames = if frame_index == bad_frame_index || last_frame_index == bad_frame_index {
106 acc += &format!(" -- <skipped unknown frames> --\n");
107 } else if skipped_frame_count == 1 {
108 acc += &format!(" -- <skipped 1 frame> --\n");
109 } else if skipped_frame_count > 1 {
110 acc += &format!(" -- <skipped {skipped_frame_count} frames> --\n");
111 };
112 acc += &format!("{frame}\n");
113 last_frame_index = frame_index;
114 }
115 acc
116 });
117
118 let skipped_frame_count = frame_index - last_frame_index - 1;
119 let skipped_frames = if frame_index == bad_frame_index || last_frame_index == bad_frame_index {
120 filtered_bt += &format!(" -- <skipped unknown frames> --");
121 } else if skipped_frame_count == 1 {
122 filtered_bt += &format!(" -- <skipped 1 frame> --");
123 } else if skipped_frame_count > 1 {
124 filtered_bt += &format!(" -- <skipped {skipped_frame_count} frames> --");
125 };
126 error!(concat!($msg, "\n\n{}\n\nPartial Stack Trace:\n\n{}\n\n") $(, $args)*, $err, filtered_bt);
127 };
128
129 ($err:ident, $msg:literal) => {
130 skerr! {@hidden $err, $msg, };
131 };
132
133 ($err:ident, $msg:literal, $($args:expr),*) => {
134 skerr! {@hidden $err, $msg, $($args),*};
135 };
136}
137
138pub use {
139 err_impl,
140 skerr,
141};