rdf_fusion_model/
error.rs

1use crate::{
2    DateTimeOverflowError, OppositeSignInDurationComponentsError, ParseDateTimeError,
3    ParseDecimalError, TooLargeForDecimalError, TooLargeForIntError,
4    TooLargeForIntegerError,
5};
6use datafusion::common::DataFusionError;
7use oxiri::IriParseError;
8use oxrdf::BlankNodeIdParseError;
9use std::error::Error;
10use std::fmt::Debug;
11use std::io;
12use std::num::{ParseFloatError, ParseIntError, TryFromIntError};
13use std::str::ParseBoolError;
14use std::string::FromUtf8Error;
15use thiserror::Error;
16
17/// A light-weight result, mainly used for SPARQL operations.
18pub type ThinResult<T> = Result<T, ThinError>;
19
20/// A thin error type that indicates an *expected* failure without any reason.
21///
22/// In SPARQL, many operations can fail. For example, because the input value had a different data
23/// type. However, these errors are expected and are part of the query evaluation. As all of these
24/// "expected" errors are treated equally in the query evaluation, we do not need to store a reason.
25#[derive(Clone, Copy, Debug, Error, PartialEq, Eq)]
26pub enum ThinError {
27    #[error("An expected error occurred.")]
28    ExpectedError,
29}
30
31impl ThinError {
32    /// Creates a result with a [ThinError].
33    pub fn expected<T>() -> ThinResult<T> {
34        Err(ThinError::ExpectedError)
35    }
36}
37
38macro_rules! implement_from {
39    ($t:ty) => {
40        impl From<$t> for ThinError {
41            fn from(_: $t) -> Self {
42                ThinError::ExpectedError
43            }
44        }
45    };
46}
47
48implement_from!(TooLargeForDecimalError);
49implement_from!(TooLargeForIntegerError);
50implement_from!(TooLargeForIntError);
51implement_from!(ParseBoolError);
52implement_from!(ParseIntError);
53implement_from!(ParseFloatError);
54implement_from!(ParseDecimalError);
55implement_from!(ParseDateTimeError);
56implement_from!(BlankNodeIdParseError);
57implement_from!(IriParseError);
58implement_from!(TryFromIntError);
59implement_from!(DateTimeOverflowError);
60implement_from!(OppositeSignInDurationComponentsError);
61implement_from!(FromUtf8Error);
62
63/// An error related to storage operations (reads, writes...).
64#[derive(Debug, thiserror::Error)]
65#[non_exhaustive]
66pub enum StorageError {
67    /// Error from the OS I/O layer.
68    #[error(transparent)]
69    Io(#[from] io::Error),
70    /// Error related to data corruption.
71    #[error(transparent)]
72    Corruption(#[from] CorruptionError),
73    #[error("{0}")]
74    Other(#[source] Box<dyn Error + Send + Sync + 'static>),
75}
76
77impl From<StorageError> for io::Error {
78    #[inline]
79    fn from(error: StorageError) -> Self {
80        match error {
81            StorageError::Io(error) => error,
82            StorageError::Corruption(error) => error.into(),
83            StorageError::Other(error) => Self::other(error),
84        }
85    }
86}
87
88// TODO: Improve when implementing proper error handling
89impl From<DataFusionError> for StorageError {
90    #[inline]
91    fn from(error: DataFusionError) -> Self {
92        Self::Other(Box::new(error))
93    }
94}
95
96/// An error return if some content in the database is corrupted.
97#[derive(Debug, thiserror::Error)]
98#[error(transparent)]
99pub struct CorruptionError(#[from] CorruptionErrorKind);
100
101/// An error return if some content in the database is corrupted.
102#[derive(Debug, thiserror::Error)]
103enum CorruptionErrorKind {
104    #[error("{0}")]
105    Msg(String),
106    #[error("{0}")]
107    Other(#[source] Box<dyn Error + Send + Sync + 'static>),
108}
109
110impl CorruptionError {
111    /// Builds an error from a printable error message.
112    #[inline]
113    pub fn new(error: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self {
114        Self(CorruptionErrorKind::Other(error.into()))
115    }
116
117    /// Builds an error from a printable error message.
118    #[inline]
119    pub fn msg(msg: impl Into<String>) -> Self {
120        Self(CorruptionErrorKind::Msg(msg.into()))
121    }
122}
123
124impl From<CorruptionError> for io::Error {
125    #[inline]
126    fn from(error: CorruptionError) -> Self {
127        Self::new(io::ErrorKind::InvalidData, error)
128    }
129}