sophia_api/source/
filter_map.rs

1//! I define [`FilterMapTripleSource`] and [`FilterMapQuadSource`],
2//! the result type of [`TripleSource::filter_map_triples`] and [`QuadSource::filter_map_quads`] respectively.
3use super::*;
4use std::collections::VecDeque;
5
6mod _triple {
7    use super::*;
8    use triple::Triple;
9
10    /// The result of [`TripleSource::filter_map_triples`] and [`QuadSource::filter_map_quads`].
11    pub struct FilterMapTripleSource<S, F> {
12        pub(in super::super) source: S,
13        pub(in super::super) filter_map: F,
14    }
15
16    impl<S, F, T> TripleSource for FilterMapTripleSource<S, F>
17    where
18        S: TripleSource,
19        F: FnMut(S::Triple<'_>) -> Option<T>,
20        T: Triple,
21    {
22        type Triple<'x> = T;
23        type Error = S::Error;
24
25        fn try_for_some_triple<E, F2>(&mut self, mut f: F2) -> StreamResult<bool, Self::Error, E>
26        where
27            E: Error,
28            F2: FnMut(Self::Triple<'_>) -> Result<(), E>,
29        {
30            let filter_map = &mut self.filter_map;
31            self.source.try_for_some_triple(|t| match (filter_map)(t) {
32                None => Ok(()),
33                Some(out) => f(out),
34            })
35        }
36
37        fn size_hint_triples(&self) -> (usize, Option<usize>) {
38            (0, self.source.size_hint_triples().1)
39        }
40    }
41
42    impl<S, F, T> QuadSource for FilterMapTripleSource<S, F>
43    where
44        S: TripleSource,
45        F: FnMut(S::Triple<'_>) -> Option<T>,
46        T: crate::quad::Quad,
47    {
48        type Quad<'x> = T;
49        type Error = S::Error;
50
51        fn try_for_some_quad<E, F2>(&mut self, mut f: F2) -> StreamResult<bool, Self::Error, E>
52        where
53            E: Error,
54            F2: FnMut(Self::Quad<'_>) -> Result<(), E>,
55        {
56            let filter_map = &mut self.filter_map;
57            self.source.try_for_some_triple(|t| match (filter_map)(t) {
58                None => Ok(()),
59                Some(out) => f(out),
60            })
61        }
62
63        fn size_hint_quads(&self) -> (usize, Option<usize>) {
64            (0, self.source.size_hint_triples().1)
65        }
66    }
67
68    impl<S, F, T> IntoIterator for FilterMapTripleSource<S, F>
69    where
70        S: TripleSource,
71        F: FnMut(S::Triple<'_>) -> Option<T>,
72    {
73        type Item = Result<T, S::Error>;
74        type IntoIter = FilterMapTripleSourceIterator<S, F, T, S::Error>;
75
76        fn into_iter(self) -> Self::IntoIter {
77            FilterMapTripleSourceIterator {
78                source: self.source,
79                filter_map: self.filter_map,
80                buffer: VecDeque::new(),
81            }
82        }
83    }
84
85    /// [`Iterator`] implementation for [`FilterMapTripleSource`]
86    pub struct FilterMapTripleSourceIterator<S, F, T, E> {
87        source: S,
88        filter_map: F,
89        buffer: VecDeque<Result<T, E>>,
90    }
91
92    impl<S, F, T> Iterator for FilterMapTripleSourceIterator<S, F, T, S::Error>
93    where
94        S: TripleSource,
95        F: FnMut(S::Triple<'_>) -> Option<T>,
96    {
97        type Item = Result<T, S::Error>;
98        fn next(&mut self) -> Option<Result<T, S::Error>> {
99            let mut remaining = true;
100            let mut buffer = VecDeque::new();
101            std::mem::swap(&mut self.buffer, &mut buffer);
102            while buffer.is_empty() && remaining {
103                match self.source.for_some_triple(&mut |i| {
104                    if let Some(t) = (self.filter_map)(i) {
105                        buffer.push_back(Ok(t));
106                    }
107                }) {
108                    Ok(b) => {
109                        remaining = b;
110                    }
111                    Err(err) => {
112                        buffer.push_back(Err(err));
113                        remaining = false;
114                    }
115                }
116            }
117            std::mem::swap(&mut self.buffer, &mut buffer);
118            self.buffer.pop_front()
119        }
120
121        fn size_hint(&self) -> (usize, Option<usize>) {
122            self.source.size_hint_triples()
123        }
124    }
125}
126pub use _triple::*;
127
128/// Maintenance: any change in the _triple module above
129/// should be reflected in the _quad module below.
130///
131/// An easy way to do this is to replace _quad with the code of _triple,
132/// replacing all occurrences of `Triple` with `Quad`,
133/// and all occurrences of `triple` with `quad`.
134mod _quad {
135    use super::*;
136    use quad::Quad;
137
138    /// The result of [`QuadSource::filter_map_quads`] and [`QuadSource::filter_map_quads`].
139    pub struct FilterMapQuadSource<S, F> {
140        pub(in super::super) source: S,
141        pub(in super::super) filter_map: F,
142    }
143
144    impl<S, F, T> QuadSource for FilterMapQuadSource<S, F>
145    where
146        S: QuadSource,
147        F: FnMut(S::Quad<'_>) -> Option<T>,
148        T: Quad,
149    {
150        type Quad<'x> = T;
151        type Error = S::Error;
152
153        fn try_for_some_quad<E, F2>(&mut self, mut f: F2) -> StreamResult<bool, Self::Error, E>
154        where
155            E: Error,
156            F2: FnMut(Self::Quad<'_>) -> Result<(), E>,
157        {
158            let filter_map = &mut self.filter_map;
159            self.source.try_for_some_quad(|t| match (filter_map)(t) {
160                None => Ok(()),
161                Some(out) => f(out),
162            })
163        }
164
165        fn size_hint_quads(&self) -> (usize, Option<usize>) {
166            (0, self.source.size_hint_quads().1)
167        }
168    }
169
170    impl<S, F, T> TripleSource for FilterMapQuadSource<S, F>
171    where
172        S: QuadSource,
173        F: FnMut(S::Quad<'_>) -> Option<T>,
174        T: crate::triple::Triple,
175    {
176        type Triple<'x> = T;
177        type Error = S::Error;
178
179        fn try_for_some_triple<E, F2>(&mut self, mut f: F2) -> StreamResult<bool, Self::Error, E>
180        where
181            E: Error,
182            F2: FnMut(Self::Triple<'_>) -> Result<(), E>,
183        {
184            let filter_map = &mut self.filter_map;
185            self.source.try_for_some_quad(|t| match (filter_map)(t) {
186                None => Ok(()),
187                Some(out) => f(out),
188            })
189        }
190
191        fn size_hint_triples(&self) -> (usize, Option<usize>) {
192            (0, self.source.size_hint_quads().1)
193        }
194    }
195
196    impl<S, F, T> IntoIterator for FilterMapQuadSource<S, F>
197    where
198        S: QuadSource,
199        F: FnMut(S::Quad<'_>) -> Option<T>,
200    {
201        type Item = Result<T, S::Error>;
202        type IntoIter = FilterMapQuadSourceIterator<S, F, T, S::Error>;
203
204        fn into_iter(self) -> Self::IntoIter {
205            FilterMapQuadSourceIterator {
206                source: self.source,
207                filter_map: self.filter_map,
208                buffer: VecDeque::new(),
209            }
210        }
211    }
212
213    /// [`Iterator`] implementation for [`FilterMapQuadSource`]
214    pub struct FilterMapQuadSourceIterator<S, F, T, E> {
215        source: S,
216        filter_map: F,
217        buffer: VecDeque<Result<T, E>>,
218    }
219
220    impl<S, F, T> Iterator for FilterMapQuadSourceIterator<S, F, T, S::Error>
221    where
222        S: QuadSource,
223        F: FnMut(S::Quad<'_>) -> Option<T>,
224    {
225        type Item = Result<T, S::Error>;
226        fn next(&mut self) -> Option<Result<T, S::Error>> {
227            let mut remaining = true;
228            let mut buffer = VecDeque::new();
229            std::mem::swap(&mut self.buffer, &mut buffer);
230            while buffer.is_empty() && remaining {
231                match self.source.for_some_quad(&mut |i| {
232                    if let Some(t) = (self.filter_map)(i) {
233                        buffer.push_back(Ok(t));
234                    }
235                }) {
236                    Ok(b) => {
237                        remaining = b;
238                    }
239                    Err(err) => {
240                        buffer.push_back(Err(err));
241                        remaining = false;
242                    }
243                }
244            }
245            std::mem::swap(&mut self.buffer, &mut buffer);
246            self.buffer.pop_front()
247        }
248
249        fn size_hint(&self) -> (usize, Option<usize>) {
250            self.source.size_hint_quads()
251        }
252    }
253}
254pub use _quad::*;
255
256#[cfg(test)]
257mod test {
258    use super::*;
259    use crate::dataset::{Dataset, MutableDataset};
260    use crate::graph::{Graph, MutableGraph};
261    use crate::quad::{Quad, Spog};
262    use crate::term::ez_term;
263    use crate::term::{SimpleTerm, Term};
264    use crate::triple::Triple;
265
266    // check that the result of TripleSource::filter_map_triples implements the expected traits,
267    // and that they work as expected
268
269    #[test]
270    fn ts_filter_map_to_triples() {
271        let g = vec![
272            [ez_term(":a"), ez_term(":b"), ez_term(":c")],
273            [ez_term(":d"), ez_term(":e"), ez_term(":f")],
274            [ez_term(":g"), ez_term(":h"), ez_term(":i")],
275        ];
276        let mut h: Vec<[SimpleTerm; 3]> = vec![];
277        g.triples()
278            .filter_map_triples(|t| {
279                (!Term::eq(t.p(), ez_term(":e"))).then_some([t.o(), t.p(), t.s()])
280            })
281            .for_each_triple(|t| {
282                h.insert_triple(t).unwrap();
283            })
284            .unwrap();
285        assert_eq!(
286            h,
287            vec![
288                [ez_term(":c"), ez_term(":b"), ez_term(":a")],
289                [ez_term(":i"), ez_term(":h"), ez_term(":g")],
290            ]
291        )
292    }
293
294    #[test]
295    fn ts_filter_map_to_quads() {
296        let g = vec![
297            [ez_term(":a"), ez_term(":b"), ez_term(":c")],
298            [ez_term(":g"), ez_term(":h"), ez_term(":i")],
299        ];
300        let mut h: Vec<Spog<SimpleTerm>> = vec![];
301        g.triples()
302            .filter_map_triples(|t| {
303                (!Term::eq(t.p(), ez_term(":e"))).then_some(([t.o(), t.p(), t.s()], None))
304            })
305            .for_each_quad(|q| {
306                h.insert_quad(q).unwrap();
307            })
308            .unwrap();
309        assert_eq!(
310            h,
311            vec![
312                ([ez_term(":c"), ez_term(":b"), ez_term(":a")], None),
313                ([ez_term(":i"), ez_term(":h"), ez_term(":g")], None),
314            ]
315        )
316    }
317
318    #[test]
319    fn ts_filter_map_iter() {
320        let g = vec![
321            [ez_term(":a"), ez_term(":b"), ez_term(":c")],
322            [ez_term(":d"), ez_term(":e"), ez_term(":f")],
323            [ez_term(":g"), ez_term(":h"), ez_term(":i")],
324        ];
325        let h: Result<Vec<String>, _> = g
326            .triples()
327            .filter_map_triples(|t| {
328                (!Term::eq(t.p(), ez_term(":e"))).then_some(t.s().iri().unwrap().to_string())
329            })
330            .into_iter()
331            .collect();
332        assert_eq!(h.unwrap(), vec!["tag:a".to_string(), "tag:g".to_string(),])
333    }
334
335    // check that the result of QuadSource::filter_map_quads implements the expected traits
336    // and that they work as expected
337
338    #[test]
339    fn qs_filter_map_to_triples() {
340        let d = vec![
341            ([ez_term(":a"), ez_term(":b"), ez_term(":c")], None),
342            ([ez_term(":d"), ez_term(":e"), ez_term(":f")], None),
343            ([ez_term(":g"), ez_term(":h"), ez_term(":i")], None),
344        ];
345        let mut h: Vec<[SimpleTerm; 3]> = vec![];
346        d.quads()
347            .filter_map_quads(|q| {
348                (!Term::eq(q.p(), ez_term(":e"))).then_some([q.o(), q.p(), q.s()])
349            })
350            .for_each_triple(|t| {
351                h.insert_triple(t).unwrap();
352            })
353            .unwrap();
354        assert_eq!(
355            h,
356            vec![
357                [ez_term(":c"), ez_term(":b"), ez_term(":a")],
358                [ez_term(":i"), ez_term(":h"), ez_term(":g")],
359            ]
360        )
361    }
362
363    #[test]
364    fn qs_filter_map_to_quads() {
365        let d = vec![
366            ([ez_term(":a"), ez_term(":b"), ez_term(":c")], None),
367            ([ez_term(":d"), ez_term(":e"), ez_term(":f")], None),
368            ([ez_term(":g"), ez_term(":h"), ez_term(":i")], None),
369        ];
370        let mut h: Vec<Spog<SimpleTerm>> = vec![];
371        d.quads()
372            .filter_map_quads(|q| {
373                (!Term::eq(q.p(), ez_term(":e"))).then_some(([q.o(), q.p(), q.s()], q.g()))
374            })
375            .for_each_quad(|q| {
376                h.insert_quad(q).unwrap();
377            })
378            .unwrap();
379        assert_eq!(
380            h,
381            vec![
382                ([ez_term(":c"), ez_term(":b"), ez_term(":a")], None),
383                ([ez_term(":i"), ez_term(":h"), ez_term(":g")], None),
384            ]
385        )
386    }
387
388    #[test]
389    fn qs_filter_map_iter() {
390        let d = vec![
391            ([ez_term(":a"), ez_term(":b"), ez_term(":c")], None),
392            ([ez_term(":d"), ez_term(":e"), ez_term(":f")], None),
393            ([ez_term(":g"), ez_term(":h"), ez_term(":i")], None),
394        ];
395        let h: Result<Vec<String>, _> = d
396            .quads()
397            .filter_map_quads(|q| {
398                (!Term::eq(q.p(), ez_term(":e"))).then_some(q.s().iri().unwrap().to_string())
399            })
400            .into_iter()
401            .collect();
402        assert_eq!(h.unwrap(), vec!["tag:a".to_string(), "tag:g".to_string(),])
403    }
404}