diff --git a/lib/Cargo.toml b/lib/Cargo.toml index c402bf10..fa9eb2f3 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -20,7 +20,6 @@ md-5 = "0.8" sha-1 = "0.8" sha2 = "0.8" digest = "0.8" -anyhow = "1" regex = "1" rio_api = "0.4" rio_turtle = "0.4" @@ -35,6 +34,7 @@ js-sys = "0.3" [dev-dependencies] rayon = "1" criterion = "0.3" +anyhow = "1" [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3" diff --git a/lib/benches/sparql_query.rs b/lib/benches/sparql_query.rs index 15f83821..bfe6ff32 100644 --- a/lib/benches/sparql_query.rs +++ b/lib/benches/sparql_query.rs @@ -1,4 +1,3 @@ -use anyhow::anyhow; use criterion::{criterion_group, criterion_main, Criterion}; use oxigraph::model::vocab::rdf; use oxigraph::model::*; @@ -55,7 +54,7 @@ fn to_relative_path(url: &str) -> Result { "rdf-tests/sparql11/", )) } else { - Err(anyhow!("Not supported url for file: {}", url)) + Err(Error::msg(format!("Not supported url for file: {}", url))) } } @@ -65,7 +64,11 @@ fn read_file(url: &str) -> Result { base_path.push(to_relative_path(url)?); Ok(BufReader::new(File::open(&base_path).map_err(|e| { - anyhow!("Opening file {} failed with {}", base_path.display(), e) + Error::msg(format!( + "Opening file {} failed with {}", + base_path.display(), + e, + )) })?)) } @@ -98,7 +101,10 @@ fn load_graph_to_repository( } else if url.ends_with(".rdf") { GraphSyntax::RdfXml } else { - return Err(anyhow!("Serialization type not found for {}", url)); + return Err(Error::msg(format!( + "Serialization type not found for {}", + url + ))); }; connection.load_graph(read_file(url)?, syntax, to_graph_name, Some(url)) } @@ -194,7 +200,7 @@ impl Iterator for TestManifest { fn next(&mut self) -> Option> { match self.tests_to_do.pop() { Some(Term::NamedNode(test_node)) => { - let test_subject = NamedOrBlankNode::from(test_node.clone()); + let test_subject = NamedOrBlankNode::from(test_node); let kind = match self .graph .object_for_subject_predicate(&test_subject, &rdf::TYPE) @@ -214,18 +220,21 @@ impl Iterator for TestManifest { let n = n.clone().into(); match self.graph.object_for_subject_predicate(&n, &qt::QUERY) { Some(Term::NamedNode(q)) => q.as_str().to_owned(), - Some(_) => return Some(Err(anyhow!("invalid query"))), - None => return Some(Err(anyhow!("query not found"))), + Some(_) => return Some(Err(Error::msg("invalid query"))), + None => return Some(Err(Error::msg("query not found"))), } } - Some(_) => return Some(Err(anyhow!("invalid action"))), + Some(_) => return Some(Err(Error::msg("invalid action"))), None => { - return Some(Err(anyhow!("action not found for test {}", test_subject))); + return Some(Err(Error::msg(format!( + "action not found for test {}", + test_subject + )))); } }; Some(Ok(Test { kind, query })) } - Some(_) => Some(Err(anyhow!("invalid test list"))), + Some(_) => Some(Err(Error::msg("invalid test list"))), None => { match self.manifests_to_do.pop() { Some(url) => { @@ -250,7 +259,7 @@ impl Iterator for TestManifest { }), ); } - Some(_) => return Some(Err(anyhow!("invalid tests list"))), + Some(_) => return Some(Err(Error::msg("invalid tests list"))), None => (), } @@ -266,7 +275,10 @@ impl Iterator for TestManifest { )); } Some(term) => { - return Some(Err(anyhow!("Invalid tests list. Got term {}", term))); + return Some(Err(Error::msg(format!( + "Invalid tests list. Got term {}", + term + )))); } None => (), } diff --git a/lib/src/error.rs b/lib/src/error.rs new file mode 100644 index 00000000..bcb24a00 --- /dev/null +++ b/lib/src/error.rs @@ -0,0 +1,130 @@ +use crate::model::ModelError; +use peg::error::ParseError; +use peg::str::LineCol; +use rio_turtle::TurtleError; +use rio_xml::RdfXmlError; +use std::error; +use std::fmt; +use std::io; +use std::string::FromUtf8Error; +use std::sync::PoisonError; + +#[derive(Debug)] +pub struct Error { + inner: ErrorKind, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.inner { + ErrorKind::Msg { msg } => write!(f, "{}", msg), + ErrorKind::Io(e) => e.fmt(f), + ErrorKind::FromUtf8(e) => e.fmt(f), + ErrorKind::Poison => write!(f, "Mutex was poisoned"), + ErrorKind::Model(e) => e.fmt(f), + ErrorKind::Other(e) => e.fmt(f), + } + } +} + +impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match &self.inner { + ErrorKind::Msg { .. } => None, + ErrorKind::Io(e) => Some(e), + ErrorKind::FromUtf8(e) => Some(e), + ErrorKind::Poison => None, + ErrorKind::Model(e) => Some(e), + ErrorKind::Other(e) => Some(e.as_ref()), + } + } +} + +impl Error { + /// Wrap an other error + pub fn wrap(error: impl error::Error + Send + Sync + 'static) -> Self { + Self { + inner: ErrorKind::Other(Box::new(error)), + } + } + + /// Builds an error from a printable error message. + pub fn msg(msg: impl Into) -> Self { + Self { + inner: ErrorKind::Msg { msg: msg.into() }, + } + } +} + +#[derive(Debug)] +enum ErrorKind { + Msg { msg: String }, + Io(io::Error), + FromUtf8(FromUtf8Error), + Poison, + Model(ModelError), + Other(Box), +} + +impl From for Error { + fn from(error: io::Error) -> Self { + Self { + inner: ErrorKind::Io(error), + } + } +} + +impl From for Error { + fn from(error: FromUtf8Error) -> Self { + Self { + inner: ErrorKind::FromUtf8(error), + } + } +} + +impl> From for Error { + fn from(error: E) -> Self { + Self { + inner: ErrorKind::Model(error.into()), + } + } +} + +impl From for Error { + fn from(error: TurtleError) -> Self { + Self::wrap(error) + } +} + +impl From for Error { + fn from(error: RdfXmlError) -> Self { + Self::wrap(error) + } +} + +impl From for Error { + fn from(error: quick_xml::Error) -> Self { + Self::wrap(error) + } +} + +impl From> for Error { + fn from(error: ParseError) -> Self { + Self::wrap(error) + } +} + +impl From> for Error { + fn from(_: PoisonError) -> Self { + Self { + inner: ErrorKind::Poison, + } + } +} + +#[cfg(feature = "rocksdb")] +impl From for Error { + fn from(error: rocksdb::Error) -> Self { + Self::wrap(error) + } +} diff --git a/lib/src/lib.rs b/lib/src/lib.rs index c63e6391..c4bafb60 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -103,13 +103,14 @@ clippy::wrong_pub_self_convention, )] +mod error; pub mod model; mod repository; pub mod sparql; pub(crate) mod store; mod syntax; -pub use anyhow::Error; +pub use error::Error; pub type Result = ::std::result::Result; pub use crate::repository::Repository; pub use crate::repository::RepositoryConnection; diff --git a/lib/src/model/error.rs b/lib/src/model/error.rs new file mode 100644 index 00000000..dc6c95ae --- /dev/null +++ b/lib/src/model/error.rs @@ -0,0 +1,37 @@ +use rio_api::iri::IriParseError; +use std::error; +use std::fmt; + +#[derive(Debug)] +pub struct ModelError { + inner: ErrorKind, +} + +impl fmt::Display for ModelError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.inner { + ErrorKind::Iri(e) => e.fmt(f), + } + } +} + +impl error::Error for ModelError { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match &self.inner { + ErrorKind::Iri(e) => Some(e), + } + } +} + +#[derive(Debug)] +enum ErrorKind { + Iri(IriParseError), +} + +impl From for ModelError { + fn from(error: IriParseError) -> Self { + Self { + inner: ErrorKind::Iri(error), + } + } +} diff --git a/lib/src/model/mod.rs b/lib/src/model/mod.rs index 76effb32..d3a713ca 100644 --- a/lib/src/model/mod.rs +++ b/lib/src/model/mod.rs @@ -3,6 +3,7 @@ //! Inspired by [RDFjs](http://rdf.js.org/) and [Apache Commons RDF](http://commons.apache.org/proper/commons-rdf/) mod blank_node; +mod error; mod graph; mod isomorphism; mod literal; @@ -12,6 +13,7 @@ pub mod vocab; pub(crate) mod xsd; pub use crate::model::blank_node::BlankNode; +pub use crate::model::error::ModelError; pub use crate::model::graph::SimpleGraph; pub use crate::model::literal::Literal; pub use crate::model::named_node::NamedNode; diff --git a/lib/src/model/named_node.rs b/lib/src/model/named_node.rs index 3e8df04a..fb3dbef4 100644 --- a/lib/src/model/named_node.rs +++ b/lib/src/model/named_node.rs @@ -1,7 +1,8 @@ -use crate::Result; +use crate::model::ModelError; use rio_api::iri::Iri; use rio_api::model as rio; use std::fmt; +use std::result::Result; /// A RDF [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) /// @@ -22,7 +23,7 @@ pub struct NamedNode { impl NamedNode { /// Builds and validate a RDF [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) - pub fn parse(iri: impl Into) -> Result { + pub fn parse(iri: impl Into) -> Result { Ok(Self::new_from_iri(Iri::parse(iri.into())?)) } diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index 349ba59e..517b08a1 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -7,8 +7,8 @@ use crate::sparql::plan::*; use crate::sparql::ServiceHandler; use crate::store::numeric_encoder::*; use crate::store::StoreConnection; +use crate::Error; use crate::Result; -use anyhow::anyhow; use digest::Digest; use md5::Md5; use rand::random; @@ -220,8 +220,8 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { if let Some(graph_name) = get_pattern_value(graph_name, &tuple) { graph_name } else { - let result: EncodedTuplesIterator<'_> = Box::new(once(Err(anyhow!( - "Unknown graph name is not allowed when evaluating property path" + let result: EncodedTuplesIterator<'_> = Box::new(once(Err(Error::msg( + "Unknown graph name is not allowed when evaluating property path", )))); return result; }; @@ -493,7 +493,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { ) -> Result> { let service_name = self.dataset.decode_named_node( get_pattern_value(service_name, from) - .ok_or_else(|| anyhow!("The SERVICE name is not bound"))?, + .ok_or_else(|| Error::msg("The SERVICE name is not bound"))?, )?; Ok(self.encode_bindings( variables, diff --git a/lib/src/sparql/json_results.rs b/lib/src/sparql/json_results.rs index cb1e76db..459229ce 100644 --- a/lib/src/sparql/json_results.rs +++ b/lib/src/sparql/json_results.rs @@ -2,8 +2,8 @@ use crate::model::*; use crate::sparql::model::*; +use crate::Error; use crate::Result; -use anyhow::anyhow; use std::io::Write; pub fn write_json_results(results: QueryResult<'_>, mut sink: W) -> Result { @@ -79,8 +79,8 @@ pub fn write_json_results(results: QueryResult<'_>, mut sink: W) -> Re sink.write_all(b"]}}")?; } QueryResult::Graph(_) => { - return Err(anyhow!( - "Graphs could not be formatted to SPARQL query results XML format" + return Err(Error::msg( + "Graphs could not be formatted to SPARQL query results XML format", )); } } diff --git a/lib/src/sparql/mod.rs b/lib/src/sparql/mod.rs index 99152065..059af70a 100644 --- a/lib/src/sparql/mod.rs +++ b/lib/src/sparql/mod.rs @@ -17,8 +17,8 @@ use crate::sparql::plan::TripleTemplate; use crate::sparql::plan::{DatasetView, PlanNode}; use crate::sparql::plan_builder::PlanBuilder; use crate::store::StoreConnection; +use crate::Error; use crate::Result; -use anyhow::anyhow; use rio_api::iri::Iri; use std::fmt; @@ -180,7 +180,7 @@ struct EmptyServiceHandler; impl ServiceHandler for EmptyServiceHandler { fn handle<'a>(&'a self, _: &NamedNode, _: &'a GraphPattern) -> Result> { - Err(anyhow!("The SERVICE feature is not implemented")) + Err(Error::msg("The SERVICE feature is not implemented")) } } diff --git a/lib/src/sparql/model.rs b/lib/src/sparql/model.rs index 0a36c4ba..c2de1f7a 100644 --- a/lib/src/sparql/model.rs +++ b/lib/src/sparql/model.rs @@ -1,8 +1,8 @@ use crate::model::*; use crate::sparql::json_results::write_json_results; use crate::sparql::xml_results::{read_xml_results, write_xml_results}; +use crate::Error; use crate::{FileSyntax, GraphSyntax, Result}; -use anyhow::anyhow; use rand::random; use rio_api::formatter::TriplesFormatter; use rio_turtle::{NTriplesFormatter, TurtleFormatter}; @@ -61,8 +61,8 @@ impl<'a> QueryResult<'a> { } }) } else { - Err(anyhow!( - "Bindings or booleans could not be formatted as an RDF graph" + Err(Error::msg( + "Bindings or booleans could not be formatted as an RDF graph", )) } } @@ -168,7 +168,7 @@ impl Variable { pub fn name(&self) -> Result<&str> { match self { Variable::Variable { name } => Ok(name), - _ => Err(anyhow!("The variable {} has no name", self)), + _ => Err(Error::msg(format!("The variable {} has no name", self))), } } } diff --git a/lib/src/sparql/plan_builder.rs b/lib/src/sparql/plan_builder.rs index de2bfb21..ae1c9130 100644 --- a/lib/src/sparql/plan_builder.rs +++ b/lib/src/sparql/plan_builder.rs @@ -5,8 +5,8 @@ use crate::sparql::model::*; use crate::sparql::plan::PlanPropertyPath; use crate::sparql::plan::*; use crate::store::numeric_encoder::{Encoder, ENCODED_DEFAULT_GRAPH}; +use crate::Error; use crate::Result; -use anyhow::anyhow; use std::collections::HashSet; pub struct PlanBuilder { @@ -654,7 +654,10 @@ impl PlanBuilder { "string", )? } else { - return Err(anyhow!("Not supported custom function {}", expression)); + return Err(Error::msg(format!( + "Not supported custom function {}", + expression + ))); } } }, @@ -680,7 +683,10 @@ impl PlanBuilder { graph_name, )?))) } else { - Err(anyhow!("The xsd:{} casting takes only one parameter", name)) + Err(Error::msg(format!( + "The xsd:{} casting takes only one parameter", + name + ))) } } diff --git a/lib/src/sparql/xml_results.rs b/lib/src/sparql/xml_results.rs index bf1f1d0d..3285364b 100644 --- a/lib/src/sparql/xml_results.rs +++ b/lib/src/sparql/xml_results.rs @@ -2,8 +2,8 @@ use crate::model::*; use crate::sparql::model::*; +use crate::Error; use crate::Result; -use anyhow::anyhow; use quick_xml::events::BytesDecl; use quick_xml::events::BytesEnd; use quick_xml::events::BytesStart; @@ -99,8 +99,8 @@ pub fn write_xml_results(results: QueryResult<'_>, sink: W) -> Result< writer.write_event(Event::End(BytesEnd::borrowed(b"sparql")))?; } QueryResult::Graph(_) => { - return Err(anyhow!( - "Graphs could not be formatted to SPARQL query results XML format" + return Err(Error::msg( + "Graphs could not be formatted to SPARQL query results XML format", )); } } @@ -130,10 +130,10 @@ pub fn read_xml_results<'a>(source: impl BufRead + 'a) -> Result let (ns, event) = reader.read_namespaced_event(&mut buffer, &mut namespace_buffer)?; if let Some(ns) = ns { if ns != b"http://www.w3.org/2005/sparql-results#".as_ref() { - return Err(anyhow!( + return Err(Error::msg(format!( "Unexpected namespace found in RDF/XML query result: {}", reader.decode(ns)? - )); + ))); } } event @@ -144,14 +144,14 @@ pub fn read_xml_results<'a>(source: impl BufRead + 'a) -> Result if event.name() == b"sparql" { state = State::Sparql; } else { - return Err(anyhow!("Expecting tag, found {}", reader.decode(event.name())?)); + return Err(Error::msg(format!("Expecting tag, found {}", reader.decode(event.name())?))); } } State::Sparql => { if event.name() == b"head" { state = State::Head; } else { - return Err(anyhow!("Expecting tag, found {}", reader.decode(event.name())?)); + return Err(Error::msg(format!("Expecting tag, found {}", reader.decode(event.name())?))); } } State::Head => { @@ -159,12 +159,12 @@ pub fn read_xml_results<'a>(source: impl BufRead + 'a) -> Result let name = event.attributes() .filter_map(|attr| attr.ok()) .find(|attr| attr.key == b"name") - .ok_or_else(|| anyhow!("No name attribute found for the tag"))?; + .ok_or_else(|| Error::msg("No name attribute found for the tag"))?; variables.push(name.unescape_and_decode_value(&reader)?); } else if event.name() == b"link" { // no op } else { - return Err(anyhow!("Expecting or tag, found {}", reader.decode(event.name())?)); + return Err(Error::msg(format!("Expecting or tag, found {}", reader.decode(event.name())?))); } } State::AfterHead => { @@ -186,17 +186,17 @@ pub fn read_xml_results<'a>(source: impl BufRead + 'a) -> Result }), ))); } else if event.name() != b"link" && event.name() != b"results" && event.name() != b"boolean" { - return Err(anyhow!("Expecting sparql tag, found {}", reader.decode(event.name())?)); + return Err(Error::msg(format!("Expecting sparql tag, found {}", reader.decode(event.name())?))); } } - State::Boolean => return Err(anyhow!("Unexpected tag inside of tag: {}", reader.decode(event.name())?)) + State::Boolean => return Err(Error::msg(format!("Unexpected tag inside of tag: {}", reader.decode(event.name())?))) }, Event::Empty(event) => match state { State::Sparql => { if event.name() == b"head" { state = State::AfterHead; } else { - return Err(anyhow!("Expecting tag, found {}", reader.decode(event.name())?)); + return Err(Error::msg(format!("Expecting tag, found {}", reader.decode(event.name())?))); } } State::Head => { @@ -204,12 +204,12 @@ pub fn read_xml_results<'a>(source: impl BufRead + 'a) -> Result let name = event.attributes() .filter_map(|v| v.ok()) .find(|attr| attr.key == b"name") - .ok_or_else(|| anyhow!("No name attribute found for the tag"))?; + .ok_or_else(|| Error::msg("No name attribute found for the tag"))?; variables.push(name.unescape_and_decode_value(&reader)?); } else if event.name() == b"link" { // no op } else { - return Err(anyhow!("Expecting or tag, found {}", reader.decode(event.name())?)); + return Err(Error::msg(format!("Expecting or tag, found {}", reader.decode(event.name())?))); } }, State::AfterHead => { @@ -219,10 +219,10 @@ pub fn read_xml_results<'a>(source: impl BufRead + 'a) -> Result Box::new(empty()), ))) } else { - return Err(anyhow!("Unexpected autoclosing tag <{}>", reader.decode(event.name())?)) + return Err(Error::msg(format!("Unexpected autoclosing tag <{}>", reader.decode(event.name())?))) } } - _ => return Err(anyhow!("Unexpected autoclosing tag <{}>", reader.decode(event.name())?)) + _ => return Err(Error::msg(format!("Unexpected autoclosing tag <{}>", reader.decode(event.name())?))) }, Event::Text(event) => { let value = event.unescaped()?; @@ -233,18 +233,18 @@ pub fn read_xml_results<'a>(source: impl BufRead + 'a) -> Result } else if value.as_ref() == b"false" { Ok(QueryResult::Boolean(false)) } else { - Err(anyhow!("Unexpected boolean value. Found {}", reader.decode(&value)?)) + Err(Error::msg(format!("Unexpected boolean value. Found {}", reader.decode(&value)?))) }; } - _ => Err(anyhow!("Unexpected textual value found: {}", reader.decode(&value)?)) + _ => Err(Error::msg(format!("Unexpected textual value found: {}", reader.decode(&value)?))) }; }, Event::End(_) => if let State::Head = state { state = State::AfterHead; } else { - return Err(anyhow!("Unexpected early file end. All results file should have a and a or tag")); + return Err(Error::msg("Unexpected early file end. All results file should have a and a or tag")); }, - Event::Eof => return Err(anyhow!("Unexpected early file end. All results file should have a and a or tag")), + Event::Eof => return Err(Error::msg("Unexpected early file end. All results file should have a and a or tag")), _ => (), } } @@ -292,10 +292,10 @@ impl ResultsIterator { .read_namespaced_event(&mut self.buffer, &mut self.namespace_buffer)?; if let Some(ns) = ns { if ns != b"http://www.w3.org/2005/sparql-results#".as_ref() { - return Err(anyhow!( + return Err(Error::msg(format!( "Unexpected namespace found in RDF/XML query result: {}", self.reader.decode(ns)? - )); + ))); } } match event { @@ -304,10 +304,10 @@ impl ResultsIterator { if event.name() == b"result" { state = State::Result; } else { - return Err(anyhow!( + return Err(Error::msg(format!( "Expecting , found {}", self.reader.decode(event.name())? - )); + ))); } } State::Result => { @@ -319,23 +319,23 @@ impl ResultsIterator { { Some(attr) => current_var = Some(attr.unescaped_value()?.to_vec()), None => { - return Err(anyhow!( - "No name attribute found for the tag" + return Err(Error::msg( + "No name attribute found for the tag", )); } } state = State::Binding; } else { - return Err(anyhow!( + return Err(Error::msg(format!( "Expecting , found {}", self.reader.decode(event.name())? - )); + ))); } } State::Binding => { if term.is_some() { - return Err(anyhow!( - "There is already a value for the current binding" + return Err(Error::msg( + "There is already a value for the current binding", )); } if event.name() == b"uri" { @@ -356,10 +356,10 @@ impl ResultsIterator { } state = State::Literal; } else { - return Err(anyhow!( + return Err(Error::msg(format!( "Expecting , or found {}", self.reader.decode(event.name())? - )); + ))); } } _ => (), @@ -390,10 +390,10 @@ impl ResultsIterator { ); } _ => { - return Err(anyhow!( + return Err(Error::msg(format!( "Unexpected textual value found: {}", self.reader.decode(&data)? - )); + ))); } } } @@ -404,7 +404,7 @@ impl ResultsIterator { if let Some(var) = ¤t_var { new_bindings[self.mapping[var]] = term.clone() } else { - return Err(anyhow!("No name found for tag")); + return Err(Error::msg("No name found for tag")); } term = None; state = State::Result; diff --git a/lib/src/store/memory.rs b/lib/src/store/memory.rs index 59c3b0d1..8235a056 100644 --- a/lib/src/store/memory.rs +++ b/lib/src/store/memory.rs @@ -2,11 +2,9 @@ use crate::store::numeric_encoder::*; use crate::store::*; use crate::{Repository, Result}; use std::collections::{HashMap, HashSet}; -use std::error::Error; -use std::fmt; use std::hash::Hash; use std::iter::{empty, once}; -use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; /// Memory based implementation of the `Repository` trait. /// It is cheap to build using the `MemoryRepository::default()` method. @@ -233,11 +231,11 @@ impl<'a> StoreTransaction for &'a MemoryStore { impl MemoryStore { fn indexes(&self) -> Result> { - Ok(self.indexes.read().map_err(MutexPoisonError::from)?) + Ok(self.indexes.read()?) } fn indexes_mut(&self) -> Result> { - Ok(self.indexes.write().map_err(MutexPoisonError::from)?) + Ok(self.indexes.write()?) } fn quads<'a>(&'a self) -> Result> + 'a> { @@ -681,20 +679,3 @@ impl StoreTransaction for MemoryTransaction<'_> { Ok(()) } } - -#[derive(Debug)] -struct MutexPoisonError {} - -impl fmt::Display for MutexPoisonError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Mutex was poisoned") - } -} - -impl Error for MutexPoisonError {} - -impl From> for MutexPoisonError { - fn from(_: PoisonError) -> Self { - Self {} - } -} diff --git a/lib/src/store/mod.rs b/lib/src/store/mod.rs index f33e530c..5f4c653e 100644 --- a/lib/src/store/mod.rs +++ b/lib/src/store/mod.rs @@ -14,7 +14,7 @@ use crate::model::*; use crate::repository::RepositoryTransaction; use crate::sparql::{QueryOptions, SimplePreparedQuery}; use crate::store::numeric_encoder::*; -use crate::{DatasetSyntax, GraphSyntax, RepositoryConnection, Result}; +use crate::{DatasetSyntax, Error, GraphSyntax, RepositoryConnection, Result}; use rio_api::parser::{QuadsParser, TriplesParser}; use rio_turtle::{NQuadsParser, NTriplesParser, TriGParser, TurtleParser}; use rio_xml::RdfXmlParser; @@ -226,7 +226,7 @@ impl StoreRepositoryTransaction { to_graph_name: Option<&NamedOrBlankNode>, ) -> Result<()> where - P::Error: Send + Sync + 'static, + Error: From, { let mut bnode_map = HashMap::default(); let graph_name = if let Some(graph_name) = to_graph_name { @@ -244,7 +244,7 @@ impl StoreRepositoryTransaction { fn load_from_quad_parser(&mut self, mut parser: P) -> Result<()> where - P::Error: Send + Sync + 'static, + Error: From, { let mut bnode_map = HashMap::default(); parser.parse_all(&mut move |q| { diff --git a/lib/src/store/numeric_encoder.rs b/lib/src/store/numeric_encoder.rs index d489b4b5..200d34bc 100644 --- a/lib/src/store/numeric_encoder.rs +++ b/lib/src/store/numeric_encoder.rs @@ -2,8 +2,8 @@ use crate::model::vocab::rdf; use crate::model::vocab::xsd; use crate::model::xsd::*; use crate::model::*; +use crate::Error; use crate::Result; -use anyhow::anyhow; use md5::digest::Digest; use md5::Md5; use rand::random; @@ -604,7 +604,7 @@ impl TermReader for R { buffer, ))) } - _ => Err(anyhow!("the term buffer has an invalid type id")), + _ => Err(Error::msg("the term buffer has an invalid type id")), } } @@ -1106,17 +1106,21 @@ pub trait Decoder { match self.decode_term(encoded)? { Term::NamedNode(named_node) => Ok(named_node.into()), Term::BlankNode(blank_node) => Ok(blank_node.into()), - Term::Literal(_) => Err(anyhow!("A literal has ben found instead of a named node")), + Term::Literal(_) => Err(Error::msg( + "A literal has ben found instead of a named node", + )), } } fn decode_named_node(&self, encoded: EncodedTerm) -> Result { match self.decode_term(encoded)? { Term::NamedNode(named_node) => Ok(named_node), - Term::BlankNode(_) => Err(anyhow!( - "A blank node has been found instead of a named node" + Term::BlankNode(_) => Err(Error::msg( + "A blank node has been found instead of a named node", + )), + Term::Literal(_) => Err(Error::msg( + "A literal has ben found instead of a named node", )), - Term::Literal(_) => Err(anyhow!("A literal has ben found instead of a named node")), } } @@ -1144,7 +1148,9 @@ pub trait Decoder { impl Decoder for S { fn decode_term(&self, encoded: EncodedTerm) -> Result { match encoded { - EncodedTerm::DefaultGraph => Err(anyhow!("The default graph tag is not a valid term")), + EncodedTerm::DefaultGraph => { + Err(Error::msg("The default graph tag is not a valid term")) + } EncodedTerm::NamedNode { iri_id } => { Ok(NamedNode::new_unchecked(get_required_str(self, iri_id)?).into()) } @@ -1183,10 +1189,10 @@ impl Decoder for S { fn get_required_str(lookup: &impl StrLookup, id: u128) -> Result { lookup.get_str(id)?.ok_or_else(|| { - anyhow!( + Error::msg(format!( "Not able to find the string with id {} in the string store", id - ) + )) }) } diff --git a/lib/src/store/rocksdb.rs b/lib/src/store/rocksdb.rs index d65e132f..f1a3c975 100644 --- a/lib/src/store/rocksdb.rs +++ b/lib/src/store/rocksdb.rs @@ -1,7 +1,7 @@ use crate::store::numeric_encoder::*; use crate::store::{Store, StoreConnection, StoreRepositoryConnection, StoreTransaction}; +use crate::Error; use crate::{Repository, Result}; -use anyhow::anyhow; use rocksdb::*; use std::io::Cursor; use std::iter::{empty, once}; @@ -596,7 +596,7 @@ impl RocksDbStoreInnerTransaction<'_> { fn get_cf<'a>(db: &'a DB, name: &str) -> Result<&'a ColumnFamily> { db.cf_handle(name) - .ok_or_else(|| anyhow!("column family {} not found", name)) + .ok_or_else(|| Error::msg(format!("column family {} not found", name))) } fn wrap_error<'a, E: 'a, I: Iterator> + 'a>( diff --git a/lib/tests/service_test_cases.rs b/lib/tests/service_test_cases.rs index 5028f7aa..10ba4c0a 100644 --- a/lib/tests/service_test_cases.rs +++ b/lib/tests/service_test_cases.rs @@ -1,9 +1,6 @@ -use anyhow::anyhow; use oxigraph::model::*; -use oxigraph::sparql::{ - BindingsIterator, GraphPattern, PreparedQuery, QueryOptions, QueryResult, ServiceHandler, -}; -use oxigraph::{GraphSyntax, MemoryRepository, Repository, RepositoryConnection, Result}; +use oxigraph::sparql::*; +use oxigraph::*; use std::io::BufRead; #[test] @@ -73,7 +70,7 @@ fn two_service_test() { .as_ref(); do_pattern(triples, graph_pattern, QueryOptions::default()) } else { - Err(anyhow!("not found")) + Err(Error::msg("not found")) } } } @@ -124,7 +121,7 @@ fn silent_service_empty_set_test() { _: &NamedNode, _: &'a GraphPattern, ) -> Result> { - Err(anyhow!("This is supposed to fail")) + Err(Error::msg("This is supposed to fail")) } } @@ -162,7 +159,7 @@ fn non_silent_service_test() { _: &NamedNode, _: &'a GraphPattern, ) -> Result> { - Err(anyhow!("This is supposed to fail")) + Err(Error::msg("This is supposed to fail")) } } @@ -232,7 +229,7 @@ fn query_repository<'a>( Box::new(collected.into_iter()), )) } - _ => Err(anyhow!("Excpected bindings but got another QueryResult")), + _ => Err(Error::msg("Excpected bindings but got another QueryResult")), } } @@ -254,7 +251,7 @@ fn pattern_repository<'a>( Box::new(collected.into_iter()), )) } - _ => Err(anyhow!("Expected bindings but got another QueryResult")), + _ => Err(Error::msg("Expected bindings but got another QueryResult")), } } diff --git a/lib/tests/sparql_test_cases.rs b/lib/tests/sparql_test_cases.rs index e2fb911c..94681655 100644 --- a/lib/tests/sparql_test_cases.rs +++ b/lib/tests/sparql_test_cases.rs @@ -1,5 +1,4 @@ ///! Integration tests based on [SPARQL 1.1 Test Cases](https://www.w3.org/2009/sparql/docs/tests/README.html) -use anyhow::anyhow; use oxigraph::model::vocab::rdf; use oxigraph::model::vocab::rdfs; use oxigraph::model::*; @@ -162,33 +161,33 @@ fn sparql_w3c_query_evaluation_testsuite() -> Result<()> { .connection()? .prepare_query(&read_file_to_string(&test.query)?, QueryOptions::default().with_base_iri(&test.query).with_service_handler(StaticServiceHandler::new(&test.service_data)?)) { - Err(error) => Err(anyhow!( + Err(error) => Err(Error::msg(format!( "Failure to parse query of {} with error: {}", test, error - )), + ))), Ok(query) => match query.exec() { - Err(error) => Err(anyhow!( + Err(error) => Err(Error::msg(format!( "Failure to execute query of {} with error: {}", test, error - )), + ))), Ok(result) => { let expected_graph = - load_sparql_query_result_graph(test.result.as_ref().unwrap()).map_err(|e| anyhow!("Error constructing expected graph for {}: {}", test, e))?; + load_sparql_query_result_graph(test.result.as_ref().unwrap()).map_err(|e| Error::msg(format!("Error constructing expected graph for {}: {}", test, e)))?; let with_order = expected_graph .triples_for_predicate(&rs::INDEX) .next() .is_some(); - let actual_graph = to_graph(result, with_order).map_err(|e| anyhow!("Error constructing result graph for {}: {}", test, e))?; + let actual_graph = to_graph(result, with_order).map_err(|e| Error::msg(format!("Error constructing result graph for {}: {}", test, e)))?; if actual_graph.is_isomorphic(&expected_graph) { Ok(()) } else { - Err(anyhow!("Failure on {}.\nExpected file:\n{}\nOutput file:\n{}\nParsed query:\n{}\nData:\n{}\n", + Err(Error::msg(format!("Failure on {}.\nExpected file:\n{}\nOutput file:\n{}\nParsed query:\n{}\nData:\n{}\n", test, expected_graph, actual_graph, Query::parse(&read_file_to_string(&test.query)?, Some(&test.query)).unwrap(), repository_to_string(&repository) - )) + ))) } } }, @@ -240,7 +239,10 @@ fn load_graph_to_repository( } else if url.ends_with(".rdf") { GraphSyntax::RdfXml } else { - return Err(anyhow!("Serialization type not found for {}", url)); + return Err(Error::msg(format!( + "Serialization type not found for {}", + url + ))); }; connection.load_graph(read_file(url)?, syntax, to_graph_name, Some(url)) } @@ -276,7 +278,7 @@ fn to_relative_path(url: &str) -> Result { "rdf-tests/sparql11/", )) } else { - Err(anyhow!("Not supported url for file: {}", url)) + Err(Error::msg(format!("Not supported url for file: {}", url))) } } @@ -286,7 +288,11 @@ fn read_file(url: &str) -> Result { base_path.push(to_relative_path(url)?); Ok(BufReader::new(File::open(&base_path).map_err(|e| { - anyhow!("Opening file {} failed with {}", base_path.display(), e) + Error::msg(format!( + "Opening file {} failed with {}", + base_path.display(), + e, + )) })?)) } @@ -528,8 +534,8 @@ impl Iterator for TestManifest { let n = n.clone().into(); let query = match self.graph.object_for_subject_predicate(&n, &qt::QUERY) { Some(Term::NamedNode(q)) => q.as_str().to_owned(), - Some(_) => return Some(Err(anyhow!("invalid query"))), - None => return Some(Err(anyhow!("query not found"))), + Some(_) => return Some(Err(Error::msg("invalid query"))), + None => return Some(Err(Error::msg("query not found"))), }; let data = match self.graph.object_for_subject_predicate(&n, &qt::DATA) { Some(Term::NamedNode(q)) => Some(q.as_str().to_owned()), @@ -567,9 +573,12 @@ impl Iterator for TestManifest { .collect(); (query, data, graph_data, service_data) } - Some(_) => return Some(Err(anyhow!("invalid action"))), + Some(_) => return Some(Err(Error::msg("invalid action"))), None => { - return Some(Err(anyhow!("action not found for test {}", test_subject))); + return Some(Err(Error::msg(format!( + "action not found for test {}", + test_subject + )))); } }; let result = match self @@ -577,7 +586,7 @@ impl Iterator for TestManifest { .object_for_subject_predicate(&test_subject, &*mf::RESULT) { Some(Term::NamedNode(n)) => Some(n.as_str().to_owned()), - Some(_) => return Some(Err(anyhow!("invalid result"))), + Some(_) => return Some(Err(Error::msg("invalid result"))), None => None, }; Some(Ok(Test { @@ -592,7 +601,7 @@ impl Iterator for TestManifest { result, })) } - Some(_) => Some(Err(anyhow!("invalid test list"))), + Some(_) => Some(Err(Error::msg("invalid test list"))), None => { match self.manifests_to_do.pop() { Some(url) => { @@ -617,7 +626,7 @@ impl Iterator for TestManifest { }), ); } - Some(_) => return Some(Err(anyhow!("invalid tests list"))), + Some(_) => return Some(Err(Error::msg("invalid tests list"))), None => (), } @@ -633,7 +642,10 @@ impl Iterator for TestManifest { )); } Some(term) => { - return Some(Err(anyhow!("Invalid tests list. Got term {}", term))); + return Some(Err(Error::msg(format!( + "Invalid tests list. Got term {}", + term + )))); } None => (), } @@ -717,7 +729,7 @@ impl ServiceHandler for StaticServiceHandler { if let QueryResult::Bindings(iterator) = self .services .get(service_name) - .ok_or_else(|| anyhow!("Service {} not found", service_name))? + .ok_or_else(|| Error::msg(format!("Service {} not found", service_name)))? .connection()? .prepare_query_from_pattern( &graph_pattern, @@ -733,7 +745,7 @@ impl ServiceHandler for StaticServiceHandler { Box::new(collected.into_iter()), )) } else { - Err(anyhow!("Expected bindings but got another QueryResult")) + Err(Error::msg("Expected bindings but got another QueryResult")) } } } diff --git a/wikibase/Cargo.toml b/wikibase/Cargo.toml index a5f15ce4..ae4979a9 100644 --- a/wikibase/Cargo.toml +++ b/wikibase/Cargo.toml @@ -16,4 +16,4 @@ clap = "2" rouille = "3" reqwest = "0.9" serde_json = "1" -chrono = "0.4" +chrono = "0.4" \ No newline at end of file diff --git a/wikibase/src/loader.rs b/wikibase/src/loader.rs index 71e6b1e3..69c1419f 100644 --- a/wikibase/src/loader.rs +++ b/wikibase/src/loader.rs @@ -30,8 +30,9 @@ impl WikibaseLoader { ) -> Result { Ok(Self { repository, - api_url: Url::parse(api_url)?, - entity_data_url: Url::parse(&(pages_base_url.to_owned() + "Special:EntityData"))?, + api_url: Url::parse(api_url).map_err(Error::wrap)?, + entity_data_url: Url::parse(&(pages_base_url.to_owned() + "Special:EntityData")) + .map_err(Error::wrap)?, client: Client::new(), namespaces: namespaces.to_vec(), start: Utc::now(), @@ -176,9 +177,12 @@ impl WikibaseLoader { .get(self.api_url.clone()) .query(parameters) .header(USER_AGENT, SERVER) - .send()? - .error_for_status()? - .json()?) + .send() + .map_err(Error::wrap)? + .error_for_status() + .map_err(Error::wrap)? + .json() + .map_err(Error::wrap)?) } fn get_entity_data(&self, id: &str) -> Result { @@ -187,8 +191,10 @@ impl WikibaseLoader { .get(self.entity_data_url.clone()) .query(&[("id", id), ("format", "nt"), ("flavor", "dump")]) .header(USER_AGENT, SERVER) - .send()? - .error_for_status()?) + .send() + .map_err(Error::wrap)? + .error_for_status() + .map_err(Error::wrap)?) } fn load_entity_data(&self, uri: &str, data: impl Read) -> Result<()> { @@ -208,6 +214,7 @@ impl WikibaseLoader { Some(&NamedNode::parse(uri)?.into()), None, ) - }) + })?; + Ok(()) } }