sophia_api/source/
filter.rs

1//! I define [`FilterTripleSource`] and [`FilterQuadSource`],
2//! the result type of [`TripleSource::filter_triples`] and [`QuadSource::filter_quads`] respectively.
3use super::*;
4
5mod _triple {
6    use super::*;
7
8    /// The result type of [`TripleSource::filter_triples`].
9    pub struct FilterTripleSource<S, P> {
10        pub(in super::super) source: S,
11        pub(in super::super) predicate: P,
12    }
13
14    impl<S, P> TripleSource for FilterTripleSource<S, P>
15    where
16        S: TripleSource,
17        P: FnMut(&S::Triple<'_>) -> bool,
18    {
19        type Triple<'x> = S::Triple<'x>;
20        type Error = S::Error;
21
22        fn try_for_some_triple<E, F>(&mut self, mut f: F) -> StreamResult<bool, Self::Error, E>
23        where
24            E: Error,
25            F: FnMut(Self::Triple<'_>) -> Result<(), E>,
26        {
27            let p = &mut self.predicate;
28            self.source.try_for_some_triple(|t| {
29                if p(&t) {
30                    f(t)?;
31                }
32                Ok(())
33            })
34        }
35
36        fn size_hint_triples(&self) -> (usize, Option<usize>) {
37            (0, self.source.size_hint_triples().1)
38        }
39    }
40}
41pub use _triple::*;
42
43/// Maintenance: any change in the _triple module above
44/// should be reflected in the _quad module below.
45///
46/// An easy way to do this is to replace _quad with the code of _triple,
47/// replacing all occurrences of `Triple` with `Quad`,
48/// and all occurrences of `triple` with `quad`.
49mod _quad {
50    use super::*;
51    /// The result type of [`QuadSource::filter_quads`].
52    pub struct FilterQuadSource<S, P> {
53        pub(in super::super) source: S,
54        pub(in super::super) predicate: P,
55    }
56
57    impl<S, P> QuadSource for FilterQuadSource<S, P>
58    where
59        S: QuadSource,
60        P: FnMut(&S::Quad<'_>) -> bool,
61    {
62        type Quad<'x> = S::Quad<'x>;
63        type Error = S::Error;
64
65        fn try_for_some_quad<E, F>(&mut self, mut f: F) -> StreamResult<bool, Self::Error, E>
66        where
67            E: Error,
68            F: FnMut(Self::Quad<'_>) -> Result<(), E>,
69        {
70            let p = &mut self.predicate;
71            self.source.try_for_some_quad(|t| {
72                if p(&t) {
73                    f(t)?;
74                }
75                Ok(())
76            })
77        }
78
79        fn size_hint_quads(&self) -> (usize, Option<usize>) {
80            (0, self.source.size_hint_quads().1)
81        }
82    }
83}
84pub use _quad::*;
85
86#[cfg(test)]
87mod test {
88    use super::*;
89    use crate::dataset::{Dataset, MutableDataset};
90    use crate::graph::{Graph, MutableGraph};
91    use crate::quad::{Quad, Spog};
92    use crate::term::ez_term;
93    use crate::term::{SimpleTerm, Term};
94    use crate::triple::Triple;
95
96    #[test]
97    fn ts_filter_to_triples() {
98        let g = vec![
99            [ez_term(":a"), ez_term(":b"), ez_term(":c")],
100            [ez_term(":d"), ez_term(":e"), ez_term(":f")],
101            [ez_term(":g"), ez_term(":h"), ez_term(":i")],
102        ];
103        let mut h: Vec<[SimpleTerm; 3]> = vec![];
104        g.triples()
105            .filter_triples(|t| !Term::eq(t.p(), &ez_term(":e")))
106            .for_each_triple(|t| {
107                h.insert_triple(t).unwrap();
108            })
109            .unwrap();
110        assert_eq!(
111            h,
112            vec![
113                [ez_term(":a"), ez_term(":b"), ez_term(":c")],
114                [ez_term(":g"), ez_term(":h"), ez_term(":i")],
115            ]
116        )
117    }
118
119    #[test]
120    fn qs_filter_to_triples() {
121        let d = vec![
122            ([ez_term(":a"), ez_term(":b"), ez_term(":c")], None),
123            ([ez_term(":d"), ez_term(":e"), ez_term(":f")], None),
124            ([ez_term(":g"), ez_term(":h"), ez_term(":i")], None),
125        ];
126        let mut h: Vec<Spog<SimpleTerm>> = vec![];
127        d.quads()
128            .filter_quads(|q| !Term::eq(q.p(), &ez_term(":e")))
129            .for_each_quad(|q| {
130                h.insert_quad(q).unwrap();
131            })
132            .unwrap();
133        assert_eq!(
134            h,
135            vec![
136                ([ez_term(":a"), ez_term(":b"), ez_term(":c")], None),
137                ([ez_term(":g"), ez_term(":h"), ez_term(":i")], None),
138            ]
139        )
140    }
141}