diff --git a/lib/src/io/write.rs b/lib/src/io/write.rs index e8f72515..cb41ecd4 100644 --- a/lib/src/io/write.rs +++ b/lib/src/io/write.rs @@ -1,8 +1,10 @@ //! Utilities to write RDF graphs and datasets +use crate::error::invalid_input_error; use crate::io::{DatasetFormat, GraphFormat}; use crate::model::*; use rio_api::formatter::{QuadsFormatter, TriplesFormatter}; +use rio_api::model as rio; use rio_turtle::{NQuadsFormatter, NTriplesFormatter, TriGFormatter, TurtleFormatter}; use rio_xml::RdfXmlFormatter; use std::io; @@ -90,10 +92,53 @@ impl TripleWriter { /// Writes a triple pub fn write<'a>(&mut self, triple: impl Into>) -> io::Result<()> { let triple = triple.into(); + let triple = rio::Triple { + subject: match triple.subject { + SubjectRef::NamedNode(node) => rio::NamedNode { iri: node.as_str() }.into(), + SubjectRef::BlankNode(node) => rio::BlankNode { id: node.as_str() }.into(), + SubjectRef::Triple(_) => { + return Err(invalid_input_error( + "Rio library does not support RDF-star yet", + )) + } + }, + predicate: rio::NamedNode { + iri: triple.predicate.as_str(), + }, + object: match triple.object { + TermRef::NamedNode(node) => rio::NamedNode { iri: node.as_str() }.into(), + TermRef::BlankNode(node) => rio::BlankNode { id: node.as_str() }.into(), + TermRef::Literal(literal) => if literal.is_plain() { + if let Some(language) = literal.language() { + rio::Literal::LanguageTaggedString { + value: literal.value(), + language, + } + } else { + rio::Literal::Simple { + value: literal.value(), + } + } + } else { + rio::Literal::Typed { + value: literal.value(), + datatype: rio::NamedNode { + iri: literal.datatype().as_str(), + }, + } + } + .into(), + TermRef::Triple(_) => { + return Err(invalid_input_error( + "Rio library does not support RDF-star yet", + )) + } + }, + }; match &mut self.formatter { - TripleWriterKind::NTriples(formatter) => formatter.format(&triple.into())?, - TripleWriterKind::Turtle(formatter) => formatter.format(&triple.into())?, - TripleWriterKind::RdfXml(formatter) => formatter.format(&triple.into())?, + TripleWriterKind::NTriples(formatter) => formatter.format(&triple)?, + TripleWriterKind::Turtle(formatter) => formatter.format(&triple)?, + TripleWriterKind::RdfXml(formatter) => formatter.format(&triple)?, } Ok(()) } @@ -190,9 +235,57 @@ impl QuadWriter { /// Writes a quad pub fn write<'a>(&mut self, quad: impl Into>) -> io::Result<()> { let quad = quad.into(); + let quad = rio::Quad { + subject: match quad.subject { + SubjectRef::NamedNode(node) => rio::NamedNode { iri: node.as_str() }.into(), + SubjectRef::BlankNode(node) => rio::BlankNode { id: node.as_str() }.into(), + SubjectRef::Triple(_) => { + return Err(invalid_input_error( + "Rio library does not support RDF-star yet", + )) + } + }, + predicate: rio::NamedNode { + iri: quad.predicate.as_str(), + }, + object: match quad.object { + TermRef::NamedNode(node) => rio::NamedNode { iri: node.as_str() }.into(), + TermRef::BlankNode(node) => rio::BlankNode { id: node.as_str() }.into(), + TermRef::Literal(literal) => if literal.is_plain() { + if let Some(language) = literal.language() { + rio::Literal::LanguageTaggedString { + value: literal.value(), + language, + } + } else { + rio::Literal::Simple { + value: literal.value(), + } + } + } else { + rio::Literal::Typed { + value: literal.value(), + datatype: rio::NamedNode { + iri: literal.datatype().as_str(), + }, + } + } + .into(), + TermRef::Triple(_) => { + return Err(invalid_input_error( + "Rio library does not support RDF-star yet", + )) + } + }, + graph_name: match quad.graph_name { + GraphNameRef::NamedNode(node) => Some(rio::NamedNode { iri: node.as_str() }.into()), + GraphNameRef::BlankNode(node) => Some(rio::BlankNode { id: node.as_str() }.into()), + GraphNameRef::DefaultGraph => None, + }, + }; match &mut self.formatter { - QuadWriterKind::NQuads(formatter) => formatter.format(&quad.into())?, - QuadWriterKind::TriG(formatter) => formatter.format(&quad.into())?, + QuadWriterKind::NQuads(formatter) => formatter.format(&quad)?, + QuadWriterKind::TriG(formatter) => formatter.format(&quad)?, } Ok(()) } diff --git a/lib/src/model/blank_node.rs b/lib/src/model/blank_node.rs index d0e7bd66..8929f3ab 100644 --- a/lib/src/model/blank_node.rs +++ b/lib/src/model/blank_node.rs @@ -203,7 +203,7 @@ impl<'a> BlankNodeRef<'a> { impl fmt::Display for BlankNodeRef<'_> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - rio::BlankNode::from(*self).fmt(f) + rio::BlankNode { id: self.as_str() }.fmt(f) } } @@ -221,13 +221,6 @@ impl<'a> From> for BlankNode { } } -impl<'a> From> for rio::BlankNode<'a> { - #[inline] - fn from(node: BlankNodeRef<'a>) -> Self { - rio::BlankNode { id: node.as_str() } - } -} - impl PartialEq for BlankNodeRef<'_> { #[inline] fn eq(&self, other: &BlankNode) -> bool { diff --git a/lib/src/model/literal.rs b/lib/src/model/literal.rs index da929c24..c79bce3b 100644 --- a/lib/src/model/literal.rs +++ b/lib/src/model/literal.rs @@ -547,7 +547,19 @@ impl<'a> LiteralRef<'a> { impl fmt::Display for LiteralRef<'_> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - rio::Literal::from(*self).fmt(f) + match self.0 { + LiteralRefContent::String(value) => rio::Literal::Simple { value }, + LiteralRefContent::LanguageTaggedString { value, language } => { + rio::Literal::LanguageTaggedString { value, language } + } + LiteralRefContent::TypedLiteral { value, datatype } => rio::Literal::Typed { + value, + datatype: rio::NamedNode { + iri: datatype.as_str(), + }, + }, + } + .fmt(f) } } @@ -565,22 +577,6 @@ impl<'a> From> for Literal { } } -impl<'a> From> for rio::Literal<'a> { - #[inline] - fn from(literal: LiteralRef<'a>) -> Self { - match literal.0 { - LiteralRefContent::String(value) => rio::Literal::Simple { value }, - LiteralRefContent::LanguageTaggedString { value, language } => { - rio::Literal::LanguageTaggedString { value, language } - } - LiteralRefContent::TypedLiteral { value, datatype } => rio::Literal::Typed { - value, - datatype: datatype.into(), - }, - } - } -} - impl<'a> From<&'a str> for LiteralRef<'a> { #[inline] fn from(value: &'a str) -> Self { diff --git a/lib/src/model/named_node.rs b/lib/src/model/named_node.rs index 2cd17f27..f2448d24 100644 --- a/lib/src/model/named_node.rs +++ b/lib/src/model/named_node.rs @@ -143,7 +143,7 @@ impl<'a> NamedNodeRef<'a> { impl fmt::Display for NamedNodeRef<'_> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - rio::NamedNode::from(*self).fmt(f) + rio::NamedNode { iri: self.as_str() }.fmt(f) } } @@ -160,13 +160,6 @@ impl<'a> From<&'a NamedNode> for NamedNodeRef<'a> { } } -impl<'a> From> for rio::NamedNode<'a> { - #[inline] - fn from(node: NamedNodeRef<'a>) -> Self { - rio::NamedNode { iri: node.as_str() } - } -} - impl PartialEq for NamedNodeRef<'_> { #[inline] fn eq(&self, other: &NamedNode) -> bool { diff --git a/lib/src/model/triple.rs b/lib/src/model/triple.rs index 31cb8bc7..0b43e110 100644 --- a/lib/src/model/triple.rs +++ b/lib/src/model/triple.rs @@ -2,7 +2,6 @@ use crate::model::blank_node::BlankNode; use crate::model::literal::Literal; use crate::model::named_node::NamedNode; use crate::model::{BlankNodeRef, LiteralRef, NamedNodeRef}; -use rio_api::model as rio; use std::fmt; use std::sync::Arc; @@ -153,16 +152,6 @@ impl<'a> From> for NamedOrBlankNode { } } -impl<'a> From> for rio::NamedOrBlankNode<'a> { - #[inline] - fn from(node: NamedOrBlankNodeRef<'a>) -> Self { - match node { - NamedOrBlankNodeRef::NamedNode(node) => rio::NamedNode::from(node).into(), - NamedOrBlankNodeRef::BlankNode(node) => rio::BlankNode::from(node).into(), - } - } -} - /// The owned union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri), [blank nodes](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node) and [triples](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple). #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum Subject { @@ -374,18 +363,6 @@ impl<'a> From<&'a NamedOrBlankNode> for SubjectRef<'a> { } } -#[allow(clippy::unimplemented, clippy::fallible_impl_from)] -impl<'a> From> for rio::NamedOrBlankNode<'a> { - #[inline] - fn from(node: SubjectRef<'a>) -> Self { - match node { - SubjectRef::NamedNode(node) => rio::NamedNode::from(node).into(), - SubjectRef::BlankNode(node) => rio::BlankNode::from(node).into(), - SubjectRef::Triple(_) => unimplemented!("Rio library does not support RDF* yet"), - } - } -} - /// An owned RDF [term](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-term) /// It is the union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri), [blank nodes](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node), [literals](https://www.w3.org/TR/rdf11-concepts/#dfn-literal) and [triples](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple). #[derive(Eq, PartialEq, Debug, Clone, Hash)] @@ -679,19 +656,6 @@ impl<'a> From> for Term { } } -#[allow(clippy::unimplemented, clippy::fallible_impl_from)] -impl<'a> From> for rio::Term<'a> { - #[inline] - fn from(node: TermRef<'a>) -> Self { - match node { - TermRef::NamedNode(node) => rio::NamedNode::from(node).into(), - TermRef::BlankNode(node) => rio::BlankNode::from(node).into(), - TermRef::Literal(node) => rio::Literal::from(node).into(), - TermRef::Triple(_) => unimplemented!("Rio library does not support RDF* yet"), - } - } -} - /// An owned [RDF triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct Triple { @@ -818,17 +782,6 @@ impl<'a> From> for Triple { } } -impl<'a> From> for rio::Triple<'a> { - #[inline] - fn from(triple: TripleRef<'a>) -> Self { - rio::Triple { - subject: triple.subject.into(), - predicate: triple.predicate.into(), - object: triple.object.into(), - } - } -} - /// A possible owned graph name. /// It is the union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri), [blank nodes](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node), and the [default graph name](https://www.w3.org/TR/rdf11-concepts/#dfn-default-graph). #[derive(Eq, PartialEq, Debug, Clone, Hash)] @@ -987,17 +940,6 @@ impl<'a> From> for GraphName { } } -impl<'a> From> for Option> { - #[inline] - fn from(name: GraphNameRef<'a>) -> Self { - match name { - GraphNameRef::NamedNode(node) => Some(rio::NamedNode::from(node).into()), - GraphNameRef::BlankNode(node) => Some(rio::BlankNode::from(node).into()), - GraphNameRef::DefaultGraph => None, - } - } -} - /// An owned [triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) in a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct Quad { @@ -1135,15 +1077,3 @@ impl<'a> From> for Quad { quad.into_owned() } } - -impl<'a> From> for rio::Quad<'a> { - #[inline] - fn from(quad: QuadRef<'a>) -> Self { - rio::Quad { - subject: quad.subject.into(), - predicate: quad.predicate.into(), - object: quad.object.into(), - graph_name: quad.graph_name.into(), - } - } -} diff --git a/lib/src/storage/numeric_encoder.rs b/lib/src/storage/numeric_encoder.rs index afa92160..36424c52 100644 --- a/lib/src/storage/numeric_encoder.rs +++ b/lib/src/storage/numeric_encoder.rs @@ -722,7 +722,9 @@ pub(crate) trait StrContainer: StrLookup { /// Encodes a term and insert strings if needed pub(crate) trait WriteEncoder: StrContainer { fn encode_named_node(&self, named_node: NamedNodeRef<'_>) -> Result { - self.encode_rio_named_node(named_node.into()) + Ok(EncodedTerm::NamedNode { + iri_id: self.encode_str(named_node.as_str())?, + }) } fn encode_blank_node(&self, blank_node: BlankNodeRef<'_>) -> Result { @@ -741,7 +743,105 @@ pub(crate) trait WriteEncoder: StrContainer { } fn encode_literal(&self, literal: LiteralRef<'_>) -> Result { - self.encode_rio_literal(literal.into()) + Ok(if literal.is_plain() { + if let Some(language) = literal.language() { + if let Ok(value) = SmallString::try_from(literal.value()) { + if let Ok(language) = SmallString::try_from(language) { + EncodedTerm::SmallSmallLangStringLiteral { value, language } + } else { + EncodedTerm::SmallBigLangStringLiteral { + value, + language_id: self.encode_str(language)?, + } + } + } else if let Ok(language) = SmallString::try_from(language) { + EncodedTerm::BigSmallLangStringLiteral { + value_id: self.encode_str(literal.value())?, + language, + } + } else { + EncodedTerm::BigBigLangStringLiteral { + value_id: self.encode_str(literal.value())?, + language_id: self.encode_str(language)?, + } + } + } else if let Ok(value) = SmallString::try_from(literal.value()) { + EncodedTerm::SmallStringLiteral(value) + } else { + EncodedTerm::BigStringLiteral { + value_id: self.encode_str(literal.value())?, + } + } + } else { + match match literal.datatype().as_str() { + "http://www.w3.org/2001/XMLSchema#boolean" => parse_boolean_str(literal.value()), + "http://www.w3.org/2001/XMLSchema#string" => { + Some(if let Ok(value) = SmallString::try_from(literal.value()) { + EncodedTerm::SmallStringLiteral(value) + } else { + EncodedTerm::BigStringLiteral { + value_id: self.encode_str(literal.value())?, + } + }) + } + "http://www.w3.org/2001/XMLSchema#float" => parse_float_str(literal.value()), + "http://www.w3.org/2001/XMLSchema#double" => parse_double_str(literal.value()), + "http://www.w3.org/2001/XMLSchema#integer" + | "http://www.w3.org/2001/XMLSchema#byte" + | "http://www.w3.org/2001/XMLSchema#short" + | "http://www.w3.org/2001/XMLSchema#int" + | "http://www.w3.org/2001/XMLSchema#long" + | "http://www.w3.org/2001/XMLSchema#unsignedByte" + | "http://www.w3.org/2001/XMLSchema#unsignedShort" + | "http://www.w3.org/2001/XMLSchema#unsignedInt" + | "http://www.w3.org/2001/XMLSchema#unsignedLong" + | "http://www.w3.org/2001/XMLSchema#positiveInteger" + | "http://www.w3.org/2001/XMLSchema#negativeInteger" + | "http://www.w3.org/2001/XMLSchema#nonPositiveInteger" + | "http://www.w3.org/2001/XMLSchema#nonNegativeInteger" => { + parse_integer_str(literal.value()) + } + "http://www.w3.org/2001/XMLSchema#decimal" => parse_decimal_str(literal.value()), + "http://www.w3.org/2001/XMLSchema#dateTime" + | "http://www.w3.org/2001/XMLSchema#dateTimeStamp" => { + parse_date_time_str(literal.value()) + } + "http://www.w3.org/2001/XMLSchema#time" => parse_time_str(literal.value()), + "http://www.w3.org/2001/XMLSchema#date" => parse_date_str(literal.value()), + "http://www.w3.org/2001/XMLSchema#gYearMonth" => { + parse_g_year_month_str(literal.value()) + } + "http://www.w3.org/2001/XMLSchema#gYear" => parse_g_year_str(literal.value()), + "http://www.w3.org/2001/XMLSchema#gMonthDay" => { + parse_g_month_day_str(literal.value()) + } + "http://www.w3.org/2001/XMLSchema#gDay" => parse_g_day_str(literal.value()), + "http://www.w3.org/2001/XMLSchema#gMonth" => parse_g_month_str(literal.value()), + "http://www.w3.org/2001/XMLSchema#duration" => parse_duration_str(literal.value()), + "http://www.w3.org/2001/XMLSchema#yearMonthDuration" => { + parse_year_month_duration_str(literal.value()) + } + "http://www.w3.org/2001/XMLSchema#dayTimeDuration" => { + parse_day_time_duration_str(literal.value()) + } + _ => None, + } { + Some(v) => v, + None => { + if let Ok(value) = SmallString::try_from(literal.value()) { + EncodedTerm::SmallTypedLiteral { + value, + datatype_id: self.encode_str(literal.datatype().as_str())?, + } + } else { + EncodedTerm::BigTypedLiteral { + value_id: self.encode_str(literal.value())?, + datatype_id: self.encode_str(literal.datatype().as_str())?, + } + } + } + } + }) } fn encode_named_or_blank_node( @@ -817,9 +917,7 @@ pub(crate) trait WriteEncoder: StrContainer { &self, named_node: rio::NamedNode<'_>, ) -> Result { - Ok(EncodedTerm::NamedNode { - iri_id: self.encode_str(named_node.iri)?, - }) + self.encode_named_node(NamedNodeRef::new_unchecked(named_node.iri)) } fn encode_rio_blank_node( @@ -836,103 +934,13 @@ pub(crate) trait WriteEncoder: StrContainer { }) } fn encode_rio_literal(&self, literal: rio::Literal<'_>) -> Result { - Ok(match literal { - rio::Literal::Simple { value } => { - if let Ok(value) = SmallString::try_from(value) { - EncodedTerm::SmallStringLiteral(value) - } else { - EncodedTerm::BigStringLiteral { - value_id: self.encode_str(value)?, - } - } - } + self.encode_literal(match literal { + rio::Literal::Simple { value } => LiteralRef::new_simple_literal(value), rio::Literal::LanguageTaggedString { value, language } => { - if let Ok(value) = SmallString::try_from(value) { - if let Ok(language) = SmallString::try_from(language) { - EncodedTerm::SmallSmallLangStringLiteral { value, language } - } else { - EncodedTerm::SmallBigLangStringLiteral { - value, - language_id: self.encode_str(language)?, - } - } - } else if let Ok(language) = SmallString::try_from(language) { - EncodedTerm::BigSmallLangStringLiteral { - value_id: self.encode_str(value)?, - language, - } - } else { - EncodedTerm::BigBigLangStringLiteral { - value_id: self.encode_str(value)?, - language_id: self.encode_str(language)?, - } - } + LiteralRef::new_language_tagged_literal_unchecked(value, language) } rio::Literal::Typed { value, datatype } => { - match match datatype.iri { - "http://www.w3.org/2001/XMLSchema#boolean" => parse_boolean_str(value), - "http://www.w3.org/2001/XMLSchema#string" => { - Some(if let Ok(value) = SmallString::try_from(value) { - EncodedTerm::SmallStringLiteral(value) - } else { - EncodedTerm::BigStringLiteral { - value_id: self.encode_str(value)?, - } - }) - } - "http://www.w3.org/2001/XMLSchema#float" => parse_float_str(value), - "http://www.w3.org/2001/XMLSchema#double" => parse_double_str(value), - "http://www.w3.org/2001/XMLSchema#integer" - | "http://www.w3.org/2001/XMLSchema#byte" - | "http://www.w3.org/2001/XMLSchema#short" - | "http://www.w3.org/2001/XMLSchema#int" - | "http://www.w3.org/2001/XMLSchema#long" - | "http://www.w3.org/2001/XMLSchema#unsignedByte" - | "http://www.w3.org/2001/XMLSchema#unsignedShort" - | "http://www.w3.org/2001/XMLSchema#unsignedInt" - | "http://www.w3.org/2001/XMLSchema#unsignedLong" - | "http://www.w3.org/2001/XMLSchema#positiveInteger" - | "http://www.w3.org/2001/XMLSchema#negativeInteger" - | "http://www.w3.org/2001/XMLSchema#nonPositiveInteger" - | "http://www.w3.org/2001/XMLSchema#nonNegativeInteger" => { - parse_integer_str(value) - } - "http://www.w3.org/2001/XMLSchema#decimal" => parse_decimal_str(value), - "http://www.w3.org/2001/XMLSchema#dateTime" - | "http://www.w3.org/2001/XMLSchema#dateTimeStamp" => { - parse_date_time_str(value) - } - "http://www.w3.org/2001/XMLSchema#time" => parse_time_str(value), - "http://www.w3.org/2001/XMLSchema#date" => parse_date_str(value), - "http://www.w3.org/2001/XMLSchema#gYearMonth" => parse_g_year_month_str(value), - "http://www.w3.org/2001/XMLSchema#gYear" => parse_g_year_str(value), - "http://www.w3.org/2001/XMLSchema#gMonthDay" => parse_g_month_day_str(value), - "http://www.w3.org/2001/XMLSchema#gDay" => parse_g_day_str(value), - "http://www.w3.org/2001/XMLSchema#gMonth" => parse_g_month_str(value), - "http://www.w3.org/2001/XMLSchema#duration" => parse_duration_str(value), - "http://www.w3.org/2001/XMLSchema#yearMonthDuration" => { - parse_year_month_duration_str(value) - } - "http://www.w3.org/2001/XMLSchema#dayTimeDuration" => { - parse_day_time_duration_str(value) - } - _ => None, - } { - Some(v) => v, - None => { - if let Ok(value) = SmallString::try_from(value) { - EncodedTerm::SmallTypedLiteral { - value, - datatype_id: self.encode_str(datatype.iri)?, - } - } else { - EncodedTerm::BigTypedLiteral { - value_id: self.encode_str(value)?, - datatype_id: self.encode_str(datatype.iri)?, - } - } - } - } + LiteralRef::new_typed_literal(value, NamedNodeRef::new_unchecked(datatype.iri)) } }) }