hickory_server/
error.rs

1/*
2 * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! All defined errors for Hickory DNS
18
19use std::{fmt, io};
20
21use thiserror::Error;
22
23use crate::proto::serialize::txt::ParseError;
24#[cfg(feature = "backtrace")]
25use crate::proto::{ExtBacktrace, trace};
26use crate::proto::{ProtoError, ProtoErrorKind};
27
28/// The error kind for errors that get returned in the crate
29#[derive(Debug, Error)]
30#[non_exhaustive]
31pub enum PersistenceErrorKind {
32    /// An error that occurred when recovering from journal
33    #[error("error recovering from journal: {}", _0)]
34    Recovery(&'static str),
35
36    /// The number of inserted records didn't match the expected amount
37    #[error("wrong insert count: {} expect: {}", got, expect)]
38    WrongInsertCount {
39        /// The number of inserted records
40        got: usize,
41        /// The number of records expected to be inserted
42        expect: usize,
43    },
44
45    // foreign
46    /// An error got returned by the hickory-proto crate
47    #[error("proto error: {0}")]
48    Proto(#[from] ProtoError),
49
50    /// An error got returned from the sqlite crate
51    #[cfg(feature = "sqlite")]
52    #[error("sqlite error: {0}")]
53    Sqlite(#[from] rusqlite::Error),
54
55    /// A request timed out
56    #[error("request timed out")]
57    Timeout,
58}
59
60/// The error type for errors that get returned in the crate
61#[derive(Debug, Error)]
62pub struct PersistenceError {
63    kind: PersistenceErrorKind,
64    #[cfg(feature = "backtrace")]
65    backtrack: Option<ExtBacktrace>,
66}
67
68impl PersistenceError {
69    /// Get the kind of the error
70    pub fn kind(&self) -> &PersistenceErrorKind {
71        &self.kind
72    }
73}
74
75impl fmt::Display for PersistenceError {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        cfg_if::cfg_if! {
78            if #[cfg(feature = "backtrace")] {
79                if let Some(backtrace) = &self.backtrack {
80                    fmt::Display::fmt(&self.kind, f)?;
81                    fmt::Debug::fmt(backtrace, f)
82                } else {
83                    fmt::Display::fmt(&self.kind, f)
84                }
85            } else {
86                fmt::Display::fmt(&self.kind, f)
87            }
88        }
89    }
90}
91
92impl From<PersistenceErrorKind> for PersistenceError {
93    fn from(kind: PersistenceErrorKind) -> Self {
94        Self {
95            kind,
96            #[cfg(feature = "backtrace")]
97            backtrack: trace!(),
98        }
99    }
100}
101
102impl From<ProtoError> for PersistenceError {
103    fn from(e: ProtoError) -> Self {
104        match e.kind() {
105            ProtoErrorKind::Timeout => PersistenceErrorKind::Timeout.into(),
106            _ => PersistenceErrorKind::from(e).into(),
107        }
108    }
109}
110
111#[cfg(feature = "sqlite")]
112impl From<rusqlite::Error> for PersistenceError {
113    fn from(e: rusqlite::Error) -> Self {
114        PersistenceErrorKind::from(e).into()
115    }
116}
117
118/// The error kind for errors that get returned in the crate
119#[derive(Debug, Error)]
120#[non_exhaustive]
121pub enum ConfigErrorKind {
122    // foreign
123    /// An error got returned from IO
124    #[error("io error: {0}")]
125    Io(#[from] io::Error),
126
127    /// An error occurred while decoding toml data
128    #[cfg(feature = "toml")]
129    #[error("toml decode error: {0}")]
130    TomlDecode(#[from] toml::de::Error),
131
132    /// An error occurred while parsing a zone file
133    #[error("failed to parse the zone file: {0}")]
134    ZoneParse(#[from] ParseError),
135}
136
137/// The error type for errors that get returned in the crate
138#[derive(Debug)]
139pub struct ConfigError {
140    kind: Box<ConfigErrorKind>,
141    #[cfg(feature = "backtrace")]
142    backtrack: Option<ExtBacktrace>,
143}
144
145impl ConfigError {
146    /// Get the kind of the error
147    pub fn kind(&self) -> &ConfigErrorKind {
148        &self.kind
149    }
150}
151
152impl fmt::Display for ConfigError {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        cfg_if::cfg_if! {
155            if #[cfg(feature = "backtrace")] {
156                if let Some(backtrace) = &self.backtrack {
157                    fmt::Display::fmt(&self.kind, f)?;
158                    fmt::Debug::fmt(backtrace, f)
159                } else {
160                    fmt::Display::fmt(&self.kind, f)
161                }
162            } else {
163                fmt::Display::fmt(&self.kind, f)
164            }
165        }
166    }
167}
168
169impl<E> From<E> for ConfigError
170where
171    E: Into<ConfigErrorKind>,
172{
173    fn from(error: E) -> Self {
174        let kind: ConfigErrorKind = error.into();
175
176        Self {
177            kind: Box::new(kind),
178            #[cfg(feature = "backtrace")]
179            backtrack: trace!(),
180        }
181    }
182}