1
//! Declare tor relay specific errors.
2

            
3
use std::fmt::{self, Display};
4

            
5
use thiserror::Error;
6
use tor_error::{ErrorKind, HasKind};
7

            
8
/// Main high-level error type for the Arti Tor relay.
9
///
10
/// If you need to handle different types of errors differently, use the
11
/// [`kind`](`tor_error::HasKind::kind`) trait method to check what kind of
12
/// error it is.
13
///
14
/// Note that although this type implements that standard
15
/// [`Error`](trait@std::error::Error) trait, the output of that trait's methods are
16
/// not covered by semantic versioning.  Specifically: you should not rely on
17
/// the specific output of `Display`, `Debug`, or `Error::source()` when run on
18
/// this type; it may change between patch versions without notification.
19
#[derive(Error, Clone, Debug)]
20
pub(crate) struct Error {
21
    /// The actual error.
22
    #[source]
23
    detail: Box<ErrorDetail>,
24
}
25

            
26
impl From<ErrorDetail> for Error {
27
    fn from(detail: ErrorDetail) -> Error {
28
        Error {
29
            detail: detail.into(),
30
        }
31
    }
32
}
33

            
34
/// Represents errors that can occur while doing Tor operations.
35
///
36
/// This enumeration is the inner view of an Error.
37
///
38
/// Instead of looking at the type, you should try to use the [`kind`](`tor_error::HasKind::kind`)
39
/// trait method to distinguish among different kinds of Error.
40
#[cfg_attr(test, derive(strum::EnumDiscriminants))]
41
#[cfg_attr(test, strum_discriminants(vis(pub(crate))))]
42
#[derive(Error, Clone, Debug)]
43
#[non_exhaustive]
44
pub(crate) enum ErrorDetail {
45
    /// A programming problem, either in our code or the code calling it.
46
    #[error("Programming problem")]
47
    Bug(#[from] tor_error::Bug),
48
    /// Building configuration failed.
49
    #[error("Problem with configuration")]
50
    Configuration(#[from] tor_config::ConfigBuildError),
51
    /// Error from the KeyMgr crate.
52
    #[error("KeyMgr error")]
53
    KeyMgr(#[from] tor_keymgr::Error),
54
}
55

            
56
impl Error {
57
    /// Consume this error and return the underlying error detail object.
58
    // TODO RELAY: remove
59
    #[allow(unused)]
60
    pub(crate) fn into_detail(self) -> ErrorDetail {
61
        *self.detail
62
    }
63
}
64

            
65
impl Display for Error {
66
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67
        write!(f, "tor: {}: {}", self.detail.kind(), &self.detail)
68
    }
69
}
70

            
71
impl tor_error::HasKind for Error {
72
    fn kind(&self) -> ErrorKind {
73
        self.detail.kind()
74
    }
75
}
76

            
77
impl tor_error::HasKind for ErrorDetail {
78
    fn kind(&self) -> ErrorKind {
79
        match self {
80
            ErrorDetail::Bug(e) => e.kind(),
81
            ErrorDetail::Configuration(e) => e.kind(),
82
            ErrorDetail::KeyMgr(e) => e.kind(),
83
        }
84
    }
85
}
86

            
87
#[cfg(test)]
88
mod test {
89
    // @@ begin test lint list maintained by maint/add_warning @@
90
    #![allow(clippy::bool_assert_comparison)]
91
    #![allow(clippy::clone_on_copy)]
92
    #![allow(clippy::dbg_macro)]
93
    #![allow(clippy::mixed_attributes_style)]
94
    #![allow(clippy::print_stderr)]
95
    #![allow(clippy::print_stdout)]
96
    #![allow(clippy::single_char_pattern)]
97
    #![allow(clippy::unwrap_used)]
98
    #![allow(clippy::unchecked_duration_subtraction)]
99
    #![allow(clippy::useless_vec)]
100
    #![allow(clippy::needless_pass_by_value)]
101
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
102
    use super::*;
103

            
104
    /// This code makes sure that our errors implement all the traits we want.
105
    #[test]
106
    fn traits_ok() {
107
        // I had intended to use `assert_impl`, but that crate can't check whether
108
        // a type is 'static.
109
        fn assert<
110
            T: Send + Sync + Clone + std::fmt::Debug + Display + std::error::Error + 'static,
111
        >() {
112
        }
113
        fn check() {
114
            assert::<Error>();
115
            assert::<ErrorDetail>();
116
        }
117
        check(); // doesn't do anything, but avoids "unused function" warnings.
118
    }
119
}