From b50a6fa13ad3c294cc7716f93f3b366067a1c84f Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Sat, 10 Feb 2024 00:41:08 -0500 Subject: [PATCH] Address feedback, preserving inner err --- lib/oxigraph/src/storage/error.rs | 4 +- lib/oxrdf/src/parser.rs | 106 +++++++++++++++--------------- lib/oxrdfio/src/error.rs | 33 +++++----- lib/oxrdfxml/src/error.rs | 23 +++++-- lib/oxrdfxml/src/parser.rs | 26 +++++--- lib/oxsdatatypes/src/date_time.rs | 20 ++++-- lib/oxsdatatypes/src/decimal.rs | 37 +++++++---- lib/sparesults/src/csv.rs | 34 +++++----- lib/sparesults/src/error.rs | 57 +++++++++++----- lib/spargebra/src/parser.rs | 16 +++-- 10 files changed, 215 insertions(+), 141 deletions(-) diff --git a/lib/oxigraph/src/storage/error.rs b/lib/oxigraph/src/storage/error.rs index 13a257f8..6e4b108f 100644 --- a/lib/oxigraph/src/storage/error.rs +++ b/lib/oxigraph/src/storage/error.rs @@ -49,7 +49,7 @@ impl CorruptionError { /// Builds an error from a printable error message. #[inline] pub(crate) fn new(error: impl Into>) -> Self { - CorruptionErrorKind::Other(error.into()).into() + Self(CorruptionErrorKind::Other(error.into())) } #[inline] @@ -67,7 +67,7 @@ impl CorruptionError { /// Builds an error from a printable error message. #[inline] pub(crate) fn msg(msg: impl Into) -> Self { - CorruptionErrorKind::Msg(msg.into()).into() + Self(CorruptionErrorKind::Msg(msg.into())) } } diff --git a/lib/oxrdf/src/parser.rs b/lib/oxrdf/src/parser.rs index 344d5227..59f488cd 100644 --- a/lib/oxrdf/src/parser.rs +++ b/lib/oxrdf/src/parser.rs @@ -29,9 +29,9 @@ impl FromStr for NamedNode { fn from_str(s: &str) -> Result { let (term, left) = read_named_node(s)?; if !left.is_empty() { - return Err(TermParseErrorKind::msg( + return Err(Self::Err::msg( "Named node serialization should end with a >", - ))?; + )); } Ok(term) } @@ -54,9 +54,9 @@ impl FromStr for BlankNode { fn from_str(s: &str) -> Result { let (term, left) = read_blank_node(s)?; if !left.is_empty() { - return Err(TermParseErrorKind::msg( + return Err(Self::Err::msg( "Blank node serialization should not contain whitespaces", - ))?; + )); } Ok(term) } @@ -107,7 +107,7 @@ impl FromStr for Literal { fn from_str(s: &str) -> Result { let (term, left) = read_literal(s)?; if !left.is_empty() { - return Err(TermParseErrorKind::msg("Invalid literal serialization"))?; + return Err(Self::Err::msg("Invalid literal serialization")); } Ok(term) } @@ -139,7 +139,7 @@ impl FromStr for Term { fn from_str(s: &str) -> Result { let (term, left) = read_term(s, 0)?; if !left.is_empty() { - return Err(TermParseErrorKind::msg("Invalid term serialization"))?; + return Err(Self::Err::msg("Invalid term serialization")); } Ok(term) } @@ -161,40 +161,42 @@ impl FromStr for Variable { /// ``` fn from_str(s: &str) -> Result { if !s.starts_with('?') && !s.starts_with('$') { - return Err(TermParseErrorKind::msg( + return Err(Self::Err::msg( "Variable serialization should start with ? or $", - ))?; + )); } - Ok( - Self::new(&s[1..]).map_err(|error| TermParseErrorKind::Variable { + Self::new(&s[1..]).map_err(|error| { + TermParseError(TermParseErrorKind::Variable { value: s.to_owned(), error, - })?, - ) + }) + }) } } -fn read_named_node(s: &str) -> Result<(NamedNode, &str), TermParseErrorKind> { +fn read_named_node(s: &str) -> Result<(NamedNode, &str), TermParseError> { let s = s.trim(); if let Some(remain) = s.strip_prefix('<') { - let end = remain.find('>').ok_or_else(|| { - TermParseErrorKind::msg("Named node serialization should end with a >") - })?; + let end = remain + .find('>') + .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| TermParseErrorKind::Iri { - value: value.to_owned(), - error, + let term = NamedNode::new(value).map_err(|error| { + TermParseError(TermParseErrorKind::Iri { + value: value.to_owned(), + error, + }) })?; Ok((term, remain)) } else { - Err(TermParseErrorKind::msg( + Err(TermParseError::msg( "Named node serialization should start with a <", )) } } -fn read_blank_node(s: &str) -> Result<(BlankNode, &str), TermParseErrorKind> { +fn read_blank_node(s: &str) -> Result<(BlankNode, &str), TermParseError> { let s = s.trim(); if let Some(remain) = s.strip_prefix("_:") { let end = remain @@ -204,19 +206,21 @@ fn read_blank_node(s: &str) -> Result<(BlankNode, &str), TermParseErrorKind> { }) .unwrap_or(remain.len()); let (value, remain) = remain.split_at(end); - let term = BlankNode::new(value).map_err(|error| TermParseErrorKind::BlankNode { - value: value.to_owned(), - error, + let term = BlankNode::new(value).map_err(|error| { + TermParseError(TermParseErrorKind::BlankNode { + value: value.to_owned(), + error, + }) })?; Ok((term, remain)) } else { - Err(TermParseErrorKind::msg( + Err(TermParseError::msg( "Blank node serialization should start with '_:'", - ))? + )) } } -fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> { +fn read_literal(s: &str) -> Result<(Literal, &str), TermParseError> { let s = s.trim(); if let Some(s) = s.strip_prefix('"') { let mut value = String::with_capacity(s.len()); @@ -232,9 +236,11 @@ fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> { let (language, remain) = remain.split_at(end); Ok(( Literal::new_language_tagged_literal(value, language).map_err( - |error| TermParseErrorKind::LanguageTag { - value: language.to_owned(), - error, + |error| { + TermParseError(TermParseErrorKind::LanguageTag { + value: language.to_owned(), + error, + }) }, )?, remain, @@ -259,16 +265,16 @@ fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> { '\\' => '\\', 'u' => read_hexa_char(&mut chars, 4)?, 'U' => read_hexa_char(&mut chars, 8)?, - _ => return Err(TermParseErrorKind::msg("Unexpected escaped char"))?, + _ => return Err(TermParseError::msg("Unexpected escaped char")), }) } else { - return Err(TermParseErrorKind::msg("Unexpected literal end")); + return Err(TermParseError::msg("Unexpected literal end")); } } _ => value.push(c), } } - Err(TermParseErrorKind::msg("Unexpected literal end")) + Err(TermParseError::msg("Unexpected literal end")) } else if let Some(remain) = s.strip_prefix("true") { Ok((Literal::new_typed_literal("true", xsd::BOOLEAN), remain)) } else if let Some(remain) = s.strip_prefix("false") { @@ -276,7 +282,7 @@ fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> { } else { let input = s.as_bytes(); if input.is_empty() { - return Err(TermParseErrorKind::msg("Empty term serialization")); + return Err(TermParseError::msg("Empty term serialization")); } let mut cursor = match input.first() { @@ -315,7 +321,7 @@ fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> { if count_exponent > 0 { Ok((Literal::new_typed_literal(s, xsd::DOUBLE), &s[cursor..])) } else { - Err(TermParseErrorKind::msg( + Err(TermParseError::msg( "Double serialization with an invalid exponent", )) } @@ -323,24 +329,21 @@ fn read_literal(s: &str) -> Result<(Literal, &str), TermParseErrorKind> { if count_after > 0 { Ok((Literal::new_typed_literal(s, xsd::DECIMAL), &s[cursor..])) } else { - Err(TermParseErrorKind::msg( + Err(TermParseError::msg( "Decimal serialization without floating part", )) } } else if count_before > 0 { Ok((Literal::new_typed_literal(s, xsd::INTEGER), &s[cursor..])) } else { - Err(TermParseErrorKind::msg("Empty integer serialization")) + Err(TermParseError::msg("Empty integer serialization")) } } } -fn read_term( - s: &str, - number_of_recursive_calls: usize, -) -> Result<(Term, &str), TermParseErrorKind> { +fn read_term(s: &str, number_of_recursive_calls: usize) -> Result<(Term, &str), TermParseError> { if number_of_recursive_calls == MAX_NUMBER_OF_NESTED_TRIPLES { - return Err(TermParseErrorKind::msg( + return Err(TermParseError::msg( "Too many nested triples. The parser fails here to avoid a stack overflow.", )); } @@ -360,7 +363,7 @@ fn read_term( Term::NamedNode(s) => s.into(), Term::BlankNode(s) => s.into(), Term::Literal(_) => { - return Err(TermParseErrorKind::msg( + return Err(TermParseError::msg( "Literals are not allowed in subject position", )) } @@ -373,14 +376,14 @@ fn read_term( remain, )) } else { - Err(TermParseErrorKind::msg( + Err(TermParseError::msg( "Nested triple serialization should be enclosed between << and >>", )) } } #[cfg(not(feature = "rdf-star"))] { - Err(TermParseErrorKind::msg("RDF-star is not supported")) + Err(TermParseError::msg("RDF-star is not supported")) } } else if s.starts_with('<') { let (term, remain) = read_named_node(s)?; @@ -394,7 +397,7 @@ fn read_term( } } -fn read_hexa_char(input: &mut Chars<'_>, len: usize) -> Result { +fn read_hexa_char(input: &mut Chars<'_>, len: usize) -> Result { let mut value = 0; for _ in 0..len { if let Some(c) = input.next() { @@ -404,17 +407,16 @@ fn read_hexa_char(input: &mut Chars<'_>, len: usize) -> Result u32::from(c) - u32::from('a') + 10, 'A'..='F' => u32::from(c) - u32::from('A') + 10, _ => { - return Err(TermParseErrorKind::msg( + return Err(TermParseError::msg( "Unexpected character in a unicode escape", )) } } } else { - return Err(TermParseErrorKind::msg("Unexpected literal string end")); + return Err(TermParseError::msg("Unexpected literal string end")); } } - char::from_u32(value) - .ok_or_else(|| TermParseErrorKind::msg("Invalid encoded unicode code point")) + char::from_u32(value).ok_or_else(|| TermParseError::msg("Invalid encoded unicode code point")) } /// An error raised during term serialization parsing using the [`FromStr`] trait. @@ -446,8 +448,8 @@ enum TermParseErrorKind { Msg { msg: &'static str }, } -impl TermParseErrorKind { +impl TermParseError { pub(crate) fn msg(msg: &'static str) -> Self { - TermParseErrorKind::Msg { msg } + Self(TermParseErrorKind::Msg { msg }) } } diff --git a/lib/oxrdfio/src/error.rs b/lib/oxrdfio/src/error.rs index 54e534d2..bc02d921 100644 --- a/lib/oxrdfio/src/error.rs +++ b/lib/oxrdfio/src/error.rs @@ -14,24 +14,16 @@ pub enum ParseError { impl ParseError { pub(crate) fn msg(msg: &'static str) -> Self { - Self::Syntax(SyntaxErrorKind::Msg { msg }.into()) + Self::Syntax(SyntaxError(SyntaxErrorKind::Msg { msg })) } } -// impl From for SyntaxError { -// #[inline] -// fn from(error: oxttl::SyntaxError) -> Self { -// Self(SyntaxErrorKind::Turtle(error)) -// } -// } -// -// impl From for SyntaxError { -// #[inline] -// fn from(error: oxrdfxml::SyntaxError) -> Self { -// Self(SyntaxErrorKind::RdfXml(error)) -// } -// } -// +impl From for SyntaxError { + #[inline] + fn from(error: oxttl::SyntaxError) -> Self { + Self(SyntaxErrorKind::Turtle(error)) + } +} impl From for ParseError { #[inline] @@ -43,6 +35,13 @@ impl From for ParseError { } } +impl From for SyntaxError { + #[inline] + fn from(error: oxrdfxml::SyntaxError) -> Self { + Self(SyntaxErrorKind::RdfXml(error)) + } +} + impl From for ParseError { #[inline] fn from(error: oxrdfxml::ParseError) -> Self { @@ -83,7 +82,7 @@ impl SyntaxError { /// The location of the error inside of the file. #[inline] pub fn location(&self) -> Option> { - match self { + match &self.0 { SyntaxErrorKind::Turtle(e) => { let location = e.location(); Some( @@ -106,7 +105,7 @@ impl SyntaxError { impl From for io::Error { #[inline] fn from(error: SyntaxError) -> Self { - match error { + match error.0 { SyntaxErrorKind::Turtle(error) => error.into(), SyntaxErrorKind::RdfXml(error) => error.into(), SyntaxErrorKind::Msg { msg } => Self::new(io::ErrorKind::InvalidData, msg), diff --git a/lib/oxrdfxml/src/error.rs b/lib/oxrdfxml/src/error.rs index 1174f09d..77e38341 100644 --- a/lib/oxrdfxml/src/error.rs +++ b/lib/oxrdfxml/src/error.rs @@ -31,14 +31,23 @@ impl From 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::Xml(error)), + _ => Self::Syntax(SyntaxError { + inner: SyntaxErrorKind::Xml(error), + }), } } } /// An error in the syntax of the parsed file. #[derive(Debug, thiserror::Error)] -pub enum SyntaxError { +#[error(transparent)] +pub struct SyntaxError { + #[from] + pub(crate) inner: SyntaxErrorKind, +} + +#[derive(Debug, thiserror::Error)] +pub enum SyntaxErrorKind { #[error(transparent)] Xml(#[from] quick_xml::Error), #[error("error while parsing IRI '{iri}': {error}")] @@ -61,15 +70,17 @@ impl SyntaxError { /// Builds an error from a printable error message. #[inline] pub(crate) fn msg(msg: impl Into) -> Self { - Self::Msg { msg: msg.into() } + Self { + inner: SyntaxErrorKind::Msg { msg: msg.into() }, + } } } impl From for io::Error { #[inline] fn from(error: SyntaxError) -> Self { - match error { - SyntaxError::Xml(error) => match error { + match error.inner { + SyntaxErrorKind::Xml(error) => match error { quick_xml::Error::Io(error) => { Arc::try_unwrap(error).unwrap_or_else(|e| Self::new(e.kind(), e)) } @@ -78,7 +89,7 @@ impl From for io::Error { } _ => Self::new(io::ErrorKind::InvalidData, error), }, - SyntaxError::Msg { msg } => Self::new(io::ErrorKind::InvalidData, msg), + SyntaxErrorKind::Msg { msg } => Self::new(io::ErrorKind::InvalidData, msg), _ => Self::new(io::ErrorKind::InvalidData, error), } } diff --git a/lib/oxrdfxml/src/parser.rs b/lib/oxrdfxml/src/parser.rs index 0ef2adf8..a4e35784 100644 --- a/lib/oxrdfxml/src/parser.rs +++ b/lib/oxrdfxml/src/parser.rs @@ -1,4 +1,4 @@ -use crate::error::{ParseError, SyntaxError}; +use crate::error::{ParseError, SyntaxError, SyntaxErrorKind}; use crate::utils::*; use oxilangtag::LanguageTag; use oxiri::{Iri, IriParseError}; @@ -575,7 +575,9 @@ impl RdfXmlReader { tag } else { LanguageTag::parse(tag.to_ascii_lowercase()) - .map_err(|error| SyntaxError::InvalidLanguageTag { tag, error })? + .map_err(|error| SyntaxError { + inner: SyntaxErrorKind::InvalidLanguageTag { tag, error }, + })? .into_inner() }); } else if attribute.key.as_ref() == b"xml:base" { @@ -586,7 +588,9 @@ impl RdfXmlReader { } else { Iri::parse(iri.clone()) } - .map_err(|error| SyntaxError::InvalidIri { iri, error })?, + .map_err(|error| SyntaxError { + inner: SyntaxErrorKind::InvalidIri { iri, error }, + })?, ) } else { // We ignore other xml attributes @@ -1165,9 +1169,11 @@ impl RdfXmlReader { } else { base_iri.resolve(&relative_iri) } - .map_err(|error| SyntaxError::InvalidIri { - iri: relative_iri, - error, + .map_err(|error| SyntaxError { + inner: SyntaxErrorKind::InvalidIri { + iri: relative_iri, + error, + }, })? .into_inner(), )) @@ -1181,9 +1187,11 @@ impl RdfXmlReader { relative_iri } else { Iri::parse(relative_iri.clone()) - .map_err(|error| SyntaxError::InvalidIri { - iri: relative_iri, - error, + .map_err(|error| SyntaxError { + inner: SyntaxErrorKind::InvalidIri { + iri: relative_iri, + error, + }, })? .into_inner() })) diff --git a/lib/oxsdatatypes/src/date_time.rs b/lib/oxsdatatypes/src/date_time.rs index 04e4a388..d508c0dd 100644 --- a/lib/oxsdatatypes/src/date_time.rs +++ b/lib/oxsdatatypes/src/date_time.rs @@ -2038,8 +2038,12 @@ fn time_on_timeline(props: &DateTimeSevenPropertyModel) -> Option { } /// A parsing error +#[derive(Debug, thiserror::Error)] +#[error(transparent)] +pub struct ParseDateTimeError(#[from] ParseDateTimeErrorKind); + #[derive(Debug, Clone, thiserror::Error)] -pub enum ParseDateTimeError { +enum ParseDateTimeErrorKind { #[error("{day} is not a valid day of {month}")] InvalidDayOfMonth { day: u8, month: u8 }, #[error(transparent)] @@ -2052,7 +2056,7 @@ pub enum ParseDateTimeError { impl ParseDateTimeError { const fn msg(message: &'static str) -> Self { - Self::Message(message) + Self(ParseDateTimeErrorKind::Message(message)) } } @@ -2308,7 +2312,7 @@ fn timezone_frag(input: &str) -> Result<(TimezoneOffset, &str), ParseDateTimeErr Ok(( TimezoneOffset::new(sign * (hours * 60 + i16::from(minutes))) - .map_err(ParseDateTimeError::InvalidTimezone)?, + .map_err(|e| ParseDateTimeError(ParseDateTimeErrorKind::InvalidTimezone(e)))?, input, )) } @@ -2378,7 +2382,9 @@ fn optional_end( fn validate_day_of_month(year: Option, month: u8, day: u8) -> Result<(), ParseDateTimeError> { // Constraint: Day-of-month Values if day > days_in_month(year, month) { - return Err(ParseDateTimeError::InvalidDayOfMonth { day, month }); + return Err(ParseDateTimeError( + ParseDateTimeErrorKind::InvalidDayOfMonth { day, month }, + )); } Ok(()) } @@ -2390,6 +2396,12 @@ fn validate_day_of_month(year: Option, month: u8, day: u8) -> Result<(), Pa #[error("overflow during xsd:dateTime computation")] pub struct DateTimeOverflowError; +impl From for ParseDateTimeError { + fn from(error: DateTimeOverflowError) -> Self { + 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). diff --git a/lib/oxsdatatypes/src/decimal.rs b/lib/oxsdatatypes/src/decimal.rs index ecb01af8..72740dc1 100644 --- a/lib/oxsdatatypes/src/decimal.rs +++ b/lib/oxsdatatypes/src/decimal.rs @@ -465,7 +465,7 @@ impl FromStr for Decimal { // (\+|-)?([0-9]+(\.[0-9]*)?|\.[0-9]+) let input = input.as_bytes(); if input.is_empty() { - return Err(ParseDecimalError::UnexpectedEnd); + return Err(PARSE_UNEXPECTED_END); } let (sign, mut input) = match input.first() { @@ -480,9 +480,9 @@ impl FromStr for Decimal { if c.is_ascii_digit() { value = value .checked_mul(10) - .ok_or(ParseDecimalError::Overflow)? + .ok_or(PARSE_OVERFLOW)? .checked_add(sign * i128::from(*c - b'0')) - .ok_or(ParseDecimalError::Overflow)?; + .ok_or(PARSE_OVERFLOW)?; input = &input[1..]; } else { break; @@ -492,12 +492,12 @@ impl FromStr for Decimal { let mut exp = DECIMAL_PART_POW; if let Some(c) = input.first() { if *c != b'.' { - return Err(ParseDecimalError::UnexpectedChar); + return Err(PARSE_UNEXPECTED_CHAR); } input = &input[1..]; if input.is_empty() && !with_before_dot { // We only have a dot - return Err(ParseDecimalError::UnexpectedEnd); + return Err(PARSE_UNEXPECTED_END); } while input.last() == Some(&b'0') { // Hack to avoid underflows @@ -508,25 +508,25 @@ impl FromStr for Decimal { exp /= 10; value = value .checked_mul(10) - .ok_or(ParseDecimalError::Overflow)? + .ok_or(PARSE_OVERFLOW)? .checked_add(sign * i128::from(*c - b'0')) - .ok_or(ParseDecimalError::Overflow)?; + .ok_or(PARSE_OVERFLOW)?; input = &input[1..]; } else { - return Err(ParseDecimalError::UnexpectedChar); + return Err(PARSE_UNEXPECTED_CHAR); } } if exp == 0 { // Underflow - return Err(ParseDecimalError::Underflow); + return Err(PARSE_UNDERFLOW); } } else if !with_before_dot { // It's empty - return Err(ParseDecimalError::UnexpectedEnd); + return Err(PARSE_UNEXPECTED_END); } Ok(Self { - value: value.checked_mul(exp).ok_or(ParseDecimalError::Overflow)?, + value: value.checked_mul(exp).ok_or(PARSE_OVERFLOW)?, }) } } @@ -608,8 +608,12 @@ impl fmt::Display for Decimal { } /// An error when parsing a [`Decimal`]. +#[derive(Debug, thiserror::Error)] +#[error(transparent)] +pub struct ParseDecimalError(#[from] DecimalParseErrorKind); + #[derive(Debug, Clone, thiserror::Error)] -pub enum ParseDecimalError { +enum DecimalParseErrorKind { #[error("Value overflow")] Overflow, #[error("Value underflow")] @@ -620,9 +624,16 @@ pub enum ParseDecimalError { UnexpectedEnd, } +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 for ParseDecimalError { fn from(_: TooLargeForDecimalError) -> Self { - Self::Overflow + Self(DecimalParseErrorKind::Overflow) } } diff --git a/lib/sparesults/src/csv.rs b/lib/sparesults/src/csv.rs index 7d975bd8..bd2fe4b1 100644 --- a/lib/sparesults/src/csv.rs +++ b/lib/sparesults/src/csv.rs @@ -1,6 +1,6 @@ //! Implementation of [SPARQL 1.1 Query Results CSV and TSV Formats](https://www.w3.org/TR/sparql11-results-csv-tsv/) -use crate::error::{ParseError, SyntaxError, TextPosition}; +use crate::error::{ParseError, SyntaxError, SyntaxErrorKind, TextPosition}; use memchr::memchr; use oxrdf::vocab::xsd; use oxrdf::*; @@ -508,21 +508,23 @@ impl TsvSolutionsReader { .sum::(); let start_position_bytes = line.split('\t').take(i).map(|c| c.len() + 1).sum::(); - SyntaxError::Term { - error: e, - term: v.into(), - location: TextPosition { - line: self.reader.line_count - 1, - column: start_position_char.try_into().unwrap(), - offset: self.reader.last_line_start - + u64::try_from(start_position_bytes).unwrap(), - }..TextPosition { - line: self.reader.line_count - 1, - column: (start_position_char + v.chars().count()) - .try_into() - .unwrap(), - offset: self.reader.last_line_start - + u64::try_from(start_position_bytes + v.len()).unwrap(), + SyntaxError { + inner: SyntaxErrorKind::Term { + error: e, + term: v.into(), + location: TextPosition { + line: self.reader.line_count - 1, + column: start_position_char.try_into().unwrap(), + offset: self.reader.last_line_start + + u64::try_from(start_position_bytes).unwrap(), + }..TextPosition { + line: self.reader.line_count - 1, + column: (start_position_char + v.chars().count()) + .try_into() + .unwrap(), + offset: self.reader.last_line_start + + u64::try_from(start_position_bytes + v.len()).unwrap(), + }, }, } })?)) diff --git a/lib/sparesults/src/error.rs b/lib/sparesults/src/error.rs index 4b1e4342..cc5a1e4a 100644 --- a/lib/sparesults/src/error.rs +++ b/lib/sparesults/src/error.rs @@ -40,14 +40,23 @@ impl From 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::Xml(error)), + _ => Self::Syntax(SyntaxError { + inner: SyntaxErrorKind::Xml(error), + }), } } } /// An error in the syntax of the parsed file. #[derive(Debug, thiserror::Error)] -pub enum SyntaxError { +#[error(transparent)] +pub struct SyntaxError { + #[from] + pub(crate) inner: SyntaxErrorKind, +} + +#[derive(Debug, thiserror::Error)] +pub(crate) enum SyntaxErrorKind { #[error(transparent)] Json(#[from] json_event_parser::SyntaxError), #[error(transparent)] @@ -70,26 +79,30 @@ impl SyntaxError { /// Builds an error from a printable error message. #[inline] pub(crate) fn msg(msg: impl Into) -> Self { - Self::Msg { - msg: msg.into(), - location: None, + Self { + inner: SyntaxErrorKind::Msg { + msg: msg.into(), + location: None, + }, } } /// Builds an error from a printable error message and a location #[inline] pub(crate) fn located_message(msg: impl Into, location: Range) -> Self { - Self::Msg { - msg: msg.into(), - location: Some(location), + Self { + inner: SyntaxErrorKind::Msg { + msg: msg.into(), + location: Some(location), + }, } } /// The location of the error inside of the file. #[inline] pub fn location(&self) -> Option> { - match self { - Self::Json(e) => { + match &self.inner { + SyntaxErrorKind::Json(e) => { let location = e.location(); Some( TextPosition { @@ -103,9 +116,9 @@ impl SyntaxError { }, ) } - Self::Term { location, .. } => Some(location.clone()), - Self::Msg { location, .. } => location.clone(), - Self::Xml(_) => None, + SyntaxErrorKind::Term { location, .. } => Some(location.clone()), + SyntaxErrorKind::Msg { location, .. } => location.clone(), + SyntaxErrorKind::Xml(_) => None, } } } @@ -113,9 +126,9 @@ impl SyntaxError { impl From for io::Error { #[inline] fn from(error: SyntaxError) -> Self { - match error { - SyntaxError::Json(error) => Self::new(io::ErrorKind::InvalidData, error), - SyntaxError::Xml(error) => match error { + match error.inner { + SyntaxErrorKind::Json(error) => Self::new(io::ErrorKind::InvalidData, error), + SyntaxErrorKind::Xml(error) => match error { quick_xml::Error::Io(error) => { Arc::try_unwrap(error).unwrap_or_else(|e| Self::new(e.kind(), e)) } @@ -124,8 +137,16 @@ impl From for io::Error { } _ => Self::new(io::ErrorKind::InvalidData, error), }, - SyntaxError::Term { .. } => Self::new(io::ErrorKind::InvalidData, error), - SyntaxError::Msg { msg, .. } => Self::new(io::ErrorKind::InvalidData, msg), + SyntaxErrorKind::Term { .. } => Self::new(io::ErrorKind::InvalidData, error), + SyntaxErrorKind::Msg { msg, .. } => Self::new(io::ErrorKind::InvalidData, msg), + } + } +} + +impl From for SyntaxError { + fn from(error: json_event_parser::SyntaxError) -> Self { + Self { + inner: SyntaxErrorKind::Json(error), } } } diff --git a/lib/spargebra/src/parser.rs b/lib/spargebra/src/parser.rs index df97fc6b..a0a8e9d1 100644 --- a/lib/spargebra/src/parser.rs +++ b/lib/spargebra/src/parser.rs @@ -17,13 +17,14 @@ use std::str::FromStr; /// 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 { let mut state = ParserState::from_base_iri(base_iri)?; - parser::QueryUnit(query, &mut state).map_err(ParseError::Parser) + 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 { let mut state = ParserState::from_base_iri(base_iri)?; - let operations = parser::UpdateInit(update, &mut state).map_err(ParseError::Parser)?; + let operations = parser::UpdateInit(update, &mut state) + .map_err(|e| ParseError(ParseErrorKind::Parser(e)))?; Ok(Update { operations, base_iri: state.base_iri, @@ -32,7 +33,11 @@ pub fn parse_update(update: &str, base_iri: Option<&str>) -> Result) -> Result { Ok(Self { base_iri: if let Some(base_iri) = base_iri { - Some(Iri::parse(base_iri.to_owned()).map_err(ParseError::InvalidBaseIri)?) + Some( + Iri::parse(base_iri.to_owned()) + .map_err(|e| ParseError(ParseErrorKind::InvalidBaseIri(e)))?, + ) } else { None },