summaryrefslogtreecommitdiff
path: root/src/err.rs
blob: 8a5a2c5fd17ad7840d5937131e461cb2470ae765 (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
// Short-hand for constructing an Error, saves some typing and import madness
macro_rules! err {
    ($n:tt)          => { crate::err::Error(Box::new(crate::err::ErrorImpl::$n)) };
    ($n:tt, $e:expr) => { crate::err::Error(Box::new(crate::err::ErrorImpl::$n($e))) };
}

#[derive(Debug)]
pub struct Error(pub(crate) Box<ErrorImpl>);

#[derive(Debug)]
pub(crate) enum ErrorImpl {
    IO(std::io::Error), // This could use some context
    ProcShutdown(std::process::ExitStatus),
    ProcTimeout,
    Status(crate::sock::ReplyLine),
    Parse, // This could be more specific
    Keyword(String),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use ErrorImpl::*;
        match &*self.0 {
            IO(e)           => write!(f, "IO error: {}", e),
            ProcShutdown(s) => write!(f, "Tor process unexpectedly shutdown with code {}", s),
            ProcTimeout     => write!(f, "Timeout while waiting for Tor process to start"),
            Status(s)       => write!(f, "Unexpected reply ({})", s),
            Parse           => write!(f, "Error parsing reply"),
            Keyword(s)      => write!(f, "Invalid keyword '{}'", s),
        }
    }
}

impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Error {
        err!(IO, e)
    }
}

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use ErrorImpl::*;
        match &*self.0 {
            IO(e) => Some(e),
            _     => None
        }
    }
}

pub type Result<T> = std::result::Result<T,Error>;