//! Data structures for [RDF 1.1 Concepts](https://www.w3.org/TR/rdf11-concepts/) like IRI, literal or triples. use std::convert::{TryFrom, TryInto}; use std::fmt; use std::fmt::Write; /// An RDF [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri). /// /// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation. /// /// ``` /// use spargebra::term::NamedNode; /// /// assert_eq!( /// "", /// NamedNode { iri: "http://example.com/foo".into() }.to_string() /// ) /// ``` #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] pub struct NamedNode { /// The [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) itself. pub iri: String, } impl fmt::Display for NamedNode { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "<{}>", self.iri) } } impl TryFrom for NamedNode { type Error = (); #[inline] fn try_from(pattern: NamedNodePattern) -> Result { match pattern { NamedNodePattern::NamedNode(t) => Ok(t), NamedNodePattern::Variable(_) => Err(()), } } } /// An RDF [blank node](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node). /// /// /// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation. /// /// ``` /// use spargebra::term::BlankNode; /// /// assert_eq!( /// "_:a1", /// BlankNode { id: "a1".into() }.to_string() /// ) /// ``` #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct BlankNode { /// The [blank node identifier](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node-identifier). pub id: String, } impl fmt::Display for BlankNode { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "_:{}", self.id) } } /// An RDF [literal](https://www.w3.org/TR/rdf11-concepts/#dfn-literal). /// /// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation. /// /// The language tags should be lowercased [as suggested by the RDF specification](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string). /// /// ``` /// use spargebra::term::NamedNode; /// use spargebra::term::Literal; /// /// assert_eq!( /// "\"foo\\nbar\"", /// Literal::Simple { value: "foo\nbar".into() }.to_string() /// ); /// /// assert_eq!( /// "\"1999-01-01\"^^", /// Literal::Typed { value: "1999-01-01".into(), datatype: NamedNode { iri: "http://www.w3.org/2001/XMLSchema#date".into() }}.to_string() /// ); /// /// assert_eq!( /// "\"foo\"@en", /// Literal::LanguageTaggedString { value: "foo".into(), language: "en".into() }.to_string() /// ); /// ``` #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum Literal { /// A [simple literal](https://www.w3.org/TR/rdf11-concepts/#dfn-simple-literal) without datatype or language form. Simple { /// The [lexical form](https://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form). value: String, }, /// A [language-tagged string](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string) LanguageTaggedString { /// The [lexical form](https://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form). value: String, /// The [language tag](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tag). language: String, }, /// A literal with an explicit datatype Typed { /// The [lexical form](https://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form). value: String, /// The [datatype IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-datatype-iri). datatype: NamedNode, }, } impl fmt::Display for Literal { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Literal::Simple { value } => print_quoted_str(value, f), Literal::LanguageTaggedString { value, language } => { print_quoted_str(value, f)?; write!(f, "@{}", language) } Literal::Typed { value, datatype } => { print_quoted_str(value, f)?; write!(f, "^^{}", datatype) } } } } /// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and [blank nodes](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node). /// /// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation. #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum Subject { NamedNode(NamedNode), BlankNode(BlankNode), Triple(Box), } impl fmt::Display for Subject { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NamedNode(node) => node.fmt(f), Self::BlankNode(node) => node.fmt(f), Self::Triple(triple) => write!( f, "<<{} {} {}>>", triple.subject, triple.predicate, triple.object ), } } } impl From for Subject { #[inline] fn from(node: NamedNode) -> Self { Self::NamedNode(node) } } impl From for Subject { #[inline] fn from(node: BlankNode) -> Self { Self::BlankNode(node) } } impl From for Subject { #[inline] fn from(triple: Triple) -> Self { Self::Triple(Box::new(triple)) } } impl From> for Subject { #[inline] fn from(triple: Box) -> Self { Self::Triple(triple) } } impl TryFrom for Subject { type Error = (); #[inline] fn try_from(term: TermPattern) -> Result { match term { TermPattern::NamedNode(t) => Ok(t.into()), TermPattern::BlankNode(t) => Ok(t.into()), TermPattern::Triple(t) => Ok(Triple::try_from(t)?.into()), TermPattern::Literal(_) | TermPattern::Variable(_) => Err(()), } } } /// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and [triples](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple). /// /// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation. #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum GroundSubject { NamedNode(NamedNode), Triple(Box), } impl fmt::Display for GroundSubject { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NamedNode(node) => node.fmt(f), Self::Triple(triple) => write!( f, "<<{} {} {}>>", triple.subject, triple.predicate, triple.object ), } } } impl From for GroundSubject { #[inline] fn from(node: NamedNode) -> Self { Self::NamedNode(node) } } impl From for GroundSubject { #[inline] fn from(triple: GroundTriple) -> Self { Self::Triple(Box::new(triple)) } } impl From> for GroundSubject { #[inline] fn from(triple: Box) -> Self { Self::Triple(triple) } } impl TryFrom for GroundSubject { type Error = (); #[inline] fn try_from(subject: Subject) -> Result { match subject { Subject::NamedNode(t) => Ok(t.into()), Subject::BlankNode(_) => Err(()), Subject::Triple(t) => Ok(GroundTriple::try_from(t)?.into()), } } } impl TryFrom for GroundSubject { type Error = (); #[inline] fn try_from(term: GroundTerm) -> Result { match term { GroundTerm::NamedNode(t) => Ok(t.into()), GroundTerm::Literal(_) => Err(()), GroundTerm::Triple(t) => Ok(t.into()), } } } /// An 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) and [literals](https://www.w3.org/TR/rdf11-concepts/#dfn-literal). /// /// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation. #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum Term { NamedNode(NamedNode), BlankNode(BlankNode), Literal(Literal), Triple(Box), } impl fmt::Display for Term { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NamedNode(node) => node.fmt(f), Self::BlankNode(node) => node.fmt(f), Self::Literal(literal) => literal.fmt(f), Self::Triple(triple) => write!( f, "<<{} {} {}>>", triple.subject, triple.predicate, triple.object ), } } } impl From for Term { #[inline] fn from(node: NamedNode) -> Self { Self::NamedNode(node) } } impl From for Term { #[inline] fn from(node: BlankNode) -> Self { Self::BlankNode(node) } } impl From for Term { #[inline] fn from(literal: Literal) -> Self { Self::Literal(literal) } } impl From for Term { #[inline] fn from(triple: Triple) -> Self { Self::Triple(Box::new(triple)) } } impl From> for Term { #[inline] fn from(triple: Box) -> Self { Self::Triple(triple) } } impl From for Term { #[inline] fn from(resource: Subject) -> Self { match resource { Subject::NamedNode(node) => node.into(), Subject::BlankNode(node) => node.into(), Subject::Triple(t) => t.into(), } } } impl TryFrom for Term { type Error = (); #[inline] fn try_from(pattern: TermPattern) -> Result { match pattern { TermPattern::NamedNode(t) => Ok(t.into()), TermPattern::BlankNode(t) => Ok(t.into()), TermPattern::Literal(t) => Ok(t.into()), TermPattern::Triple(t) => Ok(Triple::try_from(t)?.into()), TermPattern::Variable(_) => Err(()), } } } /// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri), [literals](https://www.w3.org/TR/rdf11-concepts/#dfn-literal) and [triples](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple). /// /// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation. #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum GroundTerm { NamedNode(NamedNode), Literal(Literal), Triple(Box), } impl fmt::Display for GroundTerm { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NamedNode(node) => node.fmt(f), Self::Literal(literal) => literal.fmt(f), Self::Triple(triple) => write!( f, "<<{} {} {}>>", triple.subject, triple.predicate, triple.object ), } } } impl From for GroundTerm { #[inline] fn from(node: NamedNode) -> Self { Self::NamedNode(node) } } impl From for GroundTerm { #[inline] fn from(literal: Literal) -> Self { Self::Literal(literal) } } impl From for GroundTerm { #[inline] fn from(triple: GroundTriple) -> Self { Self::Triple(Box::new(triple)) } } impl From> for GroundTerm { #[inline] fn from(triple: Box) -> Self { Self::Triple(triple) } } impl TryFrom for GroundTerm { type Error = (); #[inline] fn try_from(term: Term) -> Result { match term { Term::NamedNode(t) => Ok(t.into()), Term::BlankNode(_) => Err(()), Term::Literal(t) => Ok(t.into()), Term::Triple(t) => Ok(GroundTriple::try_from(t)?.into()), } } } /// A [RDF triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple). /// /// The default string formatter is returning a N-Quads representation. /// /// ``` /// use spargebra::term::NamedNode; /// use spargebra::term::Triple; /// /// assert_eq!( /// " ", /// Triple { /// subject: NamedNode { iri: "http://example.com/foo".into() }.into(), /// predicate: NamedNode { iri: "http://schema.org/sameAs".into() }, /// object: NamedNode { iri: "http://example.com/foo".into() }.into(), /// }.to_string() /// ) /// ``` #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct Triple { pub subject: Subject, pub predicate: NamedNode, pub object: Term, } impl fmt::Display for Triple { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} {} {}", self.subject, self.predicate, self.object) } } impl TryFrom for Triple { type Error = (); #[inline] fn try_from(triple: TriplePattern) -> Result { Ok(Self { subject: triple.subject.try_into()?, predicate: triple.predicate.try_into()?, object: triple.object.try_into()?, }) } } impl TryFrom> for Triple { type Error = (); #[inline] fn try_from(triple: Box) -> Result { Ok(Self { subject: triple.subject.try_into()?, predicate: triple.predicate.try_into()?, object: triple.object.try_into()?, }) } } /// A [RDF triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) without blank nodes. /// /// The default string formatter is returning a N-Quads representation. /// /// ``` /// use spargebra::term::NamedNode; /// use spargebra::term::GroundTriple; /// /// assert_eq!( /// " ", /// GroundTriple { /// subject: NamedNode { iri: "http://example.com/foo".into() }.into(), /// predicate: NamedNode { iri: "http://schema.org/sameAs".into() }, /// object: NamedNode { iri: "http://example.com/foo".into() }.into(), /// }.to_string() /// ) /// ``` #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct GroundTriple { pub subject: GroundSubject, pub predicate: NamedNode, pub object: GroundTerm, } impl fmt::Display for GroundTriple { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} {} {}", self.subject, self.predicate, self.object) } } impl TryFrom for GroundTriple { type Error = (); #[inline] fn try_from(triple: Triple) -> Result { Ok(Self { subject: triple.subject.try_into()?, predicate: triple.predicate, object: triple.object.try_into()?, }) } } impl TryFrom> for GroundTriple { type Error = (); #[inline] fn try_from(triple: Box) -> Result { Ok(Self { subject: triple.subject.try_into()?, predicate: triple.predicate, object: triple.object.try_into()?, }) } } /// A possible graph name. /// /// It is the union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and the [default graph name](https://www.w3.org/TR/rdf11-concepts/#dfn-default-graph). #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum GraphName { NamedNode(NamedNode), DefaultGraph, } impl fmt::Display for GraphName { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NamedNode(node) => node.fmt(f), Self::DefaultGraph => write!(f, "DEFAULT"), } } } impl From for GraphName { #[inline] fn from(node: NamedNode) -> Self { Self::NamedNode(node) } } impl TryFrom for GraphName { type Error = (); #[inline] fn try_from(pattern: GraphNamePattern) -> Result { match pattern { GraphNamePattern::NamedNode(t) => Ok(t.into()), GraphNamePattern::DefaultGraph => Ok(GraphName::DefaultGraph), GraphNamePattern::Variable(_) => Err(()), } } } /// A [RDF 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). /// /// The default string formatter is returning a N-Quads representation. /// /// ``` /// use spargebra::term::NamedNode; /// use spargebra::term::Quad; /// /// assert_eq!( /// " ", /// Quad { /// subject: NamedNode { iri: "http://example.com/foo".into() }.into(), /// predicate: NamedNode { iri: "http://schema.org/sameAs".into() }, /// object: NamedNode { iri: "http://example.com/foo".into() }.into(), /// graph_name: NamedNode { iri: "http://example.com/".into() }.into(), /// }.to_string() /// ) /// ``` #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct Quad { pub subject: Subject, pub predicate: NamedNode, pub object: Term, pub graph_name: GraphName, } impl fmt::Display for Quad { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.graph_name == GraphName::DefaultGraph { write!(f, "{} {} {}", self.subject, self.predicate, self.object) } else { write!( f, "{} {} {} {}", self.subject, self.predicate, self.object, self.graph_name ) } } } impl TryFrom for Quad { type Error = (); #[inline] fn try_from(quad: QuadPattern) -> Result { Ok(Self { subject: quad.subject.try_into()?, predicate: quad.predicate.try_into()?, object: quad.object.try_into()?, graph_name: quad.graph_name.try_into()?, }) } } /// A [RDF 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) without blank nodes. /// /// The default string formatter is returning a N-Quads representation. /// /// ``` /// use spargebra::term::NamedNode; /// use spargebra::term::GroundQuad; /// /// assert_eq!( /// " ", /// GroundQuad { /// subject: NamedNode { iri: "http://example.com/foo".into() }.into(), /// predicate: NamedNode { iri: "http://schema.org/sameAs".into() }, /// object: NamedNode { iri: "http://example.com/foo".into() }.into(), /// graph_name: NamedNode { iri: "http://example.com/".into() }.into(), /// }.to_string() /// ) /// ``` #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct GroundQuad { pub subject: GroundSubject, pub predicate: NamedNode, pub object: GroundTerm, pub graph_name: GraphName, } impl fmt::Display for GroundQuad { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.graph_name == GraphName::DefaultGraph { write!(f, "{} {} {}", self.subject, self.predicate, self.object) } else { write!( f, "{} {} {} {}", self.subject, self.predicate, self.object, self.graph_name ) } } } impl TryFrom for GroundQuad { type Error = (); #[inline] fn try_from(quad: Quad) -> Result { Ok(Self { subject: quad.subject.try_into()?, predicate: quad.predicate, object: quad.object.try_into()?, graph_name: quad.graph_name, }) } } /// A [SPARQL query variable](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables). /// /// ``` /// use spargebra::term::Variable; /// /// assert_eq!( /// "?foo", /// Variable { name: "foo".into() }.to_string() /// ); /// ``` #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] pub struct Variable { pub name: String, } impl fmt::Display for Variable { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "?{}", self.name) } } /// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables). #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum NamedNodePattern { NamedNode(NamedNode), Variable(Variable), } impl fmt::Display for NamedNodePattern { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NamedNode(node) => node.fmt(f), Self::Variable(var) => var.fmt(f), } } } impl From for NamedNodePattern { #[inline] fn from(node: NamedNode) -> Self { Self::NamedNode(node) } } impl From for NamedNodePattern { #[inline] fn from(var: Variable) -> Self { Self::Variable(var) } } /// The union of [terms](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-term) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables). #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum TermPattern { NamedNode(NamedNode), BlankNode(BlankNode), Literal(Literal), Triple(Box), Variable(Variable), } impl fmt::Display for TermPattern { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NamedNode(term) => term.fmt(f), Self::BlankNode(term) => term.fmt(f), Self::Literal(term) => term.fmt(f), Self::Triple(triple) => write!(f, "<<{}>>", triple), Self::Variable(var) => var.fmt(f), } } } impl From for TermPattern { #[inline] fn from(node: NamedNode) -> Self { Self::NamedNode(node) } } impl From for TermPattern { #[inline] fn from(node: BlankNode) -> Self { Self::BlankNode(node) } } impl From for TermPattern { #[inline] fn from(literal: Literal) -> Self { Self::Literal(literal) } } impl From for TermPattern { #[inline] fn from(triple: TriplePattern) -> Self { Self::Triple(Box::new(triple)) } } impl From> for TermPattern { #[inline] fn from(triple: Box) -> Self { Self::Triple(triple) } } impl From for TermPattern { fn from(var: Variable) -> Self { Self::Variable(var) } } impl From for TermPattern { #[inline] fn from(subject: Subject) -> Self { match subject { Subject::NamedNode(node) => node.into(), Subject::BlankNode(node) => node.into(), Subject::Triple(t) => TriplePattern::from(t).into(), } } } impl From for TermPattern { #[inline] fn from(term: Term) -> Self { match term { Term::NamedNode(node) => node.into(), Term::BlankNode(node) => node.into(), Term::Literal(literal) => literal.into(), Term::Triple(t) => TriplePattern::from(t).into(), } } } impl From for TermPattern { #[inline] fn from(element: NamedNodePattern) -> Self { match element { NamedNodePattern::NamedNode(node) => node.into(), NamedNodePattern::Variable(var) => var.into(), } } } /// The union of [terms](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-term) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables) without blank nodes. #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum GroundTermPattern { NamedNode(NamedNode), Literal(Literal), Variable(Variable), Triple(Box), } impl fmt::Display for GroundTermPattern { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NamedNode(term) => term.fmt(f), Self::Literal(term) => term.fmt(f), Self::Variable(var) => var.fmt(f), Self::Triple(triple) => write!(f, "<<{}>>", triple), } } } impl From for GroundTermPattern { #[inline] fn from(node: NamedNode) -> Self { Self::NamedNode(node) } } impl From for GroundTermPattern { #[inline] fn from(literal: Literal) -> Self { Self::Literal(literal) } } impl From for GroundTermPattern { #[inline] fn from(triple: GroundTriplePattern) -> Self { Self::Triple(Box::new(triple)) } } impl From> for GroundTermPattern { #[inline] fn from(triple: Box) -> Self { Self::Triple(triple) } } impl From for GroundTermPattern { #[inline] fn from(var: Variable) -> Self { Self::Variable(var) } } impl From for GroundTermPattern { #[inline] fn from(term: GroundSubject) -> Self { match term { GroundSubject::NamedNode(node) => node.into(), GroundSubject::Triple(triple) => GroundTriplePattern::from(triple).into(), } } } impl From for GroundTermPattern { #[inline] fn from(term: GroundTerm) -> Self { match term { GroundTerm::NamedNode(node) => node.into(), GroundTerm::Literal(literal) => literal.into(), GroundTerm::Triple(triple) => GroundTriplePattern::from(triple).into(), } } } impl From for GroundTermPattern { #[inline] fn from(element: NamedNodePattern) -> Self { match element { NamedNodePattern::NamedNode(node) => node.into(), NamedNodePattern::Variable(var) => var.into(), } } } impl TryFrom for GroundTermPattern { type Error = (); #[inline] fn try_from(pattern: TermPattern) -> Result { Ok(match pattern { TermPattern::NamedNode(named_node) => named_node.into(), TermPattern::BlankNode(_) => return Err(()), TermPattern::Literal(literal) => literal.into(), TermPattern::Triple(triple) => GroundTriplePattern::try_from(triple)?.into(), TermPattern::Variable(variable) => variable.into(), }) } } /// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri), [default graph name](https://www.w3.org/TR/rdf11-concepts/#dfn-default-graph) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables). #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub enum GraphNamePattern { NamedNode(NamedNode), DefaultGraph, Variable(Variable), } impl fmt::Display for GraphNamePattern { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NamedNode(node) => node.fmt(f), Self::DefaultGraph => f.write_str("DEFAULT"), Self::Variable(var) => var.fmt(f), } } } impl From for GraphNamePattern { #[inline] fn from(node: NamedNode) -> Self { Self::NamedNode(node) } } impl From for GraphNamePattern { #[inline] fn from(var: Variable) -> Self { Self::Variable(var) } } impl From for GraphNamePattern { #[inline] fn from(graph_name: GraphName) -> Self { match graph_name { GraphName::NamedNode(node) => node.into(), GraphName::DefaultGraph => Self::DefaultGraph, } } } impl From for GraphNamePattern { #[inline] fn from(graph_name: NamedNodePattern) -> Self { match graph_name { NamedNodePattern::NamedNode(node) => node.into(), NamedNodePattern::Variable(var) => var.into(), } } } /// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct TriplePattern { pub subject: TermPattern, pub predicate: NamedNodePattern, pub object: TermPattern, } impl TriplePattern { pub(crate) fn new( subject: impl Into, predicate: impl Into, object: impl Into, ) -> Self { Self { subject: subject.into(), predicate: predicate.into(), object: object.into(), } } } impl fmt::Display for TriplePattern { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} {} {}", self.subject, self.predicate, self.object) } } impl From for TriplePattern { #[inline] fn from(triple: Triple) -> Self { Self { subject: triple.subject.into(), predicate: triple.predicate.into(), object: triple.object.into(), } } } impl From> for TriplePattern { #[inline] fn from(triple: Box) -> Self { Self { subject: triple.subject.into(), predicate: triple.predicate.into(), object: triple.object.into(), } } } /// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) without blank nodes #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct GroundTriplePattern { pub subject: GroundTermPattern, pub predicate: NamedNodePattern, pub object: GroundTermPattern, } impl fmt::Display for GroundTriplePattern { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} {} {}", self.subject, self.predicate, self.object) } } impl From for GroundTriplePattern { #[inline] fn from(triple: GroundTriple) -> Self { Self { subject: triple.subject.into(), predicate: triple.predicate.into(), object: triple.object.into(), } } } impl From> for GroundTriplePattern { #[inline] fn from(triple: Box) -> Self { Self { subject: triple.subject.into(), predicate: triple.predicate.into(), object: triple.object.into(), } } } impl TryFrom for GroundTriplePattern { type Error = (); #[inline] fn try_from(triple: TriplePattern) -> Result { Ok(Self { subject: triple.subject.try_into()?, predicate: triple.predicate, object: triple.object.try_into()?, }) } } impl TryFrom> for GroundTriplePattern { type Error = (); #[inline] fn try_from(triple: Box) -> Result { Ok(Self { subject: triple.subject.try_into()?, predicate: triple.predicate, object: triple.object.try_into()?, }) } } /// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) in a specific graph #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct QuadPattern { pub subject: TermPattern, pub predicate: NamedNodePattern, pub object: TermPattern, pub graph_name: GraphNamePattern, } impl QuadPattern { pub(crate) fn new( subject: impl Into, predicate: impl Into, object: impl Into, graph_name: impl Into, ) -> Self { Self { subject: subject.into(), predicate: predicate.into(), object: object.into(), graph_name: graph_name.into(), } } } impl fmt::Display for QuadPattern { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.graph_name == GraphNamePattern::DefaultGraph { write!(f, "{} {} {}", self.subject, self.predicate, self.object) } else { write!( f, "GRAPH {} {{ {} {} {} }}", self.graph_name, self.subject, self.predicate, self.object ) } } } /// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) in a specific graph without blank nodes #[derive(Eq, PartialEq, Debug, Clone, Hash)] pub struct GroundQuadPattern { pub subject: GroundTermPattern, pub predicate: NamedNodePattern, pub object: GroundTermPattern, pub graph_name: GraphNamePattern, } impl fmt::Display for GroundQuadPattern { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.graph_name == GraphNamePattern::DefaultGraph { write!(f, "{} {} {}", self.subject, self.predicate, self.object) } else { write!( f, "GRAPH {} {{ {} {} {} }}", self.graph_name, self.subject, self.predicate, self.object ) } } } impl TryFrom for GroundQuadPattern { type Error = (); #[inline] fn try_from(pattern: QuadPattern) -> Result { Ok(GroundQuadPattern { subject: pattern.subject.try_into()?, predicate: pattern.predicate, object: pattern.object.try_into()?, graph_name: pattern.graph_name, }) } } #[inline] pub(crate) fn print_quoted_str(string: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_char('"')?; for c in string.chars() { match c { '\n' => f.write_str("\\n"), '\r' => f.write_str("\\r"), '"' => f.write_str("\\\""), '\\' => f.write_str("\\\\"), c => f.write_char(c), }?; } f.write_char('"') }