sophia_api/graph.rs
1//! An RDF graph, the central notion of the RDF data model,
2//! is a collection of [triples](super::triple).
3//!
4//! This module provides [reusable abstractions](#traits)
5//! for different kinds of graph,
6//! as well as a few implementations for them.
7
8use std::error::Error;
9
10use crate::dataset::adapter::GraphAsDataset;
11use crate::source::{IntoSource, StreamResult, TripleSource};
12use crate::term::{matcher::TermMatcher, SimpleTerm, Term};
13use crate::triple::Triple;
14
15use resiter::{filter::*, flat_map::*, map::*};
16
17mod _foreign_impl;
18pub mod adapter;
19#[cfg(any(test, feature = "test_macro"))]
20#[macro_use]
21pub mod test;
22
23/// Type alias for results produced by a graph.
24pub type GResult<G, T> = Result<T, <G as Graph>::Error>;
25/// Type alias for fallible triple iterators produced by a graph.
26///
27/// See [`Graph::triples`] for more information about how to use it.
28#[deprecated(
29 since = "0.8.1",
30 note = "prototypes of `triples` and `triples_matching` have changed"
31)]
32pub type GTripleSource<'a, G> = Box<dyn Iterator<Item = GResult<G, <G as Graph>::Triple<'a>>> + 'a>;
33/// Type alias for terms produced by a graph.
34pub type GTerm<'a, G> = <<G as Graph>::Triple<'a> as Triple>::Term;
35/// Type alias for fallible term iterators produced by a graph.
36///
37/// See [`Graph::subjects`] for more information about how to use it.
38#[deprecated(
39 since = "0.8.1",
40 note = "prototypes of term-yielding methods have changed"
41)]
42pub type GTermSource<'a, G> = Box<dyn Iterator<Item = GResult<G, GTerm<'a, G>>> + 'a>;
43
44/// Generic trait for RDF graphs.
45///
46/// For convenience, this trait is implemented
47/// by [standard collections of triples](#foreign-impls).
48///
49/// NB: the semantics of this trait allows a graph to contain duplicate triples;
50/// see also [`SetGraph`].
51pub trait Graph {
52 /// Determine the type of [`Triple`]s
53 /// that the methods of this graph will yield.
54 type Triple<'x>: Triple
55 where
56 Self: 'x;
57 /// The error type that this graph may raise.
58 type Error: Error + Send + Sync + 'static;
59
60 /// An iterator visiting all triples of this graph in arbitrary order.
61 ///
62 /// This iterator is fallible:
63 /// its items are `Result`s,
64 /// an error may occur at any time during the iteration.
65 ///
66 /// # Examples
67 ///
68 /// The result of this method is an iterator,
69 /// so it can be used in a `for` loop:
70 /// ```
71 /// # fn test() -> Result<(), Box<dyn std::error::Error>> {
72 /// # use sophia_api::graph::Graph;
73 /// # use sophia_api::term::SimpleTerm;
74 /// # let graph = Vec::<[SimpleTerm;3]>::new();
75 /// #
76 /// for t in graph.triples() {
77 /// let t = t?; // rethrow error if any
78 /// // do something with t
79 /// }
80 /// #
81 /// # Ok(())
82 /// # }
83 /// ```
84 /// Another way is to use the specific methods provided by [`TripleSource`],
85 /// for example:
86 /// ```
87 /// # use sophia_api::graph::Graph;
88 /// # use sophia_api::term::SimpleTerm;
89 /// # use sophia_api::source::TripleSource;
90 /// # fn test() -> Result<(), Box<dyn std::error::Error>> {
91 /// # let graph = Vec::<[SimpleTerm;3]>::new();
92 /// #
93 /// graph.triples().for_each_triple(|t| {
94 /// // do something with t
95 /// })?; // rethrow error if any
96 /// #
97 /// # Ok(())
98 /// # }
99 /// ```
100 fn triples(&self) -> impl Iterator<Item = GResult<Self, Self::Triple<'_>>> + '_;
101
102 /// An iterator visiting all triples matching the given subject, predicate and object.
103 /// See [`crate::term::matcher`].
104 ///
105 /// See also [`triples`](Graph::triples).
106 ///
107 /// # Usage
108 ///
109 /// Typical implementations of [`TermMatcher`] include arrays/slices of [`Term`]s,
110 /// closure accepting a [`SimpleTerm`], or the special matcher [`Any`].
111 ///
112 /// [`Term`]: crate::term::Term
113 /// [`SimpleTerm`]: crate::term::SimpleTerm
114 /// [`Any`]: crate::term::matcher::Any
115 /// ```
116 /// # use sophia_api::prelude::*;
117 /// # use sophia_api::ns::{Namespace, rdf};
118 /// #
119 /// # fn test<G: Graph>(graph: &G) -> Result<(), Box<dyn std::error::Error>>
120 /// # where
121 /// # G: Graph,
122 /// # {
123 /// #
124 /// let s = Namespace::new("http://schema.org/")?;
125 /// let city = s.get("City")?;
126 /// let country = s.get("Country")?;
127 ///
128 /// for t in graph.triples_matching(Any, [&rdf::type_], [city, country]) {
129 /// println!("{:?} was found", t?.s());
130 /// }
131 /// #
132 /// # Ok(()) }
133 /// ```
134 ///
135 /// Here is another example using a closure as a [`TermMatcher`].
136 ///
137 /// ```
138 /// # use sophia_api::prelude::*;
139 /// # use sophia_api::ns::rdfs;
140 /// # use sophia_api::term::SimpleTerm;
141 /// #
142 /// # fn test<G>(graph: &G) -> Result<(), Box<dyn std::error::Error>>
143 /// # where
144 /// # G: Graph,
145 /// # {
146 /// #
147 /// for t in graph.triples_matching(
148 /// Any,
149 /// [&rdfs::label],
150 /// |t: SimpleTerm| t.lexical_form().map(|v| v.contains("needle")).unwrap_or(false),
151 /// ) {
152 /// println!("{:?} was found", t?.s());
153 /// }
154 /// #
155 /// # Ok(()) }
156 /// ```
157 fn triples_matching<'s, S, P, O>(
158 &'s self,
159 sm: S,
160 pm: P,
161 om: O,
162 ) -> impl Iterator<Item = GResult<Self, Self::Triple<'s>>> + 's
163 where
164 S: TermMatcher + 's,
165 P: TermMatcher + 's,
166 O: TermMatcher + 's,
167 {
168 self.triples()
169 .filter_ok(move |t| t.matched_by(sm.matcher_ref(), pm.matcher_ref(), om.matcher_ref()))
170 }
171
172 /// Return `true` if this graph contains the given triple.
173 fn contains<TS, TP, TO>(&self, s: TS, p: TP, o: TO) -> GResult<Self, bool>
174 where
175 TS: Term,
176 TP: Term,
177 TO: Term,
178 {
179 self.triples_matching([s], [p], [o])
180 .next()
181 .transpose()
182 .map(|o| o.is_some())
183 }
184
185 /// Build a fallible iterator of all the terms used as subject in this Graph.
186 ///
187 /// NB: implementations SHOULD avoid yielding the same term multiple times, but MAY do so.
188 /// Users MUST therefore be prepared to deal with duplicates.
189 fn subjects(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
190 self.triples().map_ok(Triple::to_s)
191 }
192
193 /// Build a fallible iterator of all the terms used as predicate in this Graph.
194 ///
195 /// NB: implementations SHOULD avoid yielding the same term multiple times, but MAY do so.
196 /// Users MUST therefore be prepared to deal with duplicates.
197 fn predicates(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
198 self.triples().map_ok(Triple::to_p)
199 }
200
201 /// Build a fallible iterator of all the terms used as object in this Graph.
202 ///
203 /// NB: implementations SHOULD avoid yielding the same term multiple times, but MAY do so.
204 /// Users MUST therefore be prepared to deal with duplicates.
205 fn objects(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
206 self.triples().map_ok(Triple::to_o)
207 }
208
209 /// Build a fallible iterator of all the IRIs used in this Graph
210 /// (including those used inside quoted triples, if any).
211 ///
212 /// NB: implementations SHOULD avoid yielding the same term multiple times, but MAY do so.
213 /// Users MUST therefore be prepared to deal with duplicates.
214 fn iris(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
215 self.triples()
216 .flat_map_ok(Triple::to_spo)
217 .flat_map_ok(Term::to_atoms)
218 .filter_ok(Term::is_iri)
219 }
220
221 /// Build a fallible iterator of all the blank nodes used in this Graph
222 /// (including those used inside quoted triples, if any).
223 ///
224 /// NB: implementations SHOULD avoid yielding the same term multiple times, but MAY do so.
225 /// Users MUST therefore be prepared to deal with duplicates.
226 fn blank_nodes(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
227 self.triples()
228 .flat_map_ok(Triple::to_spo)
229 .flat_map_ok(Term::to_atoms)
230 .filter_ok(Term::is_blank_node)
231 }
232
233 /// Build a fallible iterator of all the literals used in this Graph
234 /// (including those used inside quoted triples, if any).
235 ///
236 /// NB: implementations SHOULD avoid yielding the same term multiple times, but MAY do so.
237 /// Users MUST therefore be prepared to deal with duplicates.
238 fn literals(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
239 self.triples()
240 .flat_map_ok(Triple::to_spo)
241 .flat_map_ok(Term::to_atoms)
242 .filter_ok(Term::is_literal)
243 }
244
245 /// Build a fallible iterator of all the quoted triples used in this Graph
246 /// (including those used inside quoted triples, if any).
247 ///
248 /// NB: implementations SHOULD avoid yielding the same term multiple times, but MAY do so.
249 /// Users MUST therefore be prepared to deal with duplicates.
250 fn quoted_triples<'s>(&'s self) -> Box<dyn Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_>
251 where
252 GTerm<'s, Self>: Clone,
253 {
254 Box::new(
255 self.triples()
256 .flat_map_ok(Triple::to_spo)
257 .flat_map_ok(Term::to_constituents)
258 .filter_ok(Term::is_triple),
259 )
260 }
261
262 /// Build a fallible iterator of all the variables used in this Graph
263 /// (including those used inside quoted triples, if any).
264 ///
265 /// NB: implementations SHOULD avoid yielding the same term multiple times, but MAY do so.
266 /// Users MUST therefore be prepared to deal with duplicates.
267 fn variables(&self) -> impl Iterator<Item = GResult<Self, GTerm<'_, Self>>> + '_ {
268 self.triples()
269 .flat_map_ok(Triple::to_spo)
270 .flat_map_ok(Term::to_atoms)
271 .filter_ok(Term::is_variable)
272 }
273
274 /// [`Dataset`](crate::dataset::Dataset) adapter borrowing this graph
275 fn as_dataset(&self) -> GraphAsDataset<&Self> {
276 GraphAsDataset::new(self)
277 }
278
279 /// [`Dataset`](crate::dataset::Dataset) adapter borrowing this graph mutably
280 fn as_dataset_mut(&mut self) -> GraphAsDataset<&mut Self> {
281 GraphAsDataset::new(self)
282 }
283
284 /// [`Dataset`](crate::dataset::Dataset) adapter taking ownership of this graph
285 fn into_dataset(self) -> GraphAsDataset<Self>
286 where
287 Self: Sized,
288 {
289 GraphAsDataset::new(self)
290 }
291}
292
293/// A [`Graph`] that can be constructed from a [`TripleSource`]
294pub trait CollectibleGraph: Graph + Sized {
295 /// Construct a graph from the given source
296 fn from_triple_source<TS: TripleSource>(
297 triples: TS,
298 ) -> StreamResult<Self, TS::Error, Self::Error>;
299}
300
301/// Type alias for results produced by a mutable graph.
302pub type MgResult<G, T> = std::result::Result<T, <G as MutableGraph>::MutationError>;
303
304/// Generic trait for mutable RDF graphs.
305///
306/// NB: the semantics of this trait allows a graph to contain duplicate triples;
307/// see also [`SetGraph`].
308pub trait MutableGraph: Graph {
309 /// The error type that this graph may raise during mutations.
310 type MutationError: Error + Send + Sync + 'static;
311
312 /// Insert in this graph a triple made of the the given terms.
313 ///
314 /// # Return value
315 /// The `bool` value returned in case of success is
316 /// **not significant unless** this graph also implements [`SetGraph`].
317 ///
318 /// If it does,
319 /// `true` is returned iff the insertion actually changed the graph.
320 /// In other words,
321 /// a return value of `false` means that the graph was not changed,
322 /// because the triple was already present in this [`SetGraph`].
323 ///
324 /// See also [`insert_triple`](MutableGraph::insert_triple)
325 ///
326 /// # Usage
327 /// ```
328 /// # use sophia_api::graph::{MutableGraph, MgResult};
329 /// # use sophia_api::ns::{Namespace, rdf, rdfs, xsd};
330 /// # fn populate<G: MutableGraph>(graph: &mut G) -> MgResult<G, ()> {
331 /// #
332 /// let schema = Namespace::new("http://schema.org/").unwrap();
333 /// let s_name = schema.get("name").unwrap();
334 ///
335 /// graph.insert(&s_name, &rdf::type_, &rdf::Property)?;
336 /// graph.insert(&s_name, &rdfs::range, &xsd::string)?;
337 /// graph.insert(&s_name, &rdfs::comment, "The name of the item.")?;
338 /// #
339 /// # Ok(())
340 /// # }
341 /// ```
342 fn insert<TS, TP, TO>(&mut self, s: TS, p: TP, p: TO) -> MgResult<Self, bool>
343 where
344 TS: Term,
345 TP: Term,
346 TO: Term;
347
348 /// Insert in this graph the given triple.
349 ///
350 /// NB: if you want to insert a triple `t` while keeping its ownership,
351 /// you can still pass [`t.spo()`](Triple::spo).
352 ///
353 /// See also [`MutableGraph::insert`]
354 fn insert_triple<T>(&mut self, triple: T) -> MgResult<Self, bool>
355 where
356 T: Triple,
357 {
358 let [s, p, o] = triple.to_spo();
359 self.insert(s, p, o)
360 }
361
362 /// Remove from this graph the triple made of the the given terms.
363 ///
364 /// # Return value
365 /// The `bool` value returned in case of success is
366 /// **not significant unless** this graph also implements [`SetGraph`].
367 ///
368 /// If it does,
369 /// `true` is returned iff the removal actually changed the graph.
370 /// In other words,
371 /// a return value of `false` means that the graph was not changed,
372 /// because the triple was already absent from this [`SetGraph`].
373 fn remove<TS, TP, TO>(&mut self, s: TS, p: TP, o: TO) -> MgResult<Self, bool>
374 where
375 TS: Term,
376 TP: Term,
377 TO: Term;
378
379 /// Remoe from this graph the given triple.
380 ///
381 /// NB: if you want to remove a triple `t` while keeping its ownership,
382 /// you can still pass [`t.spo()`](Triple::spo).
383 ///
384 /// See also [MutableGraph::remove]
385 fn remove_triple<T>(&mut self, triple: T) -> MgResult<Self, bool>
386 where
387 T: Triple,
388 {
389 let [s, p, o] = triple.to_spo();
390 self.remove(s, p, o)
391 }
392
393 /// Insert into this graph all triples from the given source.
394 ///
395 /// # Blank node scope
396 /// The blank nodes contained in the triple source will be inserted as is.
397 /// If they happen to have the same identifier as blank nodes already present,
398 /// they will be considered equal.
399 /// This might *not* be what you want,
400 /// especially if the graph contains data from a file,
401 /// and you are inserting data from a different file.
402 /// In that case, you should first transform the triple source,
403 /// in order to get fresh blank node identifiers.
404 ///
405 /// # Return value
406 /// The `usize` value returned in case of success is
407 /// **not significant unless** this graph also implements [`SetGraph`].
408 ///
409 /// If it does,
410 /// the number of triples that were *actually* inserted
411 /// (i.e. that were not already present in this [`SetGraph`])
412 /// is returned.
413 #[inline]
414 fn insert_all<TS: TripleSource>(
415 &mut self,
416 src: TS,
417 ) -> StreamResult<usize, TS::Error, <Self as MutableGraph>::MutationError> {
418 let mut src = src;
419 let mut c = 0;
420 src.try_for_each_triple(|t| -> MgResult<Self, ()> {
421 if self.insert_triple(t.spo())? {
422 c += 1;
423 }
424 Ok(())
425 })
426 .and(Ok(c))
427 }
428
429 /// Remove from this graph all triples from the given source.
430 ///
431 /// # Return value
432 /// The `usize` value returned in case of success is
433 /// **not significant unless** this graph also implements [`SetGraph`].
434 ///
435 /// If it does,
436 /// the number of triples that were *actually* removed
437 /// (i.e. that were not already absent from this [`SetGraph`])
438 /// is returned.
439 #[inline]
440 fn remove_all<TS: TripleSource>(
441 &mut self,
442 src: TS,
443 ) -> StreamResult<usize, TS::Error, <Self as MutableGraph>::MutationError> {
444 let mut src = src;
445 let mut c = 0;
446 src.try_for_each_triple(|t| -> MgResult<Self, ()> {
447 if self.remove_triple(t.spo())? {
448 c += 1;
449 }
450 Ok(())
451 })
452 .and(Ok(c))
453 }
454
455 /// Remove all triples matching the given matchers.
456 ///
457 /// # Return value
458 /// The `usize` value returned in case of success is
459 /// **not significant unless** this graph also implements [`SetGraph`].
460 ///
461 /// If it does,
462 /// the number of triples that were *actually* removed
463 /// (i.e. that were not already absent from this [`SetGraph`])
464 /// is returned.
465 ///
466 /// # Note to implementors
467 /// The default implementation is rather naive,
468 /// and could be improved in specific implementations of the trait.
469 fn remove_matching<S, P, O>(
470 &mut self,
471 ms: S,
472 mp: P,
473 mo: O,
474 ) -> Result<usize, Self::MutationError>
475 where
476 S: TermMatcher,
477 P: TermMatcher,
478 O: TermMatcher,
479 Self::MutationError: From<Self::Error>,
480 {
481 let to_remove: Result<Vec<[SimpleTerm; 3]>, _> = self
482 .triples_matching(ms, mp, mo)
483 .map_ok(|t| t.spo().map(Term::into_term))
484 .collect();
485 self.remove_all(to_remove?.into_iter().into_source())
486 .map_err(|err| err.unwrap_sink_error())
487 }
488
489 /// Keep only the triples matching the given matchers.
490 ///
491 /// # Note to implementors
492 /// The default implementation is rather naive,
493 /// and could be improved in specific implementations of the trait.
494 fn retain_matching<S, P, O>(&mut self, ms: S, mp: P, mo: O) -> Result<(), Self::MutationError>
495 where
496 S: TermMatcher,
497 P: TermMatcher,
498 O: TermMatcher,
499 Self::MutationError: From<Self::Error>,
500 {
501 let to_remove: Result<Vec<[SimpleTerm; 3]>, _> = self
502 .triples()
503 .filter_ok(|t| !t.matched_by(ms.matcher_ref(), mp.matcher_ref(), mo.matcher_ref()))
504 .map_ok(|t| t.spo().map(Term::into_term))
505 .collect();
506 self.remove_all(to_remove?.into_iter().into_source())
507 .map_err(|err| err.unwrap_sink_error())?;
508 Ok(())
509 }
510}
511
512/// Marker trait constraining the semantics of
513/// [`Graph`] and [`MutableGraph`].
514///
515/// It guarantees that
516/// (1) triples will never be returned / stored multiple times.
517///
518/// If the type also implements [`MutableGraph`],
519/// it must also ensure that
520/// (2) the `bool` or `usize` values returned by [`MutableGraph`]
521/// methods accurately describe how many triples were actually added/removed.
522///
523/// # Note to implementors
524/// A type implementing both [`Graph`] and [`MutableGraph`],
525/// enforcing (1) but failing to enforce (2)
526/// *must not* implement this trait.
527pub trait SetGraph: Graph {}
528
529#[cfg(test)]
530mod check_implementability {
531 /// This is a naive implementation of an RDF-star graph,
532 /// where the graph maintains
533 /// - a list of terms (either atoms or index of triple)
534 /// - a list of triples (SPO indexes, plus an 'asserted' flag)
535 ///
536 /// This avoids the need to store arbitrarily nested triples.
537 use super::*;
538 use crate::term::SimpleTerm;
539
540 #[derive(Clone, Debug, Eq, PartialEq)]
541 #[allow(dead_code)] // testing implementability
542 enum MyInternalTerm {
543 Atom(SimpleTerm<'static>),
544 QuotedTriple(usize),
545 }
546 use MyInternalTerm::*;
547
548 #[derive(Clone, Debug, Eq, PartialEq)]
549 struct MyInternalTriple {
550 asserted: bool,
551 spo: [usize; 3],
552 }
553
554 #[derive(Clone, Debug)]
555 struct MyGraph {
556 terms: Vec<MyInternalTerm>,
557 triples: Vec<MyInternalTriple>,
558 }
559
560 impl MyGraph {
561 fn make_term(&self, i: usize) -> SimpleTerm<'_> {
562 match &self.terms[i] {
563 Atom(t) => t.as_simple(),
564 QuotedTriple(j) => {
565 SimpleTerm::Triple(Box::new(self.make_triple(self.triples[*j].spo)))
566 }
567 }
568 }
569
570 fn make_triple(&self, spo: [usize; 3]) -> [SimpleTerm<'_>; 3] {
571 spo.map(|j| self.make_term(j))
572 }
573 }
574
575 impl Graph for MyGraph {
576 type Triple<'x> = [SimpleTerm<'x>; 3] where Self: 'x;
577 type Error = std::convert::Infallible;
578
579 fn triples(&self) -> impl Iterator<Item = GResult<Self, Self::Triple<'_>>> + '_ {
580 self.triples
581 .iter()
582 .filter(|t| t.asserted)
583 .map(|t| Ok(self.make_triple(t.spo)))
584 }
585 }
586}
587
588#[cfg(test)]
589mod check_implementability_lazy_term {
590 /// This implementation is internally similar to the one above,
591 /// but using dedicated lazy implementations of Term
592 /// (lazy because it avoids allocating nested triples until forced)
593 use super::*;
594 use crate::term::{SimpleTerm, TermKind};
595
596 #[derive(Clone, Debug, Eq, PartialEq)]
597 #[allow(dead_code)] // testing implementability
598 enum MyInternalTerm {
599 Atom(SimpleTerm<'static>),
600 QuotedTriple(usize),
601 }
602 use MyInternalTerm::*;
603
604 #[derive(Clone, Debug, Eq, PartialEq)]
605 struct MyInternalTriple {
606 asserted: bool,
607 spo: [usize; 3],
608 }
609
610 #[derive(Clone, Debug)]
611 struct MyGraph {
612 terms: Vec<MyInternalTerm>,
613 triples: Vec<MyInternalTriple>,
614 }
615
616 #[derive(Clone, Copy, Debug)]
617 struct MyTerm<'a> {
618 graph: &'a MyGraph,
619 index: usize,
620 }
621
622 impl<'a> Term for MyTerm<'a> {
623 type BorrowTerm<'x> = MyTerm<'x> where Self: 'x;
624
625 fn kind(&self) -> crate::term::TermKind {
626 if let Atom(t) = &self.graph.terms[self.index] {
627 t.kind()
628 } else {
629 TermKind::Triple
630 }
631 }
632
633 fn iri(&self) -> Option<crate::term::IriRef<mownstr::MownStr>> {
634 if let Atom(t) = &self.graph.terms[self.index] {
635 t.iri()
636 } else {
637 None
638 }
639 }
640
641 fn bnode_id(&self) -> Option<crate::term::BnodeId<mownstr::MownStr>> {
642 if let Atom(t) = &self.graph.terms[self.index] {
643 t.bnode_id()
644 } else {
645 None
646 }
647 }
648
649 fn lexical_form(&self) -> Option<mownstr::MownStr> {
650 if let Atom(t) = &self.graph.terms[self.index] {
651 t.lexical_form()
652 } else {
653 None
654 }
655 }
656
657 fn datatype(&self) -> Option<crate::term::IriRef<mownstr::MownStr>> {
658 if let Atom(t) = &self.graph.terms[self.index] {
659 t.datatype()
660 } else {
661 None
662 }
663 }
664
665 fn language_tag(&self) -> Option<crate::term::LanguageTag<mownstr::MownStr>> {
666 if let Atom(t) = &self.graph.terms[self.index] {
667 t.language_tag()
668 } else {
669 None
670 }
671 }
672
673 fn variable(&self) -> Option<crate::term::VarName<mownstr::MownStr>> {
674 if let Atom(t) = &self.graph.terms[self.index] {
675 t.variable()
676 } else {
677 None
678 }
679 }
680
681 fn triple(&self) -> Option<[Self::BorrowTerm<'_>; 3]> {
682 self.to_triple()
683 }
684
685 fn to_triple(self) -> Option<[Self; 3]> {
686 if let QuotedTriple(i) = &self.graph.terms[self.index] {
687 Some(self.graph.triples[*i].spo.map(|t| MyTerm {
688 graph: self.graph,
689 index: t,
690 }))
691 } else {
692 None
693 }
694 }
695
696 fn borrow_term(&self) -> Self::BorrowTerm<'_> {
697 *self
698 }
699 }
700
701 impl Graph for MyGraph {
702 type Triple<'x> = [MyTerm<'x>; 3] where Self: 'x;
703
704 type Error = std::convert::Infallible;
705
706 fn triples(&self) -> impl Iterator<Item = GResult<Self, Self::Triple<'_>>> + '_ {
707 self.triples.iter().filter(|t| t.asserted).map(|t| {
708 Ok(t.spo.map(|i| MyTerm {
709 graph: self,
710 index: i,
711 }))
712 })
713 }
714 }
715}