hickory_proto/serialize/txt/
errors.rs

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