summaryrefslogtreecommitdiffstats
path: root/src/errors.rs
blob: 7b66319242d2dfe9f17ed875dcdf07fb313756ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use backtrace::Backtrace;
use std::error::Error;
use std::fmt;

#[derive(Debug)]
pub struct KhError {
    msg: String,
    backtrace: Backtrace,
    cause: Option<Box<dyn Error>>,
}

impl KhError {
    pub fn new(msg: &str, cause: Option<Box<dyn Error>>) -> KhError {
        KhError {
            msg: msg.to_string(),
            #[cfg(debug_assertions)]
            backtrace: backtrace_strip_foreign(Backtrace::new()),
            #[cfg(not(debug_assertions))]
            backtrace: Backtrace::new_unresolved(),
            cause,
        }
    }
}

#[cfg(debug_assertions)]
fn backtrace_strip_foreign(backtrace: Backtrace) -> Backtrace {
    use backtrace::BacktraceFrame;
    let backtrace: Vec<BacktraceFrame> = backtrace.into();
    backtrace
        .into_iter()
        .filter(|frame| {
            frame
                .symbols()
                .iter()
                .map(|symbol| {
                    symbol
                        .name()
                        .and_then(|name| name.as_str())
                        .map_or(false, |name| name.contains("khaleesi"))
                })
                .any(|x| x)
        })
        .collect::<Vec<BacktraceFrame>>()
        .into()
}

impl fmt::Display for KhError {
    #[cfg(debug_assertions)]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\n{:?}", self.msg, self.backtrace)
    }
    #[cfg(not(debug_assertions))]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.msg)
    }
}

impl Error for KhError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        // lol idunno
        self.cause.as_ref().map(|cause| &**cause)
    }
}

impl From<&str> for KhError {
    fn from(e: &str) -> KhError {
        KhError::new(e, None)
    }
}

impl From<String> for KhError {
    fn from(e: String) -> KhError {
        KhError::new(&e, None)
    }
}

impl From<std::path::StripPrefixError> for KhError {
    fn from(e: std::path::StripPrefixError) -> KhError {
        let description = e.to_string();
        KhError::new(&description, Some(Box::new(e)))
    }
}

impl From<::std::io::Error> for KhError {
    fn from(e: ::std::io::Error) -> KhError {
        let description = e.to_string();
        KhError::new(&description, Some(Box::new(e)))
    }
}