Convert error to thiserror

Co-authored-by: Yuri Astrakhan <yuriastrakhan@gmail.com>
pull/778/head
Tpt 11 months ago
parent 1c3f054836
commit 655ecd3e91
  1. 31
      Cargo.lock
  2. 2
      Cargo.toml
  3. 110
      lib/oxigraph/src/sparql/error.rs
  4. 2
      lib/oxigraph/src/storage/backend/fallback.rs
  5. 12
      lib/oxigraph/src/storage/backend/rocksdb.rs
  6. 146
      lib/oxigraph/src/storage/error.rs
  7. 30
      lib/oxigraph/src/storage/numeric_encoder.rs
  8. 30
      lib/oxigraph/src/storage/small_string.rs
  9. 1
      lib/oxrdf/Cargo.toml
  10. 13
      lib/oxrdf/src/blank_node.rs
  11. 78
      lib/oxrdf/src/parser.rs
  12. 13
      lib/oxrdf/src/variable.rs
  13. 1
      lib/oxrdfio/Cargo.toml
  14. 106
      lib/oxrdfio/src/error.rs
  15. 1
      lib/oxrdfxml/Cargo.toml
  16. 106
      lib/oxrdfxml/src/error.rs
  17. 20
      lib/oxrdfxml/src/parser.rs
  18. 3
      lib/oxsdatatypes/Cargo.toml
  19. 82
      lib/oxsdatatypes/src/date_time.rs
  20. 60
      lib/oxsdatatypes/src/decimal.rs
  21. 35
      lib/oxsdatatypes/src/duration.rs
  22. 12
      lib/oxsdatatypes/src/integer.rs
  23. 1
      lib/oxttl/Cargo.toml
  24. 47
      lib/oxttl/src/toolkit/error.rs
  25. 1
      lib/sparesults/Cargo.toml
  26. 88
      lib/sparesults/src/error.rs
  27. 1
      lib/spargebra/Cargo.toml
  28. 56
      lib/spargebra/src/parser.rs

31
Cargo.lock generated

@ -290,9 +290,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.4.18"
version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f"
dependencies = [
"clap_builder",
"clap_derive",
@ -300,9 +300,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.4.18"
version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99"
dependencies = [
"anstream",
"anstyle",
@ -312,9 +312,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.4.7"
version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
dependencies = [
"heck",
"proc-macro2",
@ -324,9 +324,9 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.6.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]]
name = "codspeed"
@ -786,9 +786,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "jobserver"
version = "0.1.27"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
dependencies = [
"libc",
]
@ -1136,6 +1136,7 @@ dependencies = [
"oxiri",
"oxsdatatypes",
"rand",
"thiserror",
]
[[package]]
@ -1145,6 +1146,7 @@ dependencies = [
"oxrdf",
"oxrdfxml",
"oxttl",
"thiserror",
"tokio",
]
@ -1156,6 +1158,7 @@ dependencies = [
"oxiri",
"oxrdf",
"quick-xml",
"thiserror",
"tokio",
]
@ -1174,6 +1177,7 @@ name = "oxsdatatypes"
version = "0.2.0-alpha.1"
dependencies = [
"js-sys",
"thiserror",
]
[[package]]
@ -1184,6 +1188,7 @@ dependencies = [
"oxilangtag",
"oxiri",
"oxrdf",
"thiserror",
"tokio",
]
@ -1745,6 +1750,7 @@ dependencies = [
"memchr",
"oxrdf",
"quick-xml",
"thiserror",
"tokio",
]
@ -1757,6 +1763,7 @@ dependencies = [
"oxrdf",
"peg",
"rand",
"thiserror",
]
[[package]]
@ -1783,9 +1790,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "strsim"
version = "0.10.0"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]]
name = "subtle"

@ -60,7 +60,7 @@ sha1 = "0.10"
sha2 = "0.10"
siphasher = ">=0.3, <2.0"
text-diff = "0.4"
thiserror = "1"
thiserror = "1.0.50"
time = "0.3"
tokio = "1.29"
url = "2.4"

