Rust implementation of NextGraph, a Decentralized and local-first web 3.0 ecosystem https://nextgraph.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
nextgraph-rs/ng-oxigraph/src/oxrdf/triple.rs

1368 lines
36 KiB

use crate::oxrdf::blank_node::BlankNode;
use crate::oxrdf::literal::Literal;
use crate::oxrdf::named_node::NamedNode;
use crate::oxrdf::{BlankNodeRef, LiteralRef, NamedNodeRef};
use serde::{Deserialize, Serialize};
use std::fmt;
/// The owned 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).
#[derive(Eq, PartialEq, Debug, Clone, Hash, Serialize, Deserialize)]
pub enum NamedOrBlankNode {
NamedNode(NamedNode),
BlankNode(BlankNode),
}
impl NamedOrBlankNode {
#[inline]
pub fn is_named_node(&self) -> bool {
self.as_ref().is_named_node()
}
#[inline]
pub fn is_blank_node(&self) -> bool {
self.as_ref().is_blank_node()
}
#[inline]
pub fn as_ref(&self) -> NamedOrBlankNodeRef<'_> {
match self {
Self::NamedNode(node) => NamedOrBlankNodeRef::NamedNode(node.as_ref()),
Self::BlankNode(node) => NamedOrBlankNodeRef::BlankNode(node.as_ref()),
}
}
}
impl fmt::Display for NamedOrBlankNode {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_ref().fmt(f)
}
}
impl From<NamedNode> for NamedOrBlankNode {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<NamedNodeRef<'_>> for NamedOrBlankNode {
#[inline]
fn from(node: NamedNodeRef<'_>) -> Self {
node.into_owned().into()
}
}
impl From<BlankNode> for NamedOrBlankNode {
#[inline]
fn from(node: BlankNode) -> Self {
Self::BlankNode(node)
}
}
impl From<BlankNodeRef<'_>> for NamedOrBlankNode {
#[inline]
fn from(node: BlankNodeRef<'_>) -> Self {
node.into_owned().into()
}
}
/// The borrowed 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).
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
pub enum NamedOrBlankNodeRef<'a> {
NamedNode(NamedNodeRef<'a>),
BlankNode(BlankNodeRef<'a>),
}
impl<'a> NamedOrBlankNodeRef<'a> {
#[inline]
pub fn is_named_node(&self) -> bool {
match self {
Self::NamedNode(_) => true,
Self::BlankNode(_) => false,
}
}
#[inline]
pub fn is_blank_node(&self) -> bool {
match self {
Self::NamedNode(_) => false,
Self::BlankNode(_) => true,
}
}
#[inline]
pub fn into_owned(self) -> NamedOrBlankNode {
match self {
Self::NamedNode(node) => NamedOrBlankNode::NamedNode(node.into_owned()),
Self::BlankNode(node) => NamedOrBlankNode::BlankNode(node.into_owned()),
}
}
}
impl fmt::Display for NamedOrBlankNodeRef<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NamedNode(node) => node.fmt(f),
Self::BlankNode(node) => node.fmt(f),
}
}
}
impl<'a> From<NamedNodeRef<'a>> for NamedOrBlankNodeRef<'a> {
#[inline]
fn from(node: NamedNodeRef<'a>) -> Self {
Self::NamedNode(node)
}
}
impl<'a> From<&'a NamedNode> for NamedOrBlankNodeRef<'a> {
#[inline]
fn from(node: &'a NamedNode) -> Self {
node.as_ref().into()
}
}
impl<'a> From<BlankNodeRef<'a>> for NamedOrBlankNodeRef<'a> {
#[inline]
fn from(node: BlankNodeRef<'a>) -> Self {
Self::BlankNode(node)
}
}
impl<'a> From<&'a BlankNode> for NamedOrBlankNodeRef<'a> {
#[inline]
fn from(node: &'a BlankNode) -> Self {
node.as_ref().into()
}
}
impl<'a> From<&'a NamedOrBlankNode> for NamedOrBlankNodeRef<'a> {
#[inline]
fn from(node: &'a NamedOrBlankNode) -> Self {
node.as_ref()
}
}
impl<'a> From<NamedOrBlankNodeRef<'a>> for NamedOrBlankNode {
#[inline]
fn from(node: NamedOrBlankNodeRef<'a>) -> Self {
node.into_owned()
}
}
/// 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) (if the `rdf-star` feature is enabled).
#[derive(Eq, PartialEq, Debug, Clone, Hash, Serialize, Deserialize)]
pub enum Subject {
NamedNode(NamedNode),
BlankNode(BlankNode),
#[cfg(feature = "rdf-star")]
Triple(Box<Triple>),
}
impl Subject {
#[inline]
pub fn is_named_node(&self) -> bool {
self.as_ref().is_named_node()
}
#[inline]
pub fn is_blank_node(&self) -> bool {
self.as_ref().is_blank_node()
}
#[cfg(feature = "rdf-star")]
#[inline]
pub fn is_triple(&self) -> bool {
self.as_ref().is_triple()
}
#[inline]
pub fn as_ref(&self) -> SubjectRef<'_> {
match self {
Self::NamedNode(node) => SubjectRef::NamedNode(node.as_ref()),
Self::BlankNode(node) => SubjectRef::BlankNode(node.as_ref()),
#[cfg(feature = "rdf-star")]
Self::Triple(triple) => SubjectRef::Triple(triple),
}
}
}
impl fmt::Display for Subject {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_ref().fmt(f)
}
}
impl From<NamedNode> for Subject {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<NamedNodeRef<'_>> for Subject {
#[inline]
fn from(node: NamedNodeRef<'_>) -> Self {
node.into_owned().into()
}
}
impl From<BlankNode> for Subject {
#[inline]
fn from(node: BlankNode) -> Self {
Self::BlankNode(node)
}
}
impl From<BlankNodeRef<'_>> for Subject {
#[inline]
fn from(node: BlankNodeRef<'_>) -> Self {
node.into_owned().into()
}
}
#[cfg(feature = "rdf-star")]
impl From<Triple> for Subject {
#[inline]
fn from(node: Triple) -> Self {
Self::Triple(Box::new(node))
}
}
#[cfg(feature = "rdf-star")]
impl From<Box<Triple>> for Subject {
#[inline]
fn from(node: Box<Triple>) -> Self {
Self::Triple(node)
}
}
#[cfg(feature = "rdf-star")]
impl From<TripleRef<'_>> for Subject {
#[inline]
fn from(node: TripleRef<'_>) -> Self {
node.into_owned().into()
}
}
impl From<NamedOrBlankNode> for Subject {
#[inline]
fn from(node: NamedOrBlankNode) -> Self {
match node {
NamedOrBlankNode::NamedNode(node) => node.into(),
NamedOrBlankNode::BlankNode(node) => node.into(),
}
}
}
impl From<NamedOrBlankNodeRef<'_>> for Subject {
#[inline]
fn from(node: NamedOrBlankNodeRef<'_>) -> Self {
node.into_owned().into()
}
}
/// The borrowed 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) (if the `rdf-star` feature is enabled).
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
pub enum SubjectRef<'a> {
NamedNode(NamedNodeRef<'a>),
BlankNode(BlankNodeRef<'a>),
#[cfg(feature = "rdf-star")]
Triple(&'a Triple),
}
impl<'a> SubjectRef<'a> {
#[inline]
pub fn is_named_node(&self) -> bool {
matches!(self, Self::NamedNode(_))
}
#[inline]
pub fn is_blank_node(&self) -> bool {
matches!(self, Self::BlankNode(_))
}
#[cfg(feature = "rdf-star")]
#[inline]
pub fn is_triple(&self) -> bool {
matches!(self, Self::Triple(_))
}
#[inline]
pub fn into_owned(self) -> Subject {
match self {
Self::NamedNode(node) => Subject::NamedNode(node.into_owned()),
Self::BlankNode(node) => Subject::BlankNode(node.into_owned()),
#[cfg(feature = "rdf-star")]
Self::Triple(triple) => Subject::Triple(Box::new(triple.clone())),
}
}
}
impl fmt::Display for SubjectRef<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NamedNode(node) => node.fmt(f),
Self::BlankNode(node) => node.fmt(f),
#[cfg(feature = "rdf-star")]
Self::Triple(triple) => write!(f, "<<{triple}>>"),
}
}
}
impl<'a> From<NamedNodeRef<'a>> for SubjectRef<'a> {
#[inline]
fn from(node: NamedNodeRef<'a>) -> Self {
Self::NamedNode(node)
}
}
impl<'a> From<&'a NamedNode> for SubjectRef<'a> {
#[inline]
fn from(node: &'a NamedNode) -> Self {
node.as_ref().into()
}
}
impl<'a> From<BlankNodeRef<'a>> for SubjectRef<'a> {
#[inline]
fn from(node: BlankNodeRef<'a>) -> Self {
Self::BlankNode(node)
}
}
impl<'a> From<&'a BlankNode> for SubjectRef<'a> {
#[inline]
fn from(node: &'a BlankNode) -> Self {
node.as_ref().into()
}
}
#[cfg(feature = "rdf-star")]
impl<'a> From<&'a Triple> for SubjectRef<'a> {
#[inline]
fn from(node: &'a Triple) -> Self {
Self::Triple(node)
}
}
impl<'a> From<&'a Subject> for SubjectRef<'a> {
#[inline]
fn from(node: &'a Subject) -> Self {
node.as_ref()
}
}
impl<'a> From<SubjectRef<'a>> for Subject {
#[inline]
fn from(node: SubjectRef<'a>) -> Self {
node.into_owned()
}
}
impl<'a> From<NamedOrBlankNodeRef<'a>> for SubjectRef<'a> {
#[inline]
fn from(node: NamedOrBlankNodeRef<'a>) -> Self {
match node {
NamedOrBlankNodeRef::NamedNode(node) => node.into(),
NamedOrBlankNodeRef::BlankNode(node) => node.into(),
}
}
}
impl<'a> From<&'a NamedOrBlankNode> for SubjectRef<'a> {
#[inline]
fn from(node: &'a NamedOrBlankNode) -> Self {
node.as_ref().into()
}
}
/// 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) (if the `rdf-star` feature is enabled).
#[derive(Eq, PartialEq, Debug, Clone, Hash, Serialize, Deserialize)]
pub enum Term {
NamedNode(NamedNode),
BlankNode(BlankNode),
Literal(Literal),
#[cfg(feature = "rdf-star")]
Triple(Box<Triple>),
}
impl Term {
#[inline]
pub fn is_named_node(&self) -> bool {
self.as_ref().is_named_node()
}
#[inline]
pub fn is_blank_node(&self) -> bool {
self.as_ref().is_blank_node()
}
#[inline]
pub fn is_literal(&self) -> bool {
self.as_ref().is_literal()
}
#[cfg(feature = "rdf-star")]
#[inline]
pub fn is_triple(&self) -> bool {
self.as_ref().is_triple()
}
#[inline]
pub fn as_ref(&self) -> TermRef<'_> {
match self {
Self::NamedNode(node) => TermRef::NamedNode(node.as_ref()),
Self::BlankNode(node) => TermRef::BlankNode(node.as_ref()),
Self::Literal(literal) => TermRef::Literal(literal.as_ref()),
#[cfg(feature = "rdf-star")]
Self::Triple(triple) => TermRef::Triple(triple),
}
}
}
impl fmt::Display for Term {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_ref().fmt(f)
}
}
impl From<NamedNode> for Term {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<NamedNodeRef<'_>> for Term {
#[inline]
fn from(node: NamedNodeRef<'_>) -> Self {
node.into_owned().into()
}
}
impl From<BlankNode> for Term {
#[inline]
fn from(node: BlankNode) -> Self {
Self::BlankNode(node)
}
}
impl From<BlankNodeRef<'_>> for Term {
#[inline]
fn from(node: BlankNodeRef<'_>) -> Self {
node.into_owned().into()
}
}
impl From<Literal> for Term {
#[inline]
fn from(literal: Literal) -> Self {
Self::Literal(literal)
}
}
impl From<LiteralRef<'_>> for Term {
#[inline]
fn from(literal: LiteralRef<'_>) -> Self {
literal.into_owned().into()
}
}
#[cfg(feature = "rdf-star")]
impl From<Triple> for Term {
#[inline]
fn from(triple: Triple) -> Self {
Self::Triple(Box::new(triple))
}
}
#[cfg(feature = "rdf-star")]
impl From<Box<Triple>> for Term {
#[inline]
fn from(node: Box<Triple>) -> Self {
Self::Triple(node)
}
}
#[cfg(feature = "rdf-star")]
impl From<TripleRef<'_>> for Term {
#[inline]
fn from(triple: TripleRef<'_>) -> Self {
triple.into_owned().into()
}
}
impl From<NamedOrBlankNode> for Term {
#[inline]
fn from(node: NamedOrBlankNode) -> Self {
match node {
NamedOrBlankNode::NamedNode(node) => node.into(),
NamedOrBlankNode::BlankNode(node) => node.into(),
}
}
}
impl From<NamedOrBlankNodeRef<'_>> for Term {
#[inline]
fn from(node: NamedOrBlankNodeRef<'_>) -> Self {
node.into_owned().into()
}
}
impl From<Subject> for Term {
#[inline]
fn from(node: Subject) -> Self {
match node {
Subject::NamedNode(node) => node.into(),
Subject::BlankNode(node) => node.into(),
#[cfg(feature = "rdf-star")]
Subject::Triple(triple) => Self::Triple(triple),
}
}
}
impl From<SubjectRef<'_>> for Term {
#[inline]
fn from(node: SubjectRef<'_>) -> Self {
node.into_owned().into()
}
}
impl TryFrom<Term> for NamedNode {
type Error = TryFromTermError;
#[inline]
fn try_from(term: Term) -> Result<Self, Self::Error> {
if let Term::NamedNode(node) = term {
Ok(node)
} else {
Err(TryFromTermError {
term,
target: "NamedNode",
})
}
}
}
impl TryFrom<Term> for BlankNode {
type Error = TryFromTermError;
#[inline]
fn try_from(term: Term) -> Result<Self, Self::Error> {
if let Term::BlankNode(node) = term {
Ok(node)
} else {
Err(TryFromTermError {
term,
target: "BlankNode",
})
}
}
}
impl TryFrom<Term> for Literal {
type Error = TryFromTermError;
#[inline]
fn try_from(term: Term) -> Result<Self, Self::Error> {
if let Term::Literal(node) = term {
Ok(node)
} else {
Err(TryFromTermError {
term,
target: "Literal",
})
}
}
}
impl TryFrom<Term> for Subject {
type Error = TryFromTermError;
#[inline]
fn try_from(term: Term) -> Result<Self, Self::Error> {
match term {
Term::NamedNode(term) => Ok(Self::NamedNode(term)),
Term::BlankNode(term) => Ok(Self::BlankNode(term)),
#[cfg(feature = "rdf-star")]
Term::Triple(term) => Ok(Self::Triple(term)),
Term::Literal(_) => Err(TryFromTermError {
term,
target: "Subject",
}),
}
}
}
/// A borrowed 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) (if the `rdf-star` feature is enabled).
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
pub enum TermRef<'a> {
NamedNode(NamedNodeRef<'a>),
BlankNode(BlankNodeRef<'a>),
Literal(LiteralRef<'a>),
#[cfg(feature = "rdf-star")]
Triple(&'a Triple),
}
impl<'a> TermRef<'a> {
#[inline]
pub fn is_named_node(&self) -> bool {
matches!(self, Self::NamedNode(_))
}
#[inline]
pub fn is_blank_node(&self) -> bool {
matches!(self, Self::BlankNode(_))
}
#[inline]
pub fn is_literal(&self) -> bool {
matches!(self, Self::Literal(_))
}
#[cfg(feature = "rdf-star")]
#[inline]
pub fn is_triple(&self) -> bool {
matches!(self, Self::Triple(_))
}
#[inline]
pub fn into_owned(self) -> Term {
match self {
Self::NamedNode(node) => Term::NamedNode(node.into_owned()),
Self::BlankNode(node) => Term::BlankNode(node.into_owned()),
Self::Literal(literal) => Term::Literal(literal.into_owned()),
#[cfg(feature = "rdf-star")]
Self::Triple(triple) => Term::Triple(Box::new(triple.clone())),
}
}
}
impl fmt::Display for TermRef<'_> {
#[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),
#[cfg(feature = "rdf-star")]
Self::Triple(triple) => {
write!(f, "<<{triple}>>")
}
}
}
}
impl<'a> From<NamedNodeRef<'a>> for TermRef<'a> {
#[inline]
fn from(node: NamedNodeRef<'a>) -> Self {
Self::NamedNode(node)
}
}
impl<'a> From<&'a NamedNode> for TermRef<'a> {
#[inline]
fn from(node: &'a NamedNode) -> Self {
node.as_ref().into()
}
}
impl<'a> From<BlankNodeRef<'a>> for TermRef<'a> {
#[inline]
fn from(node: BlankNodeRef<'a>) -> Self {
Self::BlankNode(node)
}
}
impl<'a> From<&'a BlankNode> for TermRef<'a> {
#[inline]
fn from(node: &'a BlankNode) -> Self {
node.as_ref().into()
}
}
impl<'a> From<LiteralRef<'a>> for TermRef<'a> {
#[inline]
fn from(literal: LiteralRef<'a>) -> Self {
Self::Literal(literal)
}
}
impl<'a> From<&'a Literal> for TermRef<'a> {
#[inline]
fn from(literal: &'a Literal) -> Self {
literal.as_ref().into()
}
}
#[cfg(feature = "rdf-star")]
impl<'a> From<&'a Triple> for TermRef<'a> {
#[inline]
fn from(node: &'a Triple) -> Self {
Self::Triple(node)
}
}
impl<'a> From<NamedOrBlankNodeRef<'a>> for TermRef<'a> {
#[inline]
fn from(node: NamedOrBlankNodeRef<'a>) -> Self {
match node {
NamedOrBlankNodeRef::NamedNode(node) => node.into(),
NamedOrBlankNodeRef::BlankNode(node) => node.into(),
}
}
}
impl<'a> From<&'a NamedOrBlankNode> for TermRef<'a> {
#[inline]
fn from(node: &'a NamedOrBlankNode) -> Self {
node.as_ref().into()
}
}
impl<'a> From<SubjectRef<'a>> for TermRef<'a> {
#[inline]
fn from(node: SubjectRef<'a>) -> Self {
match node {
SubjectRef::NamedNode(node) => node.into(),
SubjectRef::BlankNode(node) => node.into(),
#[cfg(feature = "rdf-star")]
SubjectRef::Triple(triple) => triple.into(),
}
}
}
impl<'a> From<&'a Subject> for TermRef<'a> {
#[inline]
fn from(node: &'a Subject) -> Self {
node.as_ref().into()
}
}
impl<'a> From<&'a Term> for TermRef<'a> {
#[inline]
fn from(node: &'a Term) -> Self {
node.as_ref()
}
}
impl<'a> From<TermRef<'a>> for Term {
#[inline]
fn from(node: TermRef<'a>) -> Self {
node.into_owned()
}
}
/// An owned [RDF triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple).
///
/// The default string formatter is returning an N-Triples, Turtle, and SPARQL compatible representation:
/// ```
/// use oxrdf::{NamedNode, Triple};
///
/// assert_eq!(
/// "<http://example.com/s> <http://example.com/p> <http://example.com/o>",
/// Triple {
/// subject: NamedNode::new("http://example.com/s")?.into(),
/// predicate: NamedNode::new("http://example.com/p")?,
/// object: NamedNode::new("http://example.com/o")?.into(),
/// }
/// .to_string()
/// );
/// # Result::<_,oxrdf::IriParseError>::Ok(())
/// ```
#[derive(Eq, PartialEq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct Triple {
/// The [subject](https://www.w3.org/TR/rdf11-concepts/#dfn-subject) of this triple.
pub subject: Subject,
/// The [predicate](https://www.w3.org/TR/rdf11-concepts/#dfn-predicate) of this triple.
pub predicate: NamedNode,
/// The [object](https://www.w3.org/TR/rdf11-concepts/#dfn-object) of this triple.
pub object: Term,
}
impl Triple {
/// Builds an RDF [triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple).
#[inline]
pub fn new(
subject: impl Into<Subject>,
predicate: impl Into<NamedNode>,
object: impl Into<Term>,
) -> Self {
Self {
subject: subject.into(),
predicate: predicate.into(),
object: object.into(),
}
}
/// Builds an RDF [triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) from [`Term`]s.
///
/// Returns a [`TryFromTermError`] error if the generated triple would be ill-formed.
#[inline]
pub fn from_terms(
subject: impl Into<Term>,
predicate: impl Into<Term>,
object: impl Into<Term>,
) -> Result<Self, TryFromTermError> {
Ok(Self {
subject: subject.into().try_into()?,
predicate: predicate.into().try_into()?,
object: object.into(),
})
}
/// Encodes that this triple is in an [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset).
#[inline]
pub fn in_graph(self, graph_name: impl Into<GraphName>) -> Quad {
Quad {
subject: self.subject,
predicate: self.predicate,
object: self.object,
graph_name: graph_name.into(),
}
}
#[inline]
pub fn as_ref(&self) -> TripleRef<'_> {
TripleRef {
subject: self.subject.as_ref(),
predicate: self.predicate.as_ref(),
object: self.object.as_ref(),
}
}
}
impl fmt::Display for Triple {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_ref().fmt(f)
}
}
/// A borrowed [RDF triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple).
///
/// The default string formatter is returning an N-Triples, Turtle, and SPARQL compatible representation:
/// ```
/// use oxrdf::{NamedNodeRef, TripleRef};
///
/// assert_eq!(
/// "<http://example.com/s> <http://example.com/p> <http://example.com/o>",
/// TripleRef {
/// subject: NamedNodeRef::new("http://example.com/s")?.into(),
/// predicate: NamedNodeRef::new("http://example.com/p")?,
/// object: NamedNodeRef::new("http://example.com/o")?.into(),
/// }
/// .to_string()
/// );
/// # Result::<_,oxrdf::IriParseError>::Ok(())
/// ```
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
pub struct TripleRef<'a> {
/// The [subject](https://www.w3.org/TR/rdf11-concepts/#dfn-subject) of this triple.
pub subject: SubjectRef<'a>,
/// The [predicate](https://www.w3.org/TR/rdf11-concepts/#dfn-predicate) of this triple.
pub predicate: NamedNodeRef<'a>,
/// The [object](https://www.w3.org/TR/rdf11-concepts/#dfn-object) of this triple.
pub object: TermRef<'a>,
}
impl<'a> TripleRef<'a> {
/// Builds an RDF [triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple).
#[inline]
pub fn new(
subject: impl Into<SubjectRef<'a>>,
predicate: impl Into<NamedNodeRef<'a>>,
object: impl Into<TermRef<'a>>,
) -> Self {
Self {
subject: subject.into(),
predicate: predicate.into(),
object: object.into(),
}
}
/// Encodes that this triple is in an [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset).
#[inline]
pub fn in_graph(self, graph_name: impl Into<GraphNameRef<'a>>) -> QuadRef<'a> {
QuadRef {
subject: self.subject,
predicate: self.predicate,
object: self.object,
graph_name: graph_name.into(),
}
}
#[inline]
pub fn into_owned(self) -> Triple {
Triple {
subject: self.subject.into_owned(),
predicate: self.predicate.into_owned(),
object: self.object.into_owned(),
}
}
}
impl fmt::Display for TripleRef<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {} {}", self.subject, self.predicate, self.object)
}
}
impl<'a> From<&'a Triple> for TripleRef<'a> {
#[inline]
fn from(triple: &'a Triple) -> Self {
triple.as_ref()
}
}
impl<'a> From<TripleRef<'a>> for Triple {
#[inline]
fn from(triple: TripleRef<'a>) -> Self {
triple.into_owned()
}
}
/// 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, Default, Serialize, Deserialize)]
pub enum GraphName {
NamedNode(NamedNode),
BlankNode(BlankNode),
#[default]
DefaultGraph,
}
impl GraphName {
#[inline]
pub fn is_named_node(&self) -> bool {
self.as_ref().is_named_node()
}
#[inline]
pub fn is_blank_node(&self) -> bool {
self.as_ref().is_blank_node()
}
#[inline]
pub fn is_default_graph(&self) -> bool {
self.as_ref().is_default_graph()
}
#[inline]
pub fn as_ref(&self) -> GraphNameRef<'_> {
match self {
Self::NamedNode(node) => GraphNameRef::NamedNode(node.as_ref()),
Self::BlankNode(node) => GraphNameRef::BlankNode(node.as_ref()),
Self::DefaultGraph => GraphNameRef::DefaultGraph,
}
}
}
impl fmt::Display for GraphName {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_ref().fmt(f)
}
}
impl From<NamedNode> for GraphName {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<NamedNodeRef<'_>> for GraphName {
#[inline]
fn from(node: NamedNodeRef<'_>) -> Self {
node.into_owned().into()
}
}
impl From<BlankNode> for GraphName {
#[inline]
fn from(node: BlankNode) -> Self {
Self::BlankNode(node)
}
}
impl From<BlankNodeRef<'_>> for GraphName {
#[inline]
fn from(node: BlankNodeRef<'_>) -> Self {
node.into_owned().into()
}
}
impl From<NamedOrBlankNode> for GraphName {
#[inline]
fn from(node: NamedOrBlankNode) -> Self {
match node {
NamedOrBlankNode::NamedNode(node) => node.into(),
NamedOrBlankNode::BlankNode(node) => node.into(),
}
}
}
impl From<NamedOrBlankNodeRef<'_>> for GraphName {
#[inline]
fn from(node: NamedOrBlankNodeRef<'_>) -> Self {
node.into_owned().into()
}
}
/// A possible borrowed 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, Copy, Hash, Default)]
pub enum GraphNameRef<'a> {
NamedNode(NamedNodeRef<'a>),
BlankNode(BlankNodeRef<'a>),
#[default]
DefaultGraph,
}
impl<'a> GraphNameRef<'a> {
#[inline]
pub fn is_named_node(&self) -> bool {
matches!(self, Self::NamedNode(_))
}
#[inline]
pub fn is_blank_node(&self) -> bool {
matches!(self, Self::BlankNode(_))
}
#[inline]
pub fn is_default_graph(&self) -> bool {
matches!(self, Self::DefaultGraph)
}
#[inline]
pub fn into_owned(self) -> GraphName {
match self {
Self::NamedNode(node) => GraphName::NamedNode(node.into_owned()),
Self::BlankNode(node) => GraphName::BlankNode(node.into_owned()),
Self::DefaultGraph => GraphName::DefaultGraph,
}
}
}
impl fmt::Display for GraphNameRef<'_> {
#[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::DefaultGraph => f.write_str("DEFAULT"),
}
}
}
impl<'a> From<NamedNodeRef<'a>> for GraphNameRef<'a> {
#[inline]
fn from(node: NamedNodeRef<'a>) -> Self {
Self::NamedNode(node)
}
}
impl<'a> From<&'a NamedNode> for GraphNameRef<'a> {
#[inline]
fn from(node: &'a NamedNode) -> Self {
node.as_ref().into()
}
}
impl<'a> From<BlankNodeRef<'a>> for GraphNameRef<'a> {
#[inline]
fn from(node: BlankNodeRef<'a>) -> Self {
Self::BlankNode(node)
}
}
impl<'a> From<&'a BlankNode> for GraphNameRef<'a> {
#[inline]
fn from(node: &'a BlankNode) -> Self {
node.as_ref().into()
}
}
impl<'a> From<NamedOrBlankNodeRef<'a>> for GraphNameRef<'a> {
#[inline]
fn from(node: NamedOrBlankNodeRef<'a>) -> Self {
match node {
NamedOrBlankNodeRef::NamedNode(node) => node.into(),
NamedOrBlankNodeRef::BlankNode(node) => node.into(),
}
}
}
impl<'a> From<&'a NamedOrBlankNode> for GraphNameRef<'a> {
#[inline]
fn from(node: &'a NamedOrBlankNode) -> Self {
node.as_ref().into()
}
}
impl<'a> From<&'a GraphName> for GraphNameRef<'a> {
#[inline]
fn from(node: &'a GraphName) -> Self {
node.as_ref()
}
}
impl<'a> From<GraphNameRef<'a>> for GraphName {
#[inline]
fn from(node: GraphNameRef<'a>) -> Self {
node.into_owned()
}
}
/// An owned [triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) in an [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset).
///
/// The default string formatter is returning an N-Quads compatible representation:
/// ```
/// use oxrdf::{Quad, NamedNode};
///
/// assert_eq!(
/// "<http://example.com/s> <http://example.com/p> <http://example.com/o> <http://example.com/g>",
/// Quad {
/// subject: NamedNode::new("http://example.com/s")?.into(),
/// predicate: NamedNode::new("http://example.com/p")?,
/// object: NamedNode::new("http://example.com/o")?.into(),
/// graph_name: NamedNode::new("http://example.com/g")?.into(),
/// }.to_string()
/// );
/// # Result::<_,oxrdf::IriParseError>::Ok(())
/// ```
#[derive(Eq, PartialEq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct Quad {
/// The [subject](https://www.w3.org/TR/rdf11-concepts/#dfn-subject) of this triple.
pub subject: Subject,
/// The [predicate](https://www.w3.org/TR/rdf11-concepts/#dfn-predicate) of this triple.
pub predicate: NamedNode,
/// The [object](https://www.w3.org/TR/rdf11-concepts/#dfn-object) of this triple.
pub object: Term,
/// The name of the RDF [graph](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-graph) in which the triple is.
pub graph_name: GraphName,
}
impl Quad {
/// Builds an RDF [triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) in an [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset).
#[inline]
pub fn new(
subject: impl Into<Subject>,
predicate: impl Into<NamedNode>,
object: impl Into<Term>,
graph_name: impl Into<GraphName>,
) -> Self {
Self {
subject: subject.into(),
predicate: predicate.into(),
object: object.into(),
graph_name: graph_name.into(),
}
}
#[inline]
pub fn as_ref(&self) -> QuadRef<'_> {
QuadRef {
subject: self.subject.as_ref(),
predicate: self.predicate.as_ref(),
object: self.object.as_ref(),
graph_name: self.graph_name.as_ref(),
}
}
}
impl fmt::Display for Quad {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_ref().fmt(f)
}
}
impl From<Quad> for Triple {
#[inline]
fn from(quad: Quad) -> Self {
Self {
subject: quad.subject,
predicate: quad.predicate,
object: quad.object,
}
}
}
/// A borrowed [triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) in an [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset).
///
/// The default string formatter is returning an N-Quads compatible representation:
/// ```
/// use oxrdf::{QuadRef, NamedNodeRef};
///
/// assert_eq!(
/// "<http://example.com/s> <http://example.com/p> <http://example.com/o> <http://example.com/g>",
/// QuadRef {
/// subject: NamedNodeRef::new("http://example.com/s")?.into(),
/// predicate: NamedNodeRef::new("http://example.com/p")?,
/// object: NamedNodeRef::new("http://example.com/o")?.into(),
/// graph_name: NamedNodeRef::new("http://example.com/g")?.into(),
/// }.to_string()
/// );
/// # Result::<_,oxrdf::IriParseError>::Ok(())
/// ```
#[derive(Eq, PartialEq, Debug, Clone, Copy, Hash)]
pub struct QuadRef<'a> {
/// The [subject](https://www.w3.org/TR/rdf11-concepts/#dfn-subject) of this triple.
pub subject: SubjectRef<'a>,
/// The [predicate](https://www.w3.org/TR/rdf11-concepts/#dfn-predicate) of this triple.
pub predicate: NamedNodeRef<'a>,
/// The [object](https://www.w3.org/TR/rdf11-concepts/#dfn-object) of this triple.
pub object: TermRef<'a>,
/// The name of the RDF [graph](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-graph) in which the triple is.
pub graph_name: GraphNameRef<'a>,
}
impl<'a> QuadRef<'a> {
/// Builds an RDF [triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) in an [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset).
#[inline]
pub fn new(
subject: impl Into<SubjectRef<'a>>,
predicate: impl Into<NamedNodeRef<'a>>,
object: impl Into<TermRef<'a>>,
graph_name: impl Into<GraphNameRef<'a>>,
) -> Self {
Self {
subject: subject.into(),
predicate: predicate.into(),
object: object.into(),
graph_name: graph_name.into(),
}
}
#[inline]
pub fn into_owned(self) -> Quad {
Quad {
subject: self.subject.into_owned(),
predicate: self.predicate.into_owned(),
object: self.object.into_owned(),
graph_name: self.graph_name.into_owned(),
}
}
}
impl fmt::Display for QuadRef<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.graph_name.is_default_graph() {
write!(f, "{} {} {}", self.subject, self.predicate, self.object)
} else {
write!(
f,
"{} {} {} {}",
self.subject, self.predicate, self.object, self.graph_name
)
}
}
}
impl<'a> From<QuadRef<'a>> for TripleRef<'a> {
#[inline]
fn from(quad: QuadRef<'a>) -> Self {
Self {
subject: quad.subject,
predicate: quad.predicate,
object: quad.object,
}
}
}
impl<'a> From<&'a Quad> for QuadRef<'a> {
#[inline]
fn from(quad: &'a Quad) -> Self {
quad.as_ref()
}
}
impl<'a> From<QuadRef<'a>> for Quad {
#[inline]
fn from(quad: QuadRef<'a>) -> Self {
quad.into_owned()
}
}
/// An error return by some [`TryFrom<Term>`](TryFrom) implementations.
#[derive(Debug, Clone, thiserror::Error)]
#[error("{term} can not be converted to a {target}")]
pub struct TryFromTermError {
pub(crate) term: Term,
pub(crate) target: &'static str,
}
impl TryFromTermError {
/// The term that can't be converted
#[inline]
pub fn into_term(self) -> Term {
self.term
}
}
#[cfg(test)]
#[allow(clippy::panic_in_result_fn)]
mod tests {
use super::*;
#[test]
fn triple_from_terms() -> Result<(), TryFromTermError> {
assert_eq!(
Triple::from_terms(
NamedNode::new_unchecked("http://example.com/s"),
NamedNode::new_unchecked("http://example.com/p"),
NamedNode::new_unchecked("http://example.com/o"),
)?,
Triple::new(
NamedNode::new_unchecked("http://example.com/s"),
NamedNode::new_unchecked("http://example.com/p"),
NamedNode::new_unchecked("http://example.com/o"),
)
);
assert_eq!(
Triple::from_terms(
Literal::new_simple_literal("foo"),
NamedNode::new_unchecked("http://example.com/p"),
NamedNode::new_unchecked("http://example.com/o"),
)
.unwrap_err()
.into_term(),
Term::from(Literal::new_simple_literal("foo"))
);
assert_eq!(
Triple::from_terms(
NamedNode::new_unchecked("http://example.com/s"),
Literal::new_simple_literal("foo"),
NamedNode::new_unchecked("http://example.com/o"),
)
.unwrap_err()
.into_term(),
Term::from(Literal::new_simple_literal("foo"))
);
Ok(())
}
}