hickory_proto/serialize/txt/
errors.rs

1use std::{fmt, io};
2
3use thiserror::Error;
4
5#[cfg(feature = "backtrace")]
6use crate::trace;
7use crate::{
8    error::{ProtoError, ProtoErrorKind},
9    rr::RecordType,
10    serialize::txt::Token,
11};
12#[cfg(feature = "backtrace")]
13#[cfg_attr(docsrs, doc(cfg(feature = "backtrace")))]
14use backtrace::Backtrace as ExtBacktrace;
15
16/// An alias for parse results returned by functions of this crate
17pub type ParseResult<T> = ::std::result::Result<T, ParseError>;
18
19/// The error kind for parse errors that get returned in the crate
20#[derive(Debug, Error)]
21#[non_exhaustive]
22pub enum ParseErrorKind {
23    /// An invalid numerical character was found
24    #[error("invalid numerical character: {0}")]
25    CharToInt(char),
26
27    /// An error with an arbitrary message, referenced as &'static str
28    #[error("{0}")]
29    Message(&'static str),
30
31    /// A token is missing
32    #[error("token is missing: {0}")]
33    MissingToken(String),
34
35    /// An error with an arbitrary message, stored as String
36    #[error("{0}")]
37    Msg(String),
38
39    /// A time string could not be parsed
40    #[error("invalid time string: {0}")]
41    ParseTime(String),
42
43    /// Found an unexpected token in a stream
44    #[error("unrecognized token in stream: {0:?}")]
45    UnexpectedToken(Token),
46
47    // foreign
48    /// An address parse error
49    #[error("network address parse error: {0}")]
50    AddrParse(#[from] std::net::AddrParseError),
51
52    /// A data encoding error
53    #[error("data encoding error: {0}")]
54    DataEncoding(#[from] data_encoding::DecodeError),
55
56    /// An error got returned from IO
57    #[error("io error: {0}")]
58    Io(#[from] std::io::Error),
59
60    /// An error from the lexer
61    #[error("lexer error: {0}")]
62    Lexer(#[from] LexerError),
63
64    /// A number parsing error
65    #[error("error parsing number: {0}")]
66    ParseInt(#[from] std::num::ParseIntError),
67
68    /// An error got returned by the hickory-proto crate
69    #[error("proto error: {0}")]
70    Proto(#[from] ProtoError),
71
72    /// Unknown RecordType
73    #[error("unknown RecordType: {0}")]
74    UnknownRecordType(u16),
75
76    /// Unknown RecordType
77    #[error("unsupported RecordType: {0}")]
78    UnsupportedRecordType(RecordType),
79
80    /// A request timed out
81    #[error("request timed out")]
82    Timeout,
83}
84
85impl Clone for ParseErrorKind {
86    fn clone(&self) -> Self {
87        use ParseErrorKind::*;
88        match self {
89            CharToInt(c) => CharToInt(*c),
90            Message(msg) => Message(msg),
91            MissingToken(ref s) => MissingToken(s.clone()),
92            Msg(ref msg) => Msg(msg.clone()),
93            ParseTime(ref s) => ParseTime(s.clone()),
94            UnexpectedToken(ref token) => UnexpectedToken(token.clone()),
95
96            AddrParse(e) => AddrParse(e.clone()),
97            DataEncoding(e) => DataEncoding(*e),
98            Io(e) => Io(std::io::Error::from(e.kind())),
99            Lexer(e) => Lexer(e.clone()),
100            ParseInt(e) => ParseInt(e.clone()),
101            Proto(e) => Proto(e.clone()),
102            UnsupportedRecordType(ty) => UnsupportedRecordType(*ty),
103            UnknownRecordType(ty) => UnknownRecordType(*ty),
104            Timeout => Timeout,
105        }
106    }
107}
108
109/// The error type for parse errors that get returned in the crate
110#[derive(Error, Debug)]
111pub struct ParseError {
112    kind: ParseErrorKind,
113    #[cfg(feature = "backtrace")]
114    backtrack: Option<ExtBacktrace>,
115}
116
117impl ParseError {
118    /// Get the kind of the error
119    pub fn kind(&self) -> &ParseErrorKind {
120        &self.kind
121    }
122}
123
124impl fmt::Display for ParseError {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        cfg_if::cfg_if! {
127            if #[cfg(feature = "backtrace")] {
128                if let Some(ref backtrace) = self.backtrack {
129                    fmt::Display::fmt(&self.kind, f)?;
130                    fmt::Debug::fmt(backtrace, f)
131                } else {
132                    fmt::Display::fmt(&self.kind, f)
133                }
134            } else {
135                fmt::Display::fmt(&self.kind, f)
136            }
137        }
138    }
139}
140
141impl From<ParseErrorKind> for ParseError {
142    fn from(kind: ParseErrorKind) -> Self {
143        Self {
144            kind,
145            #[cfg(feature = "backtrace")]
146            backtrack: trace!(),
147        }
148    }
149}
150
151impl From<&'static str> for ParseError {
152    fn from(msg: &'static str) -> Self {
153        ParseErrorKind::Message(msg).into()
154    }
155}
156
157impl From<String> for ParseError {
158    fn from(msg: String) -> Self {
159        ParseErrorKind::Msg(msg).into()
160    }
161}
162
163impl From<std::net::AddrParseError> for ParseError {
164    fn from(e: std::net::AddrParseError) -> Self {
165        ParseErrorKind::from(e).into()
166    }
167}
168
169impl From<::data_encoding::DecodeError> for ParseError {
170    fn from(e: data_encoding::DecodeError) -> Self {
171        ParseErrorKind::from(e).into()
172    }
173}
174
175impl From<io::Error> for ParseError {
176    fn from(e: io::Error) -> Self {
177        match e.kind() {
178            io::ErrorKind::TimedOut => ParseErrorKind::Timeout.into(),
179            _ => ParseErrorKind::from(e).into(),
180        }
181    }
182}
183
184impl From<LexerError> for ParseError {
185    fn from(e: LexerError) -> Self {
186        ParseErrorKind::from(e).into()
187    }
188}
189
190impl From<std::num::ParseIntError> for ParseError {
191    fn from(e: std::num::ParseIntError) -> Self {
192        ParseErrorKind::from(e).into()
193    }
194}
195
196impl From<ProtoError> for ParseError {
197    fn from(e: ProtoError) -> Self {
198        match *e.kind() {
199            ProtoErrorKind::Timeout => ParseErrorKind::Timeout.into(),
200            _ => ParseErrorKind::from(e).into(),
201        }
202    }
203}
204
205impl From<std::convert::Infallible> for ParseError {
206    fn from(_e: std::convert::Infallible) -> Self {
207        panic!("infallible")
208    }
209}
210
211impl From<ParseError> for io::Error {
212    fn from(e: ParseError) -> Self {
213        match *e.kind() {
214            ParseErrorKind::Timeout => Self::new(io::ErrorKind::TimedOut, e),
215            _ => Self::new(io::ErrorKind::Other, e),
216        }
217    }
218}
219
220/// An alias for lexer results returned by functions of this crate
221pub(crate) type LexerResult<T> = ::std::result::Result<T, LexerError>;
222
223/// The error kind for lexer errors that get returned in the crate
224#[derive(Eq, PartialEq, Debug, Error, Clone)]
225#[non_exhaustive]
226pub enum LexerErrorKind {
227    /// Unexpected end of input
228    #[error("unexpected end of input")]
229    EOF,
230
231    /// An illegal character was found
232    #[error("illegal character input: {0}")]
233    IllegalCharacter(char),
234
235    /// An illegal state was reached
236    #[error("illegal state: {0}")]
237    IllegalState(&'static str),
238
239    /// An error with an arbitrary message, referenced as &'static str
240    #[error("{0}")]
241    Message(&'static str),
242
243    /// An unclosed list was found
244    #[error("unclosed list, missing ')'")]
245    UnclosedList,
246
247    /// An unclosed quoted string was found
248    #[error("unclosed quoted string")]
249    UnclosedQuotedString,
250
251    /// An unrecognized character was found
252    #[error("unrecognized character input: {0}")]
253    UnrecognizedChar(char),
254
255    /// An unrecognized dollar content was found
256    #[error("unrecognized dollar content: {0}")]
257    UnrecognizedDollar(String),
258
259    /// An unrecognized octet was found
260    #[error("unrecognized octet: {0:x}")]
261    UnrecognizedOctet(u32),
262}
263
264/// The error type for lexer errors that get returned in the crate
265#[derive(Clone, Error, Debug)]
266pub struct LexerError {
267    kind: LexerErrorKind,
268    #[cfg(feature = "backtrace")]
269    backtrack: Option<ExtBacktrace>,
270}
271
272impl LexerError {
273    /// Get the kind of the error
274    pub fn kind(&self) -> &LexerErrorKind {
275        &self.kind
276    }
277}
278
279impl From<LexerErrorKind> for LexerError {
280    fn from(kind: LexerErrorKind) -> Self {
281        Self {
282            kind,
283            #[cfg(feature = "backtrace")]
284            backtrack: trace!(),
285        }
286    }
287}
288
289impl fmt::Display for LexerError {
290    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291        cfg_if::cfg_if! {
292            if #[cfg(feature = "backtrace")] {
293                if let Some(ref backtrace) = self.backtrack {
294                    fmt::Display::fmt(&self.kind, f)?;
295                    fmt::Debug::fmt(backtrace, f)
296                } else {
297                    fmt::Display::fmt(&self.kind, f)
298                }
299            } else {
300                fmt::Display::fmt(&self.kind, f)
301            }
302        }
303    }
304}