use std::error::Error;
use crate::dataset::adapter::GraphAsDataset;
use crate::source::{IntoSource, StreamResult, TripleSource};
use crate::term::{matcher::TermMatcher, SimpleTerm, Term};
use crate::triple::Triple;
use resiter::{filter::*, flat_map::*, map::*};
mod _foreign_impl;
pub mod adapter;
#[cfg(any(test, feature = "test_macro"))]
#[macro_use]
pub mod test;
pub type GResult<G, T> = Result<T, <G as Graph>::Error>;
#[deprecated(
since = "0.8.1",
note = "prototypes of `triples` and `triples_matching` have changed"
)]
pub type GTripleSource<'a, G> = Box<dyn Iterator<Item = GResult<G, <G as Graph>::Triple<'a>>> + 'a>;
pub type GTerm<'a, G> = <<G as Graph>::Triple<'a> as Triple>::Term;
#[deprecated(
since = "0.8.1",
note = "prototypes of term-yielding methods have changed"
)]
pub type GTermSource<'a, G> = Box<dyn Iterator<Item = GResult<G, GTerm<'a, G>>> + 'a>;
pub trait Graph {
type Triple<'x>: Triple
where
Self: 'x;
type Error: Error + Send + Sync + 'static;
fn triples(&self) -> impl Iterator<Item = GResult<Self, Self::Triple<'_>>> + '_;
fn triples_matching<'s, S, P, O>(
&'s self,
sm: S,
pm: P,
om: O,
) -> impl Iterator<Item = GResult<Self, Self::Triple<'s>>> + 's
where
S: TermMatcher + 's,
P: TermMatcher + 's,
O: TermMatcher + 's,
{
self.triples()
.filter_ok(move |t| t.matched_by(sm.matcher_ref(), pm.matcher_ref(), om.matcher_ref()))
}
fn contains<TS, TP, TO>(&self, s: TS, p: TP, o: TO) -> GResult<Self, bool>
where
TS: Term,
TP: Term,
TO: Term,
{
self.triples_matching([s], [p], [o])
.next()
.transpose()
.map(|o| o.is_some())
}
fn subjects(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
self.triples().map_ok(Triple::to_s)
}
fn predicates(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
self.triples().map_ok(Triple::to_p)
}
fn objects(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
self.triples().map_ok(Triple::to_o)
}
fn iris(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
self.triples()
.flat_map_ok(Triple::to_spo)
.flat_map_ok(Term::to_atoms)
.filter_ok(Term::is_iri)
}
fn blank_nodes(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
self.triples()
.flat_map_ok(Triple::to_spo)
.flat_map_ok(Term::to_atoms)
.filter_ok(Term::is_blank_node)
}
fn literals(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
self.triples()
.flat_map_ok(Triple::to_spo)
.flat_map_ok(Term::to_atoms)
.filter_ok(Term::is_literal)
}
fn quoted_triples<'s>(&'s self) -> Box<dyn Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_>
where
GTerm<'s, Self>: Clone,
{
Box::new(
self.triples()
.flat_map_ok(Triple::to_spo)
.flat_map_ok(Term::to_constituents)
.filter_ok(Term::is_triple),
)
}
fn variables(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
self.triples()
.flat_map_ok(Triple::to_spo)
.flat_map_ok(Term::to_atoms)
.filter_ok(Term::is_variable)
}
fn as_dataset(&self) -> GraphAsDataset<&Self> {
GraphAsDataset::new(self)
}
fn as_dataset_mut(&mut self) -> GraphAsDataset<&mut Self> {
GraphAsDataset::new(self)
}
fn into_dataset(self) -> GraphAsDataset<Self>
where
Self: Sized,
{
GraphAsDataset::new(self)
}
}
pub trait CollectibleGraph: Graph + Sized {
fn from_triple_source<TS: TripleSource>(
triples: TS,
) -> StreamResult<Self, TS::Error, Self::Error>;
}
pub type MgResult<G, T> = std::result::Result<T, <G as MutableGraph>::MutationError>;
pub trait MutableGraph: Graph {
type MutationError: Error + Send + Sync + 'static;
fn insert<TS, TP, TO>(&mut self, s: TS, p: TP, p: TO) -> MgResult<Self, bool>
where
TS: Term,
TP: Term,
TO: Term;
fn insert_triple<T>(&mut self, triple: T) -> MgResult<Self, bool>
where
T: Triple,
{
let [s, p, o] = triple.to_spo();
self.insert(s, p, o)
}
fn remove<TS, TP, TO>(&mut self, s: TS, p: TP, o: TO) -> MgResult<Self, bool>
where
TS: Term,
TP: Term,
TO: Term;
fn remove_triple<T>(&mut self, triple: T) -> MgResult<Self, bool>
where
T: Triple,
{
let [s, p, o] = triple.to_spo();
self.remove(s, p, o)
}
#[inline]
fn insert_all<TS: TripleSource>(
&mut self,
src: TS,
) -> StreamResult<usize, TS::Error, <Self as MutableGraph>::MutationError> {
let mut src = src;
let mut c = 0;
src.try_for_each_triple(|t| -> MgResult<Self, ()> {
if self.insert_triple(t.spo())? {
c += 1;
}
Ok(())
})
.and(Ok(c))
}
#[inline]
fn remove_all<TS: TripleSource>(
&mut self,
src: TS,
) -> StreamResult<usize, TS::Error, <Self as MutableGraph>::MutationError> {
let mut src = src;
let mut c = 0;
src.try_for_each_triple(|t| -> MgResult<Self, ()> {
if self.remove_triple(t.spo())? {
c += 1;
}
Ok(())
})
.and(Ok(c))
}
fn remove_matching<S, P, O>(
&mut self,
ms: S,
mp: P,
mo: O,
) -> Result<usize, Self::MutationError>
where
S: TermMatcher,
P: TermMatcher,
O: TermMatcher,
Self::MutationError: From<Self::Error>,
{
let to_remove: Result<Vec<[SimpleTerm; 3]>, _> = self
.triples_matching(ms, mp, mo)
.map_ok(|t| t.spo().map(Term::into_term))
.collect();
self.remove_all(to_remove?.into_iter().into_source())
.map_err(|err| err.unwrap_sink_error())
}
fn retain_matching<S, P, O>(&mut self, ms: S, mp: P, mo: O) -> Result<(), Self::MutationError>
where
S: TermMatcher,
P: TermMatcher,
O: TermMatcher,
Self::MutationError: From<Self::Error>,
{
let to_remove: Result<Vec<[SimpleTerm; 3]>, _> = self
.triples()
.filter_ok(|t| !t.matched_by(ms.matcher_ref(), mp.matcher_ref(), mo.matcher_ref()))
.map_ok(|t| t.spo().map(Term::into_term))
.collect();
self.remove_all(to_remove?.into_iter().into_source())
.map_err(|err| err.unwrap_sink_error())?;
Ok(())
}
}
pub trait SetGraph: Graph {}
#[cfg(test)]
mod check_implementability {
use super::*;
use crate::term::SimpleTerm;
#[derive(Clone, Debug, Eq, PartialEq)]
#[allow(dead_code)] enum MyInternalTerm {
Atom(SimpleTerm<'static>),
QuotedTriple(usize),
}
use MyInternalTerm::*;
#[derive(Clone, Debug, Eq, PartialEq)]
struct MyInternalTriple {
asserted: bool,
spo: [usize; 3],
}
#[derive(Clone, Debug)]
struct MyGraph {
terms: Vec<MyInternalTerm>,
triples: Vec<MyInternalTriple>,
}
impl MyGraph {
fn make_term(&self, i: usize) -> SimpleTerm<'_> {
match &self.terms[i] {
Atom(t) => t.as_simple(),
QuotedTriple(j) => {
SimpleTerm::Triple(Box::new(self.make_triple(self.triples[*j].spo)))
}
}
}
fn make_triple(&self, spo: [usize; 3]) -> [SimpleTerm<'_>; 3] {
spo.map(|j| self.make_term(j))
}
}
impl Graph for MyGraph {
type Triple<'x> = [SimpleTerm<'x>; 3] where Self: 'x;
type Error = std::convert::Infallible;
fn triples(&self) -> impl Iterator<Item = GResult<Self, Self::Triple<'_>>> + '_ {
self.triples
.iter()
.filter(|t| t.asserted)
.map(|t| Ok(self.make_triple(t.spo)))
}
}
}
#[cfg(test)]
mod check_implementability_lazy_term {
use super::*;
use crate::term::{SimpleTerm, TermKind};
#[derive(Clone, Debug, Eq, PartialEq)]
#[allow(dead_code)] enum MyInternalTerm {
Atom(SimpleTerm<'static>),
QuotedTriple(usize),
}
use MyInternalTerm::*;
#[derive(Clone, Debug, Eq, PartialEq)]
struct MyInternalTriple {
asserted: bool,
spo: [usize; 3],
}
#[derive(Clone, Debug)]
struct MyGraph {
terms: Vec<MyInternalTerm>,
triples: Vec<MyInternalTriple>,
}
#[derive(Clone, Copy, Debug)]
struct MyTerm<'a> {
graph: &'a MyGraph,
index: usize,
}
impl<'a> Term for MyTerm<'a> {
type BorrowTerm<'x> = MyTerm<'x> where Self: 'x;
fn kind(&self) -> crate::term::TermKind {
if let Atom(t) = &self.graph.terms[self.index] {
t.kind()
} else {
TermKind::Triple
}
}
fn iri(&self) -> Option<crate::term::IriRef<mownstr::MownStr>> {
if let Atom(t) = &self.graph.terms[self.index] {
t.iri()
} else {
None
}
}
fn bnode_id(&self) -> Option<crate::term::BnodeId<mownstr::MownStr>> {
if let Atom(t) = &self.graph.terms[self.index] {
t.bnode_id()
} else {
None
}
}
fn lexical_form(&self) -> Option<mownstr::MownStr> {
if let Atom(t) = &self.graph.terms[self.index] {
t.lexical_form()
} else {
None
}
}
fn datatype(&self) -> Option<crate::term::IriRef<mownstr::MownStr>> {
if let Atom(t) = &self.graph.terms[self.index] {
t.datatype()
} else {
None
}
}
fn language_tag(&self) -> Option<crate::term::LanguageTag<mownstr::MownStr>> {
if let Atom(t) = &self.graph.terms[self.index] {
t.language_tag()
} else {
None
}
}
fn variable(&self) -> Option<crate::term::VarName<mownstr::MownStr>> {
if let Atom(t) = &self.graph.terms[self.index] {
t.variable()
} else {
None
}
}
fn triple(&self) -> Option<[Self::BorrowTerm<'_>; 3]> {
self.to_triple()
}
fn to_triple(self) -> Option<[Self; 3]> {
if let QuotedTriple(i) = &self.graph.terms[self.index] {
Some(self.graph.triples[*i].spo.map(|t| MyTerm {
graph: self.graph,
index: t,
}))
} else {
None
}
}
fn borrow_term(&self) -> Self::BorrowTerm<'_> {
*self
}
}
impl Graph for MyGraph {
type Triple<'x> = [MyTerm<'x>; 3] where Self: 'x;
type Error = std::convert::Infallible;
fn triples(&self) -> impl Iterator<Item = GResult<Self, Self::Triple<'_>>> + '_ {
self.triples.iter().filter(|t| t.asserted).map(|t| {
Ok(t.spo.map(|i| MyTerm {
graph: self,
index: i,
}))
})
}
}
}