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}