rdftk_core/
error.rs

1/*!
2Provides the crate's `Error` and `Result` types as well as helper functions.
3
4 */
5
6use std::fmt::{Debug, Display};
7
8// ------------------------------------------------------------------------------------------------
9// Public Types
10// ------------------------------------------------------------------------------------------------
11
12pub trait ErrorSource: std::error::Error {
13    fn as_error_source(&self) -> &(dyn std::error::Error + 'static);
14}
15
16///
17/// The Error type for this crate.
18///
19#[derive(Debug)]
20pub enum Error {
21    ///
22    /// This signals a parser *tokenizer* error.
23    ///
24    Tokenizer {
25        representation: String,
26        source: Box<dyn std::error::Error>,
27    },
28    ///
29    /// This signals a parser error where some expected value was **not** found.
30    ///
31    ParserExpected {
32        rule_fn: String,
33        expecting: String,
34    },
35    ///
36    /// This signals a parser error where some unexpected value **was** not found.
37    ///
38    ParserUnexpected {
39        rule_fn: String,
40        given: String,
41        expecting: Vec<String>,
42    },
43    ParserUnreachable {
44        rule_fn: String,
45        given: String,
46    },
47    ///
48    /// The String value provided is not a valid value for it's type.
49    ///
50    InvalidFromStr {
51        value: String,
52        name: String,
53    },
54    ///
55    /// Could not coerce from `from_type` to `to_type`.
56    ///
57    InvalidLiteralTypeCooercion {
58        from_type: String,
59        to_type: String,
60    },
61    ///
62    /// Could not decode a supposedly hex-encoded string.
63    ///
64    HexDecoder {
65        value: String,
66        index: usize,
67    },
68
69    ///
70    /// The String value provided is not a valid Blank Node name.
71    ///
72    InvalidBlankNodeName {
73        name: String,
74    },
75    ///
76    /// A QName may not have an empty name part.
77    ///
78    EmptyQName,
79    ///
80    /// The String value provided is not a valid QName.
81    ///
82    InvalidQName {
83        name: String,
84    },
85    ///
86    /// Values from these different providers cannot be combined.
87    ///
88    ProviderMismatch {
89        lhs: String,
90        rhs: String,
91    },
92    ///
93    /// The match combination is not valid.
94    ///
95    InvalidMatch,
96    ///
97    /// An Absolute IRI was expected.
98    ///
99    AbsoluteIriExpected {
100        uri: String,
101    },
102
103    ///
104    ///Some model element was in an invalid state for the requested operation.
105    ///
106    InvalidState,
107    ///
108    /// Statements as objects, from RDF*, are not supported by this representation.
109    ///
110    RdfStarNotSupported {
111        representation: String,
112    },
113    ///
114    /// Cited model.formulae, from N3, are not supported by this representation.
115    ///
116    FormulaeNotSupported {
117        representation: String,
118    },
119    ///
120    /// Could not read or write query results in this representation.
121    ///
122    QueryResultsFormat {
123        representation: String,
124    },
125
126    ///
127    /// An error occurred borrowing from a standard cell type.
128    ///
129    Borrow(::std::cell::BorrowError),
130    ///
131    /// An error in the standard I/O library.
132    ///
133    Io(::std::io::Error),
134    ///
135    /// An error parsing IRI strings.
136    ///
137    Iri(::rdftk_iri::Error),
138    ///
139    /// An eror parsing language-tag strings.
140    ///
141    LanguageTag(::language_tags::ParseError),
142    ///
143    /// An error parsing Name strings.
144    ///
145    Name(::rdftk_iri::NameParseError),
146    ///
147    /// An error occurred converting to UTF-8 text.
148    ///
149    Utf8(::std::string::FromUtf8Error),
150
151    ///
152    /// An error occurred decoding base-64 data.
153    ///
154    #[cfg(feature = "binary_types")]
155    Base64Decoder(::base64::DecodeError),
156}
157
158///
159/// A Result type that specifically uses this crate's Error.
160///
161pub type Result<T> = std::result::Result<T, Error>;
162
163// ------------------------------------------------------------------------------------------------
164// Public Functions
165// ------------------------------------------------------------------------------------------------
166
167///
168/// Create Error object.
169///
170#[inline(always)]
171pub fn invalid_from_str_error<S1, S2>(value: S1, type_name: S2) -> Error
172where
173    S1: Into<String>,
174    S2: Into<String>,
175{
176    Error::InvalidFromStr {
177        value: value.into(),
178        name: type_name.into(),
179    }
180}
181
182///
183/// Create Error object.
184///
185#[inline(always)]
186pub fn invalid_blank_node_name_error<S>(name: S) -> Error
187where
188    S: Into<String>,
189{
190    Error::InvalidBlankNodeName { name: name.into() }
191}
192
193///
194/// Create Error object.
195///
196#[inline(always)]
197pub fn empty_qname_error() -> Error {
198    Error::EmptyQName
199}
200
201///
202/// Create Error object.
203///
204#[inline(always)]
205pub fn invalid_qname_error<S>(name: S) -> Error
206where
207    S: Into<String>,
208{
209    Error::InvalidQName { name: name.into() }
210}
211
212///
213/// Create Error object.
214///
215#[inline(always)]
216pub fn provider_mismatch_error<S1, S2>(lhs: S1, rhs: S2) -> Error
217where
218    S1: Into<String>,
219    S2: Into<String>,
220{
221    Error::ProviderMismatch {
222        lhs: lhs.into(),
223        rhs: rhs.into(),
224    }
225}
226
227///
228/// Create Error object.
229///
230#[inline(always)]
231pub fn invalid_match_error() -> Error {
232    Error::InvalidMatch
233}
234
235///
236/// Create Error object.
237///
238#[inline(always)]
239pub fn absolute_iri_expected_error<S>(uri: S) -> Error
240where
241    S: Into<String>,
242{
243    Error::AbsoluteIriExpected { uri: uri.into() }
244}
245
246///
247/// Create Error object.
248///
249#[inline(always)]
250pub fn invalid_state_error() -> Error {
251    Error::InvalidState
252}
253
254///
255/// Create Error object.
256///
257#[inline(always)]
258pub fn rdf_star_not_supported_error<S>(representation: S) -> Error
259where
260    S: Into<String>,
261{
262    Error::RdfStarNotSupported {
263        representation: representation.into(),
264    }
265}
266
267///
268/// Create Error object.
269///
270#[inline(always)]
271pub fn formulae_not_supported_error<S>(representation: S) -> Error
272where
273    S: Into<String>,
274{
275    Error::FormulaeNotSupported {
276        representation: representation.into(),
277    }
278}
279
280///
281/// Create Error object.
282///
283#[inline(always)]
284pub fn query_results_format_error<S>(representation: S) -> Error
285where
286    S: Into<String>,
287{
288    Error::QueryResultsFormat {
289        representation: representation.into(),
290    }
291}
292
293// ------------------------------------------------------------------------------------------------
294
295///
296/// Display an error trace to stdout.
297///
298#[inline(always)]
299pub fn print_trace(e: &dyn std::error::Error) {
300    println!("{}", error_trace(e));
301}
302
303///
304/// Display an error trace to stderr.
305///
306#[inline(always)]
307pub fn eprint_trace(e: &dyn std::error::Error) {
308    eprintln!("{}", error_trace(e));
309}
310
311///
312/// Convert an error into a trace string.
313///
314#[inline(always)]
315pub fn error_trace(e: &dyn std::error::Error) -> String {
316    trace_one(e, 1)
317}
318
319// ------------------------------------------------------------------------------------------------
320// Implementations
321// ------------------------------------------------------------------------------------------------
322
323impl Display for Error {
324    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
325        write!(
326            f,
327            "{}",
328            match self {
329                Self::Tokenizer { representation, source } => format!("The tokenizer for {representation} generated an error: {source}"),
330                Self::ParserExpected { rule_fn, expecting } => format!("Parser was expecting `{expecting}` in function `{rule_fn}`."),
331                Self::ParserUnexpected { rule_fn, given, expecting } => format!("Parser was not expecting `{given}` in function `{rule_fn}`; expecting {expecting:?}."),
332                Self::ParserUnreachable { rule_fn, given } => format!("Parser should not have reached `{given}` in function `{rule_fn}`."),
333                Self::InvalidFromStr { value, name } => format!(
334                    "The String value `{value}` is not a valid value for it's type: '{name}'."
335                ),
336                Self::InvalidBlankNodeName { name } =>
337                    format!("The String value `{name}` is not a valid Blank Node name."),
338                Self::InvalidLiteralTypeCooercion { from_type, to_type } =>
339                    format!("Not possible to coerce a literal from `{from_type}` into `{to_type}`."),
340                Self::HexDecoder { value, index } => format!("Could not decode a hex-encoded string, bad value `{value}` at index {index}"),
341                Self::EmptyQName => "A QName may not have an empty name part.".to_string(),
342                Self::InvalidQName { name } =>
343                    format!("The String value `{name}` is not a valid QName."),
344                Self::ProviderMismatch { lhs, rhs } => format!(
345                    "Values from these different providers cannot be combined ({lhs:?}, {rhs:?})."
346                ),
347                Self::InvalidMatch => "The match combination is not valid.".to_string(),
348                Self::AbsoluteIriExpected { uri } =>
349                    format!("An Absolute IRI was expected at, not '{uri}'."),
350                Self::InvalidState =>
351                    "Some model element was in an invalid state for the requested operation.".to_string(),
352                Self::RdfStarNotSupported { representation } => format!("Statements as objects, from RDF*, are not supported by the {representation:?} representation."),
353                Self::FormulaeNotSupported { representation } => format!("Cited model.formulae, from N3, are not supported by the {representation:?} representation."),
354                Self::QueryResultsFormat { representation } => format!("Could not read or write query results in the {representation:?} representation."),
355                Self::Borrow(source) => format!("A cell borrow error occurred; source: {source}"),
356                Self::Io(source) => format!("An I/O error occurred; source: {source}"),
357                Self::Iri(source) =>format!("An error occurred parsing an IRI; source: {source}"),
358                Self::LanguageTag(source) => format!("An error occurred parsing a language tag; source: {source}"),
359                Self::Name(source) => format!("An error occurred parsing a name; source: {source}"),
360                Self::Utf8(source) => format!("An error occurred parsing a UTF-8 string; source: {source}"),
361                #[cfg(feature = "binary_types")]
362                Self::Base64Decoder(source) => format!("An error occurred parsing a base64 encoded string; source: {source}"),
363            }
364        )
365    }
366}
367
368impl std::error::Error for Error {
369    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
370        match self {
371            //Self::Tokenizer { source } => Some(source),
372            Self::Borrow(source) => Some(source),
373            Self::Io(source) => Some(source),
374            Self::Iri(source) => Some(source),
375            Self::LanguageTag(source) => Some(source),
376            Self::Name(source) => Some(source),
377            Self::Utf8(source) => Some(source),
378            Self::Base64Decoder(source) => Some(source),
379            _ => None,
380        }
381    }
382}
383
384impl From<::std::cell::BorrowError> for Error {
385    fn from(source: ::std::cell::BorrowError) -> Self {
386        Self::Borrow(source)
387    }
388}
389
390impl From<::std::io::Error> for Error {
391    fn from(source: ::std::io::Error) -> Self {
392        Self::Io(source)
393    }
394}
395
396impl From<::rdftk_iri::Error> for Error {
397    fn from(source: ::rdftk_iri::Error) -> Self {
398        Self::Iri(source)
399    }
400}
401
402impl From<::language_tags::ParseError> for Error {
403    fn from(source: ::language_tags::ParseError) -> Self {
404        Self::LanguageTag(source)
405    }
406}
407
408impl From<::rdftk_iri::NameParseError> for Error {
409    fn from(source: ::rdftk_iri::NameParseError) -> Self {
410        Self::Name(source)
411    }
412}
413
414impl From<::std::string::FromUtf8Error> for Error {
415    fn from(source: ::std::string::FromUtf8Error) -> Self {
416        Self::Utf8(source)
417    }
418}
419
420#[cfg(feature = "binary_types")]
421impl From<::base64::DecodeError> for Error {
422    fn from(source: ::base64::DecodeError) -> Self {
423        Self::Base64Decoder(source)
424    }
425}
426
427#[allow(clippy::from_over_into)]
428impl<T> Into<Result<T>> for Error {
429    fn into(self) -> Result<T> {
430        Err(self)
431    }
432}
433
434// ------------------------------------------------------------------------------------------------
435// Private Functions
436// ------------------------------------------------------------------------------------------------
437
438fn trace_one(e: &dyn std::error::Error, count: i32) -> String {
439    use std::fmt::Write;
440
441    let mut trace = String::new();
442
443    writeln!(&mut trace, "{}. {}", count, e).expect("Failed to write message.");
444
445    if let Some(source) = e.source() {
446        write!(&mut trace, "{}", trace_one(source, count + 1)).expect("Failed to write source.");
447    }
448
449    writeln!(&mut trace).expect("Failed to write line break");
450    trace
451}