@ -5,93 +5,53 @@ use crate::sparql::ParseError;
use crate::storage::StorageError;
use std::convert::Infallible;
use std::error::Error;
use std::{fmt, io};
use std::io;
/// A SPARQL evaluation error.
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum EvaluationError {
/// An error in SPARQL parsing.
Parsing(ParseError),
#[error(transparent)]
Parsing(#[from] ParseError),
/// An error from the storage.
Storage(StorageError),
#[error(transparent)]
Storage(#[from] StorageError),
/// An error while parsing an external RDF file.
GraphParsing(RdfParseError),
#[error(transparent)]
GraphParsing(#[from] RdfParseError),
/// An error while parsing an external result file (likely from a federated query).
ResultsParsing(ResultsParseError),
#[error(transparent)]
ResultsParsing(#[from] ResultsParseError),
/// An error returned during results serialization.
ResultsSerialization(io::Error),
#[error(transparent)]
ResultsSerialization(#[from] io::Error),
/// Error during `SERVICE` evaluation
Service(Box<dyn Error + Send + Sync + 'static>),
#[error("{0}")]
Service(#[source] Box<dyn Error + Send + Sync + 'static>),
/// Error when `CREATE` tries to create an already existing graph
#[error("The graph {0} already exists")]
GraphAlreadyExists(NamedNode),
/// Error when `DROP` or `CLEAR` tries to remove a not existing graph
#[error("The graph {0} does not exist")]
GraphDoesNotExist(NamedNode),
/// The variable storing the `SERVICE` name is unbound
#[error("The variable encoding the service name is unbound")]
UnboundService,
/// The given `SERVICE` is not supported
#[error("The service {0} is not supported")]
UnsupportedService(NamedNode),
/// The given content media type returned from an HTTP response is not supported (`SERVICE` and `LOAD`)
#[error("The content media type {0} is not supported")]
UnsupportedContentType(String),
/// The `SERVICE` call has not returns solutions
#[error("The service is not returning solutions but a boolean or a graph")]
ServiceDoesNotReturnSolutions,
/// The results are not a RDF graph
#[error("The query results are not a RDF graph")]
NotAGraph,
}
impl fmt::Display for EvaluationError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Parsing(error) => error.fmt(f),
Self::Storage(error) => error.fmt(f),
Self::GraphParsing(error) => error.fmt(f),
Self::ResultsParsing(error) => error.fmt(f),
Self::ResultsSerialization(error) => error.fmt(f),
Self::Service(error) => error.fmt(f),
Self::GraphAlreadyExists(graph) => write!(f, "The graph {graph} already exists"),
Self::GraphDoesNotExist(graph) => write!(f, "The graph {graph} does not exist"),
Self::UnboundService => {
f.write_str("The variable encoding the service name is unbound")
}
Self::UnsupportedService(service) => {
write!(f, "The service {service} is not supported")
}
Self::UnsupportedContentType(content_type) => {
write!(f, "The content media type {content_type} is not supported")
}
Self::ServiceDoesNotReturnSolutions => {
f.write_str("The service is not returning solutions but a boolean or a graph")
}
Self::NotAGraph => f.write_str("The query results are not a RDF graph"),
}
}
}
impl Error for EvaluationError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Parsing(e) => Some(e),
Self::Storage(e) => Some(e),
Self::GraphParsing(e) => Some(e),
Self::ResultsParsing(e) => Some(e),
Self::ResultsSerialization(e) => Some(e),
Self::Service(e) => {
let e = Box::as_ref(e);
Some(e)
}
Self::GraphAlreadyExists(_)
| Self::GraphDoesNotExist(_)
| Self::UnboundService
| Self::UnsupportedService(_)
| Self::UnsupportedContentType(_)
| Self::ServiceDoesNotReturnSolutions
| Self::NotAGraph => None,
}
}
}
impl From<Infallible> for EvaluationError {
#[inline]
fn from(error: Infallible) -> Self {
@ -99,34 +59,6 @@ impl From<Infallible> for EvaluationError {
}
}
impl From<ParseError> for EvaluationError {
#[inline]
fn from(error: ParseError) -> Self {
Self::Parsing(error)
}
}
impl From<StorageError> for EvaluationError {
#[inline]
fn from(error: StorageError) -> Self {
Self::Storage(error)
}
}
impl From<RdfParseError> for EvaluationError {
#[inline]
fn from(error: RdfParseError) -> Self {
Self::GraphParsing(error)
}
}
impl From<ResultsParseError> for EvaluationError {
#[inline]
fn from(error: ResultsParseError) -> Self {
Self::ResultsParsing(error)
}
}
impl From<EvaluationError> for io::Error {
#[inline]
fn from(error: EvaluationError) -> Self {

@ -36,7 +36,7 @@ impl Db {
if self.0.read().unwrap().contains_key(&column_family) {
Ok(column_family)
} else {
Err(CorruptionError::msg(format!("Column family {name} does not exist")).into())
Err(CorruptionError::from_missing_column_family_name(name).into())
}
}

@ -548,7 +548,7 @@ impl Db {
return Ok(ColumnFamily(*cf_handle));
}
}
Err(CorruptionError::msg(format!("Column family {name} does not exist")).into())
Err(CorruptionError::from_missing_column_family_name(name).into())
}
#[must_use]
@ -1314,6 +1314,8 @@ impl SstFileWriter {
}
}
#[derive(thiserror::Error)]
#[error("{}", self.message())]
struct ErrorStatus(rocksdb_status_t);
unsafe impl Send for ErrorStatus {}
@ -1352,14 +1354,6 @@ impl fmt::Debug for ErrorStatus {
}
}
impl fmt::Display for ErrorStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.message())
}
}
impl Error for ErrorStatus {}
impl From<ErrorStatus> for StorageError {
fn from(status: ErrorStatus) -> Self {
if status.0.code == rocksdb_status_code_t_rocksdb_status_code_io_error {

@ -1,48 +1,23 @@
use crate::io::{ParseError, RdfFormat};
use crate::storage::numeric_encoder::EncodedTerm;
use oxiri::IriParseError;
use oxrdf::TermRef;
use std::error::Error;
use std::{fmt, io};
use thiserror::Error;
use std::io;
/// An error related to storage operations (reads, writes...).
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum StorageError {
/// Error from the OS I/O layer.
Io(io::Error),
#[error(transparent)]
Io(#[from] io::Error),
/// Error related to data corruption.
Corruption(CorruptionError),
#[error(transparent)]
Corruption(#[from] CorruptionError),
#[doc(hidden)]
Other(Box<dyn Error + Send + Sync + 'static>),
}
impl fmt::Display for StorageError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => e.fmt(f),
Self::Corruption(e) => e.fmt(f),
Self::Other(e) => e.fmt(f),
}
}
}
impl Error for StorageError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Corruption(e) => Some(e),
Self::Other(e) => Some(e.as_ref()),
}
}
}
impl From<io::Error> for StorageError {
#[inline]
fn from(error: io::Error) -> Self {
Self::Io(error)
}
#[error("{0}")]
Other(#[source] Box<dyn Error + Send + Sync + 'static>),
}
impl From<StorageError> for io::Error {
@ -57,59 +32,42 @@ impl From<StorageError> for io::Error {
}
/// An error return if some content in the database is corrupted.
#[derive(Debug)]
pub struct CorruptionError {
inner: CorruptionErrorKind,
}
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct CorruptionError(#[from] CorruptionErrorKind);
#[derive(Debug)]
/// An error return if some content in the database is corrupted.
#[derive(Debug, thiserror::Error)]
enum CorruptionErrorKind {
#[error("{0}")]
Msg(String),
Other(Box<dyn Error + Send + Sync + 'static>),
#[error("{0}")]
Other(#[source] Box<dyn Error + Send + Sync + 'static>),
}
impl CorruptionError {
/// Builds an error from a printable error message.
#[inline]
pub(crate) fn new(error: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self {
Self {
inner: CorruptionErrorKind::Other(error.into()),
}
}
/// Builds an error from a printable error message.
#[inline]
pub(crate) fn msg(msg: impl Into<String>) -> Self {
Self {
inner: CorruptionErrorKind::Msg(msg.into()),
}
Self(CorruptionErrorKind::Other(error.into()))
}
}
impl fmt::Display for CorruptionError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
CorruptionErrorKind::Msg(e) => e.fmt(f),
CorruptionErrorKind::Other(e) => e.fmt(f),
}
pub(crate) fn from_encoded_term(encoded: &EncodedTerm, term: &TermRef<'_>) -> Self {
// TODO: eventually use a dedicated error enum value
Self::msg(format!("Invalid term encoding {encoded:?} for {term}"))
}
}
impl Error for CorruptionError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.inner {
CorruptionErrorKind::Msg(_) => None,
CorruptionErrorKind::Other(e) => Some(e.as_ref()),
}
pub(crate) fn from_missing_column_family_name(name: &'static str) -> Self {
// TODO: eventually use a dedicated error enum value
Self::msg(format!("Column family {name} does not exist"))
}
}
impl From<CorruptionError> for StorageError {
/// Builds an error from a printable error message.
#[inline]
fn from(error: CorruptionError) -> Self {
Self::Corruption(error)
pub(crate) fn msg(msg: impl Into<String>) -> Self {
Self(CorruptionErrorKind::Msg(msg.into()))
}
}
@ -121,57 +79,25 @@ impl From<CorruptionError> for io::Error {
}
/// An error raised while loading a file into a [`Store`](crate::store::Store).
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub enum LoaderError {
/// An error raised while reading the file.
Parsing(ParseError),
#[error(transparent)]
Parsing(#[from] ParseError),
/// An error raised during the insertion in the store.
Storage(StorageError),
#[error(transparent)]
Storage(#[from] StorageError),
/// The base IRI is invalid.
#[error("Invalid base IRI '{iri}': {error}")]
InvalidBaseIri {
/// The IRI itself.
iri: String,
/// The parsing error.
#[source]
error: IriParseError,
},
}
impl fmt::Display for LoaderError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Parsing(e) => e.fmt(f),
Self::Storage(e) => e.fmt(f),
Self::InvalidBaseIri { iri, error } => write!(f, "Invalid base IRI '{iri}': {error}"),
}
}
}
impl Error for LoaderError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Parsing(e) => Some(e),
Self::Storage(e) => Some(e),
Self::InvalidBaseIri { error, .. } => Some(error),
}
}
}
impl From<ParseError> for LoaderError {
#[inline]
fn from(error: ParseError) -> Self {
Self::Parsing(error)
}
}
impl From<StorageError> for LoaderError {
#[inline]
fn from(error: StorageError) -> Self {
Self::Storage(error)
}
}
impl From<LoaderError> for io::Error {
#[inline]
fn from(error: LoaderError) -> Self {
@ -186,7 +112,7 @@ impl From<LoaderError> for io::Error {
}
/// An error raised while writing a file from a [`Store`](crate::store::Store).
#[derive(Debug, Error)]
#[derive(Debug, thiserror::Error)]
pub enum SerializerError {
/// An error raised while writing the content.
#[error(transparent)]

@ -713,19 +713,13 @@ pub fn insert_term<F: FnMut(&StrHash, &str) -> Result<(), StorageError>>(
if let EncodedTerm::NamedNode { iri_id } = encoded {
insert_str(iri_id, node.as_str())
} else {
Err(
CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}"))
.into(),
)
Err(CorruptionError::from_encoded_term(encoded, &term).into())
}
}
TermRef::BlankNode(node) => match encoded {
EncodedTerm::BigBlankNode { id_id } => insert_str(id_id, node.as_str()),
EncodedTerm::SmallBlankNode(..) | EncodedTerm::NumericalBlankNode { .. } => Ok(()),
_ => Err(
CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}"))
.into(),
),
_ => Err(CorruptionError::from_encoded_term(encoded, &term).into()),
},
TermRef::Literal(literal) => match encoded {
EncodedTerm::BigStringLiteral { value_id }
@ -736,10 +730,7 @@ pub fn insert_term<F: FnMut(&StrHash, &str) -> Result<(), StorageError>>(
if let Some(language) = literal.language() {
insert_str(language_id, language)
} else {
Err(CorruptionError::new(format!(
"Invalid term encoding {encoded:?} for {term}"
))
.into())
Err(CorruptionError::from_encoded_term(encoded, &term).into())
}
}
EncodedTerm::BigBigLangStringLiteral {
@ -750,10 +741,7 @@ pub fn insert_term<F: FnMut(&StrHash, &str) -> Result<(), StorageError>>(
if let Some(language) = literal.language() {
insert_str(language_id, language)
} else {
Err(CorruptionError::new(format!(
"Invalid term encoding {encoded:?} for {term}"
))
.into())
Err(CorruptionError::from_encoded_term(encoded, &term).into())
}
}
EncodedTerm::SmallTypedLiteral { datatype_id, .. } => {
@ -784,10 +772,7 @@ pub fn insert_term<F: FnMut(&StrHash, &str) -> Result<(), StorageError>>(
| EncodedTerm::DurationLiteral(..)
| EncodedTerm::YearMonthDurationLiteral(..)
| EncodedTerm::DayTimeDurationLiteral(..) => Ok(()),
_ => Err(
CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}"))
.into(),
),
_ => Err(CorruptionError::from_encoded_term(encoded, &term).into()),
},
TermRef::Triple(triple) => {
if let EncodedTerm::Triple(encoded) = encoded {
@ -799,10 +784,7 @@ pub fn insert_term<F: FnMut(&StrHash, &str) -> Result<(), StorageError>>(
)?;
insert_term(triple.object.as_ref(), &encoded.object, insert_str)
} else {
Err(
CorruptionError::new(format!("Invalid term encoding {encoded:?} for {term}"))
.into(),
)
Err(CorruptionError::from_encoded_term(encoded, &term).into())
}
}
}

@ -1,6 +1,5 @@
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::error::Error;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::str::{FromStr, Utf8Error};
@ -169,31 +168,10 @@ impl<'a> TryFrom<&'a str> for SmallString {
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, thiserror::Error)]
pub enum BadSmallStringError {
#[error("small strings could only contain at most 15 characters, found {0}")]
TooLong(usize),
BadUtf8(Utf8Error),
}
impl fmt::Display for BadSmallStringError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::TooLong(v) => write!(
f,
"small strings could only contain at most 15 characters, found {v}"
),
Self::BadUtf8(e) => e.fmt(f),
}
}
}
impl Error for BadSmallStringError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::TooLong(_) => None,
Self::BadUtf8(e) => Some(e),
}
}
#[error(transparent)]
BadUtf8(#[from] Utf8Error),
}

