arti_relay/
err.rs

1//! Declare tor relay specific errors.
2
3use std::fmt::{self, Display};
4
5use thiserror::Error;
6use 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)]
20pub(crate) struct Error {
21    /// The actual error.
22    #[source]
23    detail: Box<ErrorDetail>,
24}
25
26impl 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]
44pub(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
56impl 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
65impl 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
71impl tor_error::HasKind for Error {
72    fn kind(&self) -> ErrorKind {
73        self.detail.kind()
74    }
75}
76
77impl 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)]
88mod 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}