summaryrefslogtreecommitdiffstats
path: root/src/errors.rs
blob: a4c16b00bf26967aa1c3ef67325dfbe944bfd64b (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
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)))
  }
}