Skip to main content

fbxcel/pull_parser/
error.rs

1//! Errors and result types.
2//!
3//! Types in this module will be used among multiple versions of parsers.
4
5use std::{error, fmt, io};
6
7use crate::pull_parser::SyntacticPosition;
8
9pub use self::{
10    data::{Compression, DataError},
11    operation::OperationError,
12    warning::Warning,
13};
14
15mod data;
16mod operation;
17mod warning;
18
19/// Parsing result.
20pub type Result<T> = std::result::Result<T, Error>;
21
22/// Parsing error.
23#[derive(Debug)]
24pub struct Error {
25    /// The real error.
26    repr: Box<Repr>,
27}
28
29impl Error {
30    /// Returns the error kind.
31    #[inline]
32    #[must_use]
33    pub fn kind(&self) -> ErrorKind {
34        self.repr.error.kind()
35    }
36
37    /// Returns a reference to the inner error container.
38    #[inline]
39    #[must_use]
40    pub fn get_ref(&self) -> &ErrorContainer {
41        &self.repr.error
42    }
43
44    /// Returns a reference to the inner error if the type matches.
45    #[inline]
46    #[must_use]
47    pub fn downcast_ref<T: 'static + error::Error>(&self) -> Option<&T> {
48        self.repr.error.as_error().downcast_ref::<T>()
49    }
50
51    /// Returns the syntactic position if available.
52    #[inline]
53    #[must_use]
54    pub fn position(&self) -> Option<&SyntacticPosition> {
55        self.repr.position.as_ref()
56    }
57
58    /// Creates a new `Error` with the given syntactic position info.
59    #[inline]
60    #[must_use]
61    pub(crate) fn with_position(error: ErrorContainer, position: SyntacticPosition) -> Self {
62        Self {
63            repr: Box::new(Repr::with_position(error, position)),
64        }
65    }
66
67    /// Sets the syntactic position and returns the new error.
68    #[inline]
69    #[must_use]
70    pub(crate) fn and_position(mut self, position: SyntacticPosition) -> Self {
71        self.repr.position = Some(position);
72        self
73    }
74}
75
76impl fmt::Display for Error {
77    #[inline]
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        self.repr.error.fmt(f)
80    }
81}
82
83impl error::Error for Error {
84    #[inline]
85    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
86        self.repr.error.source()
87    }
88}
89
90impl<T> From<T> for Error
91where
92    T: Into<ErrorContainer>,
93{
94    #[inline]
95    fn from(e: T) -> Self {
96        Error {
97            repr: Box::new(Repr::new(e.into())),
98        }
99    }
100}
101
102/// Internal representation of parsing error.
103#[derive(Debug)]
104struct Repr {
105    /// Error.
106    error: ErrorContainer,
107    /// Syntactic position.
108    position: Option<SyntacticPosition>,
109}
110
111impl Repr {
112    /// Creates a new `Repr`.
113    #[inline]
114    #[must_use]
115    pub(crate) fn new(error: ErrorContainer) -> Self {
116        Self {
117            error,
118            position: None,
119        }
120    }
121
122    /// Creates a new `Repr` with the given syntactic position info.
123    #[inline]
124    #[must_use]
125    pub(crate) fn with_position(error: ErrorContainer, position: SyntacticPosition) -> Self {
126        Self {
127            error,
128            position: Some(position),
129        }
130    }
131}
132
133/// Error kind for parsing errors.
134#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
135pub enum ErrorKind {
136    /// Invalid data.
137    ///
138    /// With this error kind, the inner error must be [`DataError`].
139    ///
140    /// [`DataError`]: enum.DataError.html
141    Data,
142    /// I/O error.
143    ///
144    /// With this error kind, the inner error must be [`std::io::Error`].
145    ///
146    /// [`std::io::Error`]:
147    /// https://doc.rust-lang.org/stable/std/io/struct.Error.html
148    Io,
149    /// Invalid operation.
150    ///
151    /// With this error kind, the inner error must be [`OperationError`].
152    ///
153    /// [`OperationError`]: enum.OperationError.html
154    Operation,
155    /// Critical warning.
156    ///
157    /// With this error kind, the inner error must be [`Warning`].
158    ///
159    /// [`Warning`]: enum.Warning.html
160    Warning,
161}
162
163/// Parsing error container.
164#[derive(Debug)]
165pub enum ErrorContainer {
166    /// Invalid data.
167    Data(DataError),
168    /// I/O error.
169    Io(io::Error),
170    /// Invalid operation.
171    Operation(OperationError),
172    /// Critical warning.
173    Warning(Warning),
174}
175
176impl ErrorContainer {
177    /// Returns the error kind of the error.
178    #[must_use]
179    pub fn kind(&self) -> ErrorKind {
180        match self {
181            ErrorContainer::Data(_) => ErrorKind::Data,
182            ErrorContainer::Io(_) => ErrorKind::Io,
183            ErrorContainer::Operation(_) => ErrorKind::Operation,
184            ErrorContainer::Warning(_) => ErrorKind::Warning,
185        }
186    }
187
188    /// Returns `&dyn std::error::Error`.
189    #[must_use]
190    pub fn as_error(&self) -> &(dyn 'static + error::Error) {
191        match self {
192            ErrorContainer::Data(e) => e,
193            ErrorContainer::Io(e) => e,
194            ErrorContainer::Operation(e) => e,
195            ErrorContainer::Warning(e) => e,
196        }
197    }
198}
199
200impl error::Error for ErrorContainer {
201    #[inline]
202    #[must_use]
203    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
204        Some(self.as_error())
205    }
206}
207
208impl fmt::Display for ErrorContainer {
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        match self {
211            ErrorContainer::Data(e) => write!(f, "Data error: {}", e),
212            ErrorContainer::Io(e) => write!(f, "I/O error: {}", e),
213            ErrorContainer::Operation(e) => write!(f, "Invalid operation: {}", e),
214            ErrorContainer::Warning(e) => write!(f, "Warning considered critical: {}", e),
215        }
216    }
217}
218
219impl From<io::Error> for ErrorContainer {
220    #[inline]
221    fn from(e: io::Error) -> Self {
222        ErrorContainer::Io(e)
223    }
224}
225
226impl From<DataError> for ErrorContainer {
227    #[inline]
228    fn from(e: DataError) -> Self {
229        ErrorContainer::Data(e)
230    }
231}
232
233impl From<OperationError> for ErrorContainer {
234    #[inline]
235    fn from(e: OperationError) -> Self {
236        ErrorContainer::Operation(e)
237    }
238}
239
240impl From<Warning> for ErrorContainer {
241    #[inline]
242    fn from(e: Warning) -> Self {
243        ErrorContainer::Warning(e)
244    }
245}