@ -22,6 +22,7 @@ oxilangtag.workspace = true
oxiri.workspace = true
oxsdatatypes = { workspace = true, optional = true }
rand.workspace = true
thiserror.workspace = true
[lints]
workspace = true

@ -1,5 +1,4 @@
use rand::random;
use std::error::Error;
use std::io::Write;
use std::{fmt, str};
@ -345,18 +344,10 @@ fn to_integer_id(id: &str) -> Option<u128> {
}
/// An error raised during [`BlankNode`] IDs validation.
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
#[error("The blank node identifier is invalid")]
pub struct BlankNodeIdParseError;
impl fmt::Display for BlankNodeIdParseError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("The blank node identifier is invalid")
}
}
impl Error for BlankNodeIdParseError {}
#[cfg(test)]
mod tests {
#![allow(clippy::panic_in_result_fn)]

@ -5,9 +5,8 @@ use crate::{
};
#[cfg(feature = "rdf-star")]
use crate::{Subject, Triple};
use std::error::Error;
use std::char;
use std::str::{Chars, FromStr};
use std::{char, fmt};
/// This limit is set in order to avoid stack overflow error when parsing nested triples due to too many recursive calls.
/// The actual limit value is a wet finger compromise between not failing to parse valid files and avoiding to trigger stack overflow errors.
@ -166,11 +165,11 @@ impl FromStr for Variable {
"Variable serialization should start with ? or $",
));
}
Self::new(&s[1..]).map_err(|error| Self::Err {
kind: TermParseErrorKind::Variable {
Self::new(&s[1..]).map_err(|error| {
TermParseError(TermParseErrorKind::Variable {
value: s.to_owned(),
error,
},
})
})
}
}
@ -183,11 +182,11 @@ fn read_named_node(s: &str) -> Result<(NamedNode, &str), TermParseError> {
.ok_or_else(|| TermParseError::msg("Named node serialization should end with a >"))?;
let (value, remain) = remain.split_at(end);
let remain = &remain[1..];
let term = NamedNode::new(value).map_err(|error| TermParseError {
kind: TermParseErrorKind::Iri {
let term = NamedNode::new(value).map_err(|error| {
TermParseError(TermParseErrorKind::Iri {
value: value.to_owned(),
error,
},
})
})?;
Ok((term, remain))
} else {
@ -207,11 +206,11 @@ fn read_blank_node(s: &str) -> Result<(BlankNode, &str), TermParseError> {
})
.unwrap_or(remain.len());
let (value, remain) = remain.split_at(end);
let term = BlankNode::new(value).map_err(|error| TermParseError {
kind: TermParseErrorKind::BlankNode {
let term = BlankNode::new(value).map_err(|error| {
TermParseError(TermParseErrorKind::BlankNode {
value: value.to_owned(),
error,
},
})
})?;
Ok((term, remain))
} else {
@ -237,11 +236,11 @@ fn read_literal(s: &str) -> Result<(Literal, &str), TermParseError> {
let (language, remain) = remain.split_at(end);
Ok((
Literal::new_language_tagged_literal(value, language).map_err(
|error| TermParseError {
kind: TermParseErrorKind::LanguageTag {
|error| {
TermParseError(TermParseErrorKind::LanguageTag {
value: language.to_owned(),
error,
},
})
},
)?,
remain,
@ -421,61 +420,36 @@ fn read_hexa_char(input: &mut Chars<'_>, len: usize) -> Result<char, TermParseEr
}
/// An error raised during term serialization parsing using the [`FromStr`] trait.
#[derive(Debug)]
pub struct TermParseError {
kind: TermParseErrorKind,
}
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct TermParseError(#[from] TermParseErrorKind);
#[derive(Debug)]
/// An internal error raised during term serialization parsing using the [`FromStr`] trait.
#[derive(Debug, thiserror::Error)]
enum TermParseErrorKind {
Iri {
error: IriParseError,
value: String,
},
#[error("Error while parsing the named node '{value}': {error}")]
Iri { error: IriParseError, value: String },
#[error("Error while parsing the blank node '{value}': {error}")]
BlankNode {
error: BlankNodeIdParseError,
value: String,
},
#[error("Error while parsing the language tag '{value}': {error}")]
LanguageTag {
error: LanguageTagParseError,
value: String,
},
#[error("Error while parsing the variable '{value}': {error}")]
Variable {
error: VariableNameParseError,
value: String,
},
Msg {
msg: &'static str,
},
#[error("{0}")]
Msg(&'static str),
}
impl fmt::Display for TermParseError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
TermParseErrorKind::Iri { error, value } => {
write!(f, "Error while parsing the named node '{value}': {error}")
}
TermParseErrorKind::BlankNode { error, value } => {
write!(f, "Error while parsing the blank node '{value}': {error}")
}
TermParseErrorKind::LanguageTag { error, value } => {
write!(f, "Error while parsing the language tag '{value}': {error}")
}
TermParseErrorKind::Variable { error, value } => {
write!(f, "Error while parsing the variable '{value}': {error}")
}
TermParseErrorKind::Msg { msg } => f.write_str(msg),
}
}
}
impl Error for TermParseError {}
impl TermParseError {
pub(crate) fn msg(msg: &'static str) -> Self {
Self {
kind: TermParseErrorKind::Msg { msg },
}
Self(TermParseErrorKind::Msg(msg))
}
}

@ -1,5 +1,4 @@
use std::cmp::Ordering;
use std::error::Error;
use std::fmt;
/// A [SPARQL query](https://www.w3.org/TR/sparql11-query/) owned variable.
@ -212,14 +211,6 @@ fn validate_variable_identifier(id: &str) -> Result<(), VariableNameParseError>
}
/// An error raised during [`Variable`] name validation.
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
#[error("The variable name is invalid")]
pub struct VariableNameParseError;
impl fmt::Display for VariableNameParseError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("The variable name is invalid")
}
}
impl Error for VariableNameParseError {}

@ -22,6 +22,7 @@ rdf-star = ["oxrdf/rdf-star", "oxttl/rdf-star"]
oxrdf.workspace = true
oxrdfxml.workspace = true
oxttl.workspace = true
thiserror.workspace = true
tokio = { workspace = true, optional = true, features = ["io-util"] }
[dev-dependencies]

@ -1,50 +1,27 @@
use std::error::Error;
use std::io;
use std::ops::Range;
use std::{fmt, io};
/// Error returned during RDF format parsing.
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
/// I/O error during parsing (file not found...).
Io(io::Error),
#[error(transparent)]
Io(#[from] io::Error),
/// An error in the file syntax.
Syntax(SyntaxError),
#[error(transparent)]
Syntax(#[from] SyntaxError),
}
impl ParseError {
pub(crate) fn msg(msg: &'static str) -> Self {
Self::Syntax(SyntaxError {
inner: SyntaxErrorKind::Msg { msg },
})
}
}
impl fmt::Display for ParseError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => e.fmt(f),
Self::Syntax(e) => e.fmt(f),
}
}
}
impl Error for ParseError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Syntax(e) => Some(e),
}
Self::Syntax(SyntaxError(SyntaxErrorKind::Msg(msg)))
}
}
impl From<oxttl::SyntaxError> for SyntaxError {
#[inline]
fn from(error: oxttl::SyntaxError) -> Self {
Self {
inner: SyntaxErrorKind::Turtle(error),
}
Self(SyntaxErrorKind::Turtle(error))
}
}
@ -61,9 +38,7 @@ impl From<oxttl::ParseError> for ParseError {
impl From<oxrdfxml::SyntaxError> for SyntaxError {
#[inline]
fn from(error: oxrdfxml::SyntaxError) -> Self {
Self {
inner: SyntaxErrorKind::RdfXml(error),
}
Self(SyntaxErrorKind::RdfXml(error))
}
}
@ -77,20 +52,6 @@ impl From<oxrdfxml::ParseError> for ParseError {
}
}
impl From<io::Error> for ParseError {
#[inline]
fn from(error: io::Error) -> Self {
Self::Io(error)
}
}
impl From<SyntaxError> for ParseError {
#[inline]
fn from(error: SyntaxError) -> Self {
Self::Syntax(error)
}
}
impl From<ParseError> for io::Error {
#[inline]
fn from(error: ParseError) -> Self {
@ -102,23 +63,26 @@ impl From<ParseError> for io::Error {
}
/// An error in the syntax of the parsed file.
#[derive(Debug)]
pub struct SyntaxError {
inner: SyntaxErrorKind,
}
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct SyntaxError(#[from] SyntaxErrorKind);
#[derive(Debug)]
/// An error in the syntax of the parsed file.
#[derive(Debug, thiserror::Error)]
enum SyntaxErrorKind {
Turtle(oxttl::SyntaxError),
RdfXml(oxrdfxml::SyntaxError),
Msg { msg: &'static str },
#[error(transparent)]
Turtle(#[from] oxttl::SyntaxError),
#[error(transparent)]
RdfXml(#[from] oxrdfxml::SyntaxError),
#[error("{0}")]
Msg(&'static str),
}
impl SyntaxError {
/// The location of the error inside of the file.
#[inline]
pub fn location(&self) -> Option<Range<TextPosition>> {
match &self.inner {
match &self.0 {
SyntaxErrorKind::Turtle(e) => {
let location = e.location();
Some(
@ -133,29 +97,7 @@ impl SyntaxError {
},
)
}
SyntaxErrorKind::RdfXml(_) | SyntaxErrorKind::Msg { .. } => None,
}
}
}
impl fmt::Display for SyntaxError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
SyntaxErrorKind::Turtle(e) => e.fmt(f),
SyntaxErrorKind::RdfXml(e) => e.fmt(f),
SyntaxErrorKind::Msg { msg } => f.write_str(msg),
}
}
}
impl Error for SyntaxError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.inner {
SyntaxErrorKind::Turtle(e) => Some(e),
SyntaxErrorKind::RdfXml(e) => Some(e),
SyntaxErrorKind::Msg { .. } => None,
SyntaxErrorKind::RdfXml(_) | SyntaxErrorKind::Msg(_) => None,
}
}
}
@ -163,10 +105,10 @@ impl Error for SyntaxError {
impl From<SyntaxError> for io::Error {
#[inline]
fn from(error: SyntaxError) -> Self {
match error.inner {
match error.0 {
SyntaxErrorKind::Turtle(error) => error.into(),
SyntaxErrorKind::RdfXml(error) => error.into(),
SyntaxErrorKind::Msg { msg } => Self::new(io::ErrorKind::InvalidData, msg),
SyntaxErrorKind::Msg(msg) => Self::new(io::ErrorKind::InvalidData, msg),
}
}
}

@ -22,6 +22,7 @@ oxilangtag.workspace = true
oxiri.workspace = true
oxrdf.workspace = true
quick-xml.workspace = true
thiserror.workspace = true
tokio = { workspace = true, optional = true, features = ["io-util"] }
[dev-dependencies]

@ -1,50 +1,17 @@
use oxilangtag::LanguageTagParseError;
use oxiri::IriParseError;
use std::error::Error;
use std::io;
use std::sync::Arc;
use std::{fmt, io};
/// Error returned during RDF/XML parsing.
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
/// I/O error during parsing (file not found...).
Io(io::Error),
#[error(transparent)]
Io(#[from] io::Error),
/// An error in the file syntax.
Syntax(SyntaxError),
}
impl fmt::Display for ParseError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => e.fmt(f),
Self::Syntax(e) => e.fmt(f),
}
}
}
impl Error for ParseError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Syntax(e) => Some(e),
}
}
}
impl From<io::Error> for ParseError {
#[inline]
fn from(error: io::Error) -> Self {
Self::Io(error)
}
}
impl From<SyntaxError> for ParseError {
#[inline]
fn from(error: SyntaxError) -> Self {
Self::Syntax(error)
}
#[error(transparent)]
Syntax(#[from] SyntaxError),
}
impl From<ParseError> for io::Error {
@ -64,77 +31,48 @@ impl From<quick_xml::Error> for ParseError {
quick_xml::Error::Io(error) => {
Self::Io(Arc::try_unwrap(error).unwrap_or_else(|e| io::Error::new(e.kind(), e)))
}
_ => Self::Syntax(SyntaxError {
inner: SyntaxErrorKind::Xml(error),
}),
_ => Self::Syntax(SyntaxError(SyntaxErrorKind::Xml(error))),
}
}
}
/// An error in the syntax of the parsed file.
#[derive(Debug)]
pub struct SyntaxError {
pub(crate) inner: SyntaxErrorKind,
}
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct SyntaxError(#[from] pub(crate) SyntaxErrorKind);
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub enum SyntaxErrorKind {
Xml(quick_xml::Error),
#[error(transparent)]
Xml(#[from] quick_xml::Error),
#[error("error while parsing IRI '{iri}': {error}")]
InvalidIri {
iri: String,
#[source]
error: IriParseError,
},
#[error("error while parsing language tag '{tag}': {error}")]
InvalidLanguageTag {
tag: String,
#[source]
error: LanguageTagParseError,
},
Msg {
msg: String,
},
#[error("{0}")]
Msg(String),
}
impl SyntaxError {
/// Builds an error from a printable error message.
#[inline]
pub(crate) fn msg(msg: impl Into<String>) -> Self {
Self {
inner: SyntaxErrorKind::Msg { msg: msg.into() },
}
}
}
impl fmt::Display for SyntaxError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
SyntaxErrorKind::Xml(error) => error.fmt(f),
SyntaxErrorKind::InvalidIri { iri, error } => {
write!(f, "error while parsing IRI '{iri}': {error}")
}
SyntaxErrorKind::InvalidLanguageTag { tag, error } => {
write!(f, "error while parsing language tag '{tag}': {error}")
}
SyntaxErrorKind::Msg { msg } => f.write_str(msg),
}
}
}
impl Error for SyntaxError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.inner {
SyntaxErrorKind::Xml(error) => Some(error),
SyntaxErrorKind::InvalidIri { error, .. } => Some(error),
SyntaxErrorKind::InvalidLanguageTag { error, .. } => Some(error),
SyntaxErrorKind::Msg { .. } => None,
}
Self(SyntaxErrorKind::Msg(msg.into()))
}
}
impl From<SyntaxError> for io::Error {
#[inline]
fn from(error: SyntaxError) -> Self {
match error.inner {
match error.0 {
SyntaxErrorKind::Xml(error) => match error {
quick_xml::Error::Io(error) => {
Arc::try_unwrap(error).unwrap_or_else(|e| Self::new(e.kind(), e))
@ -144,7 +82,7 @@ impl From<SyntaxError> for io::Error {
}
_ => Self::new(io::ErrorKind::InvalidData, error),
},
SyntaxErrorKind::Msg { msg } => Self::new(io::ErrorKind::InvalidData, msg),
SyntaxErrorKind::Msg(msg) => Self::new(io::ErrorKind::InvalidData, msg),
_ => Self::new(io::ErrorKind::InvalidData, error),
}
}

@ -575,8 +575,8 @@ impl<R> RdfXmlReader<R> {
tag
} else {
LanguageTag::parse(tag.to_ascii_lowercase())
.map_err(|error| SyntaxError {
inner: SyntaxErrorKind::InvalidLanguageTag { tag, error },
.map_err(|error| {
SyntaxError(SyntaxErrorKind::InvalidLanguageTag { tag, error })
})?
.into_inner()
});
@ -588,9 +588,7 @@ impl<R> RdfXmlReader<R> {
} else {
Iri::parse(iri.clone())
}
.map_err(|error| SyntaxError {
inner: SyntaxErrorKind::InvalidIri { iri, error },
})?,
.map_err(|error| SyntaxError(SyntaxErrorKind::InvalidIri { iri, error }))?,
)
} else {
// We ignore other xml attributes
@ -1169,11 +1167,11 @@ impl<R> RdfXmlReader<R> {
} else {
base_iri.resolve(&relative_iri)
}
.map_err(|error| SyntaxError {
inner: SyntaxErrorKind::InvalidIri {
.map_err(|error| {
SyntaxError(SyntaxErrorKind::InvalidIri {
iri: relative_iri,
error,
},
})
})?
.into_inner(),
))
@ -1187,11 +1185,11 @@ impl<R> RdfXmlReader<R> {
relative_iri
} else {
Iri::parse(relative_iri.clone())
.map_err(|error| SyntaxError {
inner: SyntaxErrorKind::InvalidIri {
.map_err(|error| {
SyntaxError(SyntaxErrorKind::InvalidIri {
iri: relative_iri,
error,
},
})
})?
.into_inner()
}))

@ -17,6 +17,9 @@ rust-version.workspace = true
js = ["js-sys"]
custom-now = []
[dependencies]
thiserror.workspace = true
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
js-sys = { workspace = true, optional = true }

@ -2,7 +2,6 @@
use crate::{DayTimeDuration, Decimal, Duration, YearMonthDuration};
use std::cmp::{min, Ordering};
use std::error::Error;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
@ -2039,42 +2038,28 @@ fn time_on_timeline(props: &DateTimeSevenPropertyModel) -> Option<Decimal> {
}
/// A parsing error
#[derive(Debug, Clone)]
pub struct ParseDateTimeError {
kind: ParseDateTimeErrorKind,
}
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct ParseDateTimeError(#[from] ParseDateTimeErrorKind);
#[derive(Debug, Clone)]
#[derive(Debug, Clone, thiserror::Error)]
enum ParseDateTimeErrorKind {
#[error("{day} is not a valid day of {month}")]
InvalidDayOfMonth { day: u8, month: u8 },
Overflow(DateTimeOverflowError),
#[error(transparent)]
Overflow(#[from] DateTimeOverflowError),
#[error(transparent)]
InvalidTimezone(InvalidTimezoneError),
#[error("{0}")]
Message(&'static str),
}
impl fmt::Display for ParseDateTimeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
ParseDateTimeErrorKind::InvalidDayOfMonth { day, month } => {
write!(f, "{day} is not a valid day of {month}")
}
ParseDateTimeErrorKind::Overflow(error) => error.fmt(f),
ParseDateTimeErrorKind::InvalidTimezone(error) => error.fmt(f),
ParseDateTimeErrorKind::Message(msg) => f.write_str(msg),
}
}
}
impl ParseDateTimeError {
const fn msg(message: &'static str) -> Self {
Self {
kind: ParseDateTimeErrorKind::Message(message),
}
Self(ParseDateTimeErrorKind::Message(message))
}
}
impl Error for ParseDateTimeError {}
// [16] dateTimeLexicalRep ::= yearFrag '-' monthFrag '-' dayFrag 'T' ((hourFrag ':' minuteFrag ':' secondFrag) | endOfDayFrag) timezoneFrag?
fn date_time_lexical_rep(input: &str) -> Result<(DateTime, &str), ParseDateTimeError> {
let (year, input) = year_frag(input)?;
@ -2326,11 +2311,8 @@ fn timezone_frag(input: &str) -> Result<(TimezoneOffset, &str), ParseDateTimeErr
}
Ok((
TimezoneOffset::new(sign * (hours * 60 + i16::from(minutes))).map_err(|e| {
ParseDateTimeError {
kind: ParseDateTimeErrorKind::InvalidTimezone(e),
}
})?,
TimezoneOffset::new(sign * (hours * 60 + i16::from(minutes)))
.map_err(|e| ParseDateTimeError(ParseDateTimeErrorKind::InvalidTimezone(e)))?,
input,
))
}
@ -2400,9 +2382,9 @@ fn optional_end<T>(
fn validate_day_of_month(year: Option<i64>, month: u8, day: u8) -> Result<(), ParseDateTimeError> {
// Constraint: Day-of-month Values
if day > days_in_month(year, month) {
return Err(ParseDateTimeError {
kind: ParseDateTimeErrorKind::InvalidDayOfMonth { day, month },
});
return Err(ParseDateTimeError(
ParseDateTimeErrorKind::InvalidDayOfMonth { day, month },
));
}
Ok(())
}
@ -2410,51 +2392,33 @@ fn validate_day_of_month(year: Option<i64>, month: u8, day: u8) -> Result<(), Pa
/// An overflow during [`DateTime`]-related operations.
///
/// Matches XPath [`FODT0001` error](https://www.w3.org/TR/xpath-functions-31/#ERRFODT0001).
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, thiserror::Error)]
#[error("overflow during xsd:dateTime computation")]
pub struct DateTimeOverflowError;
impl fmt::Display for DateTimeOverflowError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("overflow during xsd:dateTime computation")
}
}
impl Error for DateTimeOverflowError {}
impl From<DateTimeOverflowError> for ParseDateTimeError {
fn from(error: DateTimeOverflowError) -> Self {
Self {
kind: ParseDateTimeErrorKind::Overflow(error),
}
Self(ParseDateTimeErrorKind::Overflow(error))
}
}
/// The value provided as timezone is not valid.
///
/// Matches XPath [`FODT0003` error](https://www.w3.org/TR/xpath-functions-31/#ERRFODT0003).
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, thiserror::Error)]
#[error("invalid timezone offset {}:{}",
self.offset_in_minutes / 60,
self.offset_in_minutes.abs() % 60)]
pub struct InvalidTimezoneError {
offset_in_minutes: i64,
}
impl fmt::Display for InvalidTimezoneError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"invalid timezone offset {}:{}",
self.offset_in_minutes / 60,
self.offset_in_minutes.abs() % 60
)
}
}
impl Error for InvalidTimezoneError {}
#[cfg(test)]
mod tests {
#![allow(clippy::panic_in_result_fn)]
use super::*;
use std::error::Error;
#[test]
fn from_str() -> Result<(), ParseDateTimeError> {

@ -1,5 +1,4 @@
use crate::{Boolean, Double, Float, Integer, TooLargeForIntegerError};
use std::error::Error;
use std::fmt;
use std::fmt::Write;
use std::str::FromStr;
@ -609,67 +608,42 @@ impl fmt::Display for Decimal {
}
/// An error when parsing a [`Decimal`].
#[derive(Debug, Clone)]
pub struct ParseDecimalError {
kind: DecimalParseErrorKind,
}
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct ParseDecimalError(#[from] DecimalParseErrorKind);
#[derive(Debug, Clone)]
#[derive(Debug, Clone, thiserror::Error)]
enum DecimalParseErrorKind {
#[error("Value overflow")]
Overflow,
#[error("Value underflow")]
Underflow,
#[error("Unexpected character")]
UnexpectedChar,
#[error("Unexpected end of string")]
UnexpectedEnd,
}
const PARSE_OVERFLOW: ParseDecimalError = ParseDecimalError {
kind: DecimalParseErrorKind::Overflow,
};
const PARSE_UNDERFLOW: ParseDecimalError = ParseDecimalError {
kind: DecimalParseErrorKind::Underflow,
};
const PARSE_UNEXPECTED_CHAR: ParseDecimalError = ParseDecimalError {
kind: DecimalParseErrorKind::UnexpectedChar,
};
const PARSE_UNEXPECTED_END: ParseDecimalError = ParseDecimalError {
kind: DecimalParseErrorKind::UnexpectedEnd,
};
impl fmt::Display for ParseDecimalError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
DecimalParseErrorKind::Overflow => f.write_str("Value overflow"),
DecimalParseErrorKind::Underflow => f.write_str("Value underflow"),
DecimalParseErrorKind::UnexpectedChar => f.write_str("Unexpected character"),
DecimalParseErrorKind::UnexpectedEnd => f.write_str("Unexpected end of string"),
}
}
}
impl Error for ParseDecimalError {}
const PARSE_OVERFLOW: ParseDecimalError = ParseDecimalError(DecimalParseErrorKind::Overflow);
const PARSE_UNDERFLOW: ParseDecimalError = ParseDecimalError(DecimalParseErrorKind::Underflow);
const PARSE_UNEXPECTED_CHAR: ParseDecimalError =
ParseDecimalError(DecimalParseErrorKind::UnexpectedChar);
const PARSE_UNEXPECTED_END: ParseDecimalError =
ParseDecimalError(DecimalParseErrorKind::UnexpectedEnd);
impl From<TooLargeForDecimalError> for ParseDecimalError {
fn from(_: TooLargeForDecimalError) -> Self {
Self {
kind: DecimalParseErrorKind::Overflow,
}
Self(DecimalParseErrorKind::Overflow)
}
}
/// The input is too large to fit into a [`Decimal`].
///
/// Matches XPath [`FOCA0001` error](https://www.w3.org/TR/xpath-functions-31/#ERRFOCA0001).
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, thiserror::Error)]
#[error("Value too large for xsd:decimal internal representation")]
pub struct TooLargeForDecimalError;
impl fmt::Display for TooLargeForDecimalError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Value too large for xsd:decimal internal representation")
}
}
impl Error for TooLargeForDecimalError {}
#[cfg(test)]
mod tests {
#![allow(clippy::panic_in_result_fn)]

@ -1,6 +1,5 @@
use crate::{DateTime, Decimal};
use std::cmp::Ordering;
use std::error::Error;
use std::fmt;
use std::str::FromStr;
use std::time::Duration as StdDuration;
@ -937,7 +936,8 @@ fn decimal_prefix(input: &str) -> (&str, &str) {
}
/// A parsing error
#[derive(Debug, Clone)]
#[derive(Debug, Clone, thiserror::Error)]
#[error("{msg}")]
pub struct ParseDurationError {
msg: &'static str,
}
@ -946,46 +946,24 @@ const OVERFLOW_ERROR: ParseDurationError = ParseDurationError {
msg: "Overflow error",
};
impl fmt::Display for ParseDurationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.msg)
}
}
impl ParseDurationError {
const fn msg(msg: &'static str) -> Self {
Self { msg }
}
}
impl Error for ParseDurationError {}
/// An overflow during [`Duration`]-related operations.
///
/// Matches XPath [`FODT0002` error](https://www.w3.org/TR/xpath-functions-31/#ERRFODT0002).
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, thiserror::Error)]
#[error("overflow during xsd:duration computation")]
pub struct DurationOverflowError;
impl fmt::Display for DurationOverflowError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("overflow during xsd:duration computation")
}
}
impl Error for DurationOverflowError {}
/// The year-month and the day-time components of a [`Duration`] have an opposite sign.
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, thiserror::Error)]
#[error("The xsd:yearMonthDuration and xsd:dayTimeDuration components of a xsd:duration can't have opposite sign")]
pub struct OppositeSignInDurationComponentsError;
impl fmt::Display for OppositeSignInDurationComponentsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("The xsd:yearMonthDuration and xsd:dayTimeDuration components of a xsd:duration can't have opposite sign")
}
}
impl Error for OppositeSignInDurationComponentsError {}
impl From<OppositeSignInDurationComponentsError> for ParseDurationError {
#[inline]
fn from(_: OppositeSignInDurationComponentsError) -> Self {
@ -1000,6 +978,7 @@ mod tests {
#![allow(clippy::panic_in_result_fn)]
use super::*;
use std::error::Error;
#[test]
fn from_str() -> Result<(), ParseDurationError> {

@ -1,5 +1,4 @@
use crate::{Boolean, Decimal, Double, Float};
use std::error::Error;
use std::fmt;
use std::num::ParseIntError;
use std::str::FromStr;
@ -264,17 +263,10 @@ impl TryFrom<Double> for Integer {
/// The input is too large to fit into an [`Integer`].
///
/// Matches XPath [`FOCA0003` error](https://www.w3.org/TR/xpath-functions-31/#ERRFOCA0003).
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, thiserror::Error)]
#[error("Value too large for xsd:integer internal representation")]
pub struct TooLargeForIntegerError;
impl fmt::Display for TooLargeForIntegerError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Value too large for xsd:integer internal representation")
}
}
impl Error for TooLargeForIntegerError {}
#[cfg(test)]
mod tests {
#![allow(clippy::panic_in_result_fn)]

@ -23,6 +23,7 @@ memchr.workspace = true
oxrdf.workspace = true
oxiri.workspace = true
oxilangtag.workspace = true
thiserror.workspace = true
tokio = { workspace = true, optional = true, features = ["io-util"] }
[dev-dependencies]

@ -1,4 +1,3 @@
use std::error::Error;
use std::ops::Range;
use std::{fmt, io};
@ -13,7 +12,7 @@ pub struct TextPosition {
/// An error in the syntax of the parsed file.
///
/// It is composed of a message and a byte range in the input.
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub struct SyntaxError {
pub(super) location: Range<TextPosition>,
pub(super) message: String,
@ -67,8 +66,6 @@ impl fmt::Display for SyntaxError {
}
}
impl Error for SyntaxError {}
impl From<SyntaxError> for io::Error {
#[inline]
fn from(error: SyntaxError) -> Self {
@ -79,46 +76,14 @@ impl From<SyntaxError> for io::Error {
/// A parsing error.
///
/// It is the union of [`SyntaxError`] and [`io::Error`].
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
/// I/O error during parsing (file not found...).
Io(io::Error),
#[error(transparent)]
Io(#[from] io::Error),
/// An error in the file syntax.
Syntax(SyntaxError),
}
impl fmt::Display for ParseError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => e.fmt(f),
Self::Syntax(e) => e.fmt(f),
}
}
}
impl Error for ParseError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(match self {
Self::Io(e) => e,
Self::Syntax(e) => e,
})
}
}
impl From<SyntaxError> for ParseError {
#[inline]
fn from(error: SyntaxError) -> Self {
Self::Syntax(error)
}
}
impl From<io::Error> for ParseError {
#[inline]
fn from(error: io::Error) -> Self {
Self::Io(error)
}
#[error(transparent)]
Syntax(#[from] SyntaxError),
}
impl From<ParseError> for io::Error {

@ -23,6 +23,7 @@ json-event-parser.workspace = true
memchr.workspace = true
oxrdf.workspace = true
quick-xml.workspace = true
thiserror.workspace = true
tokio = { workspace = true, optional = true, features = ["io-util"] }
[dev-dependencies]

@ -1,50 +1,17 @@
use oxrdf::TermParseError;
use std::error::Error;
use std::io;
use std::ops::Range;
use std::sync::Arc;
use std::{fmt, io};
/// Error returned during SPARQL result formats format parsing.
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub enum ParseError {
/// I/O error during parsing (file not found...).
Io(io::Error),
#[error(transparent)]
Io(#[from] io::Error),
/// An error in the file syntax.
Syntax(SyntaxError),
}
impl fmt::Display for ParseError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => e.fmt(f),
Self::Syntax(e) => e.fmt(f),
}
}
}
impl Error for ParseError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Syntax(e) => Some(e),
}
}
}
impl From<io::Error> for ParseError {
#[inline]
fn from(error: io::Error) -> Self {
Self::Io(error)
}
}
impl From<SyntaxError> for ParseError {
#[inline]
fn from(error: SyntaxError) -> Self {
Self::Syntax(error)
}
#[error(transparent)]
Syntax(#[from] SyntaxError),
}
impl From<ParseError> for io::Error {
@ -81,20 +48,27 @@ impl From<quick_xml::Error> for ParseError {
}
/// An error in the syntax of the parsed file.
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct SyntaxError {
#[from]
pub(crate) inner: SyntaxErrorKind,
}
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
pub(crate) enum SyntaxErrorKind {
Json(json_event_parser::SyntaxError),
Xml(quick_xml::Error),
#[error(transparent)]
Json(#[from] json_event_parser::SyntaxError),
#[error(transparent)]
Xml(#[from] quick_xml::Error),
#[error("Error {error} on '{term}' in line {}", location.start.line + 1)]
Term {
#[source]
error: TermParseError,
term: String,
location: Range<TextPosition>,
},
#[error("{msg}")]
Msg {
msg: String,
location: Option<Range<TextPosition>>,
@ -149,34 +123,6 @@ impl SyntaxError {
}
}
impl fmt::Display for SyntaxError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
SyntaxErrorKind::Json(e) => e.fmt(f),
SyntaxErrorKind::Xml(e) => e.fmt(f),
SyntaxErrorKind::Term {
error,
term,
location,
} => write!(f, "{error} on '{term}' in line {}", location.start.line + 1),
SyntaxErrorKind::Msg { msg, .. } => f.write_str(msg),
}
}
}
impl Error for SyntaxError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.inner {
SyntaxErrorKind::Json(e) => Some(e),
SyntaxErrorKind::Xml(e) => Some(e),
SyntaxErrorKind::Term { error, .. } => Some(error),
SyntaxErrorKind::Msg { .. } => None,
}
}
}
impl From<SyntaxError> for io::Error {
#[inline]
fn from(error: SyntaxError) -> Self {

@ -25,6 +25,7 @@ oxiri.workspace = true
oxrdf.workspace = true
peg.workspace = true
rand.workspace = true
thiserror.workspace = true
[lints]
workspace = true

@ -9,26 +9,22 @@ use oxrdf::vocab::{rdf, xsd};
use peg::parser;
use peg::str::LineCol;
use rand::random;
use std::char;
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::mem::take;
use std::str::FromStr;
use std::{char, fmt};
/// Parses a SPARQL query with an optional base IRI to resolve relative IRIs in the query.
pub fn parse_query(query: &str, base_iri: Option<&str>) -> Result<Query, ParseError> {
let mut state = ParserState::from_base_iri(base_iri)?;
parser::QueryUnit(query, &mut state).map_err(|e| ParseError {
inner: ParseErrorKind::Parser(e),
})
parser::QueryUnit(query, &mut state).map_err(|e| ParseError(ParseErrorKind::Parser(e)))
}
/// Parses a SPARQL update with an optional base IRI to resolve relative IRIs in the query.
pub fn parse_update(update: &str, base_iri: Option<&str>) -> Result<Update, ParseError> {
let mut state = ParserState::from_base_iri(base_iri)?;
let operations = parser::UpdateInit(update, &mut state).map_err(|e| ParseError {
inner: ParseErrorKind::Parser(e),
})?;
let operations = parser::UpdateInit(update, &mut state)
.map_err(|e| ParseError(ParseErrorKind::Parser(e)))?;
Ok(Update {
operations,
base_iri: state.base_iri,
@ -36,37 +32,16 @@ pub fn parse_update(update: &str, base_iri: Option<&str>) -> Result<Update, Pars
}
/// Error returned during SPARQL parsing.
#[derive(Debug)]
pub struct ParseError {
inner: ParseErrorKind,
}
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct ParseError(#[from] ParseErrorKind);
#[derive(Debug)]
#[derive(Debug, thiserror::Error)]
enum ParseErrorKind {
InvalidBaseIri(IriParseError),
Parser(peg::error::ParseError<LineCol>),
}
impl fmt::Display for ParseError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
ParseErrorKind::InvalidBaseIri(e) => {
write!(f, "Invalid SPARQL base IRI provided: {e}")
}
ParseErrorKind::Parser(e) => e.fmt(f),
}
}
}
impl Error for ParseError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.inner {
ParseErrorKind::InvalidBaseIri(e) => Some(e),
ParseErrorKind::Parser(e) => Some(e),
}
}
#[error("Invalid SPARQL base IRI provided: {0}")]
InvalidBaseIri(#[from] IriParseError),
#[error(transparent)]
Parser(#[from] peg::error::ParseError<LineCol>),
}
struct AnnotatedTerm {
@ -697,9 +672,10 @@ impl ParserState {
pub(crate) fn from_base_iri(base_iri: Option<&str>) -> Result<Self, ParseError> {
Ok(Self {
base_iri: if let Some(base_iri) = base_iri {
Some(Iri::parse(base_iri.to_owned()).map_err(|e| ParseError {
inner: ParseErrorKind::InvalidBaseIri(e),
})?)
Some(
Iri::parse(base_iri.to_owned())
.map_err(|e| ParseError(ParseErrorKind::InvalidBaseIri(e)))?,
)
} else {
None
},

Loading…
Cancel
Save