1use std::env;
6use std::fmt::Debug;
7
8use backtrace::Backtrace;
9use serde_json::Error as SerdeError;
10
11pub fn make_error(err: std::io::Error, raw: impl Debug, file: &str, line: u32) -> std::io::Error {
13 if cfg!(debug_assertions) {
14 if let Ok(val) = env::var("RUST_BACKTRACE") {
15 if val.trim() != "0" {
16 error!("Stack:\n{:?}", Backtrace::new());
17 error!("Error:\n\t{:?}\n\tat {}:{}", raw, file, line);
18 return err;
19 }
20 }
21 }
22 error!(
23 "Error:\n\t{:?}\n\tat {}:{}\n\tnote: enable `RUST_BACKTRACE=1` env to display a backtrace",
24 raw, file, line
25 );
26 err
27}
28
29macro_rules! define_error_macro {
32 ($fn:ident, $err:expr) => {
33 #[macro_export]
34 macro_rules! $fn {
35 () => {
36 std::io::Error::new($err.kind(), format!("{}: {}:{}", $err, file!(), line!()))
37 };
38 ($raw:expr) => {
39 $crate::error::make_error($err, &$raw, file!(), line!())
40 };
41 }
42 };
43}
44
45macro_rules! define_libc_error_macro {
47 ($fn:ident, $code:ident) => {
48 define_error_macro!($fn, std::io::Error::from_raw_os_error(libc::$code));
49 };
50}
51
52define_libc_error_macro!(einval, EINVAL);
55define_libc_error_macro!(enoent, ENOENT);
56define_libc_error_macro!(ebadf, EBADF);
57define_libc_error_macro!(eacces, EACCES);
58define_libc_error_macro!(enotdir, ENOTDIR);
59define_libc_error_macro!(eisdir, EISDIR);
60define_libc_error_macro!(ealready, EALREADY);
61define_libc_error_macro!(enosys, ENOSYS);
62define_libc_error_macro!(epipe, EPIPE);
63define_libc_error_macro!(eio, EIO);
64
65#[macro_export]
67macro_rules! bail_einval {
68 ($($arg:tt)*) => {{
69 return Err(einval!(format!($($arg)*)))
70 }}
71}
72
73#[macro_export]
75macro_rules! bail_eio {
76 ($($arg:tt)*) => {{
77 return Err(eio!(format!($($arg)*)))
78 }}
79}
80
81define_error_macro!(last_error, std::io::Error::last_os_error());
83define_error_macro!(eother, std::io::Error::new(std::io::ErrorKind::Other, ""));
84
85#[derive(Debug)]
87pub enum MetricsError {
88 NoCounter,
90 Serialize(SerdeError),
92}
93
94#[cfg(test)]
95mod tests {
96 fn check_size(size: usize) -> std::io::Result<()> {
97 if size > 0x1000 {
98 return Err(einval!());
99 }
100
101 Ok(())
102 }
103
104 #[test]
105 fn test_einval() {
106 assert_eq!(
107 check_size(0x2000).unwrap_err().kind(),
108 std::io::Error::from_raw_os_error(libc::EINVAL).kind()
109 );
110 }
111}