sophia_api/source/
map.rs

1//! I define [`MapSource`], the result type of [`Source::map_items`].
2use super::*;
3use std::{collections::VecDeque, error::Error};
4
5/// The result of [`Source::map_items`].
6pub struct MapSource<S, F> {
7    pub(super) source: S,
8    pub(super) map: F,
9}
10
11impl<S, F, T> Source for MapSource<S, F>
12where
13    S: Source,
14    F: FnMut(S::Item<'_>) -> T,
15{
16    type Item<'x> = T;
17    type Error = S::Error;
18
19    fn try_for_some_item<E, F2>(&mut self, mut f: F2) -> StreamResult<bool, Self::Error, E>
20    where
21        E: Error + Send + Sync + 'static,
22        F2: FnMut(Self::Item<'_>) -> Result<(), E>,
23    {
24        let map = &mut self.map;
25        self.source.try_for_some_item(|t| f((map)(t)))
26    }
27
28    fn size_hint_items(&self) -> (usize, Option<usize>) {
29        self.source.size_hint_items()
30    }
31}
32
33impl<S, F, T> IntoIterator for MapSource<S, F>
34where
35    S: Source,
36    F: FnMut(S::Item<'_>) -> T,
37{
38    type Item = Result<T, S::Error>;
39    type IntoIter = MapSourceIterator<S, F, T, S::Error>;
40
41    fn into_iter(self) -> Self::IntoIter {
42        MapSourceIterator {
43            source: self.source,
44            map: self.map,
45            buffer: VecDeque::new(),
46        }
47    }
48}
49
50/// [`Iterator`] implementation for the returned value of [`Source::map_items`].
51pub struct MapSourceIterator<S, F, T, E> {
52    source: S,
53    map: F,
54    buffer: VecDeque<Result<T, E>>,
55}
56
57impl<S, F, T> Iterator for MapSourceIterator<S, F, T, S::Error>
58where
59    S: Source,
60    F: FnMut(S::Item<'_>) -> T,
61{
62    type Item = Result<T, S::Error>;
63    fn next(&mut self) -> Option<Result<T, S::Error>> {
64        let mut remaining = true;
65        let mut buffer = VecDeque::new();
66        std::mem::swap(&mut self.buffer, &mut buffer);
67        while buffer.is_empty() && remaining {
68            let resb = self.source.for_some_item(|i| {
69                buffer.push_back(Ok((self.map)(i)));
70            });
71            match resb {
72                Ok(b) => {
73                    remaining = b;
74                }
75                Err(err) => {
76                    buffer.push_back(Err(err));
77                    remaining = false;
78                }
79            }
80        }
81        std::mem::swap(&mut self.buffer, &mut buffer);
82        self.buffer.pop_front()
83    }
84
85    fn size_hint(&self) -> (usize, Option<usize>) {
86        self.source.size_hint_items()
87    }
88}
89
90#[cfg(test)]
91mod test {
92    use super::*;
93    use crate::dataset::{Dataset, MutableDataset};
94    use crate::graph::{Graph, MutableGraph};
95    use crate::quad::{Quad, Spog};
96    use crate::term::ez_term;
97    use crate::term::{SimpleTerm, Term};
98    use crate::triple::Triple;
99
100    // check that the result of TripleSource::map_triples implements the expected traits,
101    // and that they work as expected
102
103    #[test]
104    fn ts_map_to_triples() {
105        let g = vec![
106            [ez_term(":a"), ez_term(":b"), ez_term(":c")],
107            [ez_term(":d"), ez_term(":e"), ez_term(":f")],
108            [ez_term(":g"), ez_term(":h"), ez_term(":i")],
109        ];
110        let mut h: Vec<[SimpleTerm; 3]> = vec![];
111        g.triples()
112            .map_triples(|t| [t.o(), t.p(), t.s()])
113            .for_each_triple(|t| {
114                h.insert_triple(t).unwrap();
115            })
116            .unwrap();
117        assert_eq!(
118            h,
119            vec![
120                [ez_term(":c"), ez_term(":b"), ez_term(":a")],
121                [ez_term(":f"), ez_term(":e"), ez_term(":d")],
122                [ez_term(":i"), ez_term(":h"), ez_term(":g")],
123            ]
124        )
125    }
126
127    #[test]
128    fn ts_map_to_quads() {
129        let g = vec![
130            [ez_term(":a"), ez_term(":b"), ez_term(":c")],
131            [ez_term(":d"), ez_term(":e"), ez_term(":f")],
132            [ez_term(":g"), ez_term(":h"), ez_term(":i")],
133        ];
134        let mut h: Vec<Spog<SimpleTerm>> = vec![];
135        g.triples()
136            .map_triples(|t| ([t.o(), t.p(), t.s()], None))
137            .for_each_quad(|q| {
138                h.insert_quad(q).unwrap();
139            })
140            .unwrap();
141        assert_eq!(
142            h,
143            vec![
144                ([ez_term(":c"), ez_term(":b"), ez_term(":a")], None),
145                ([ez_term(":f"), ez_term(":e"), ez_term(":d")], None),
146                ([ez_term(":i"), ez_term(":h"), ez_term(":g")], None),
147            ]
148        )
149    }
150
151    #[test]
152    fn ts_map_iter() {
153        let g = vec![
154            [ez_term(":a"), ez_term(":b"), ez_term(":c")],
155            [ez_term(":d"), ez_term(":e"), ez_term(":f")],
156            [ez_term(":g"), ez_term(":h"), ez_term(":i")],
157        ];
158        let h: Result<Vec<String>, _> = g
159            .triples()
160            .map_triples(|t| t.s().iri().unwrap().to_string())
161            .into_iter()
162            .collect();
163        assert_eq!(
164            h.unwrap(),
165            vec![
166                "tag:a".to_string(),
167                "tag:d".to_string(),
168                "tag:g".to_string(),
169            ]
170        )
171    }
172
173    // check that the result of QuadSource::map_quads implements the expected traits
174    // and that they work as expected
175
176    #[test]
177    fn qs_map_to_triples() {
178        let d = vec![
179            ([ez_term(":a"), ez_term(":b"), ez_term(":c")], None),
180            ([ez_term(":d"), ez_term(":e"), ez_term(":f")], None),
181            ([ez_term(":g"), ez_term(":h"), ez_term(":i")], None),
182        ];
183        let mut h: Vec<[SimpleTerm; 3]> = vec![];
184        d.quads()
185            .map_quads(|q| [q.o(), q.p(), q.s()])
186            .for_each_triple(|t| {
187                h.insert_triple(t).unwrap();
188            })
189            .unwrap();
190        assert_eq!(
191            h,
192            vec![
193                [ez_term(":c"), ez_term(":b"), ez_term(":a")],
194                [ez_term(":f"), ez_term(":e"), ez_term(":d")],
195                [ez_term(":i"), ez_term(":h"), ez_term(":g")],
196            ]
197        )
198    }
199
200    #[test]
201    fn qs_map_to_quads() {
202        let d = vec![
203            ([ez_term(":a"), ez_term(":b"), ez_term(":c")], None),
204            ([ez_term(":d"), ez_term(":e"), ez_term(":f")], None),
205            ([ez_term(":g"), ez_term(":h"), ez_term(":i")], None),
206        ];
207        let mut h: Vec<Spog<SimpleTerm>> = vec![];
208        d.quads()
209            .map_quads(|q| ([q.o(), q.p(), q.s()], q.g()))
210            .for_each_quad(|q| {
211                h.insert_quad(q).unwrap();
212            })
213            .unwrap();
214        assert_eq!(
215            h,
216            vec![
217                ([ez_term(":c"), ez_term(":b"), ez_term(":a")], None),
218                ([ez_term(":f"), ez_term(":e"), ez_term(":d")], None),
219                ([ez_term(":i"), ez_term(":h"), ez_term(":g")], None),
220            ]
221        )
222    }
223
224    #[test]
225    fn qs_map_iter() {
226        let d = vec![
227            ([ez_term(":a"), ez_term(":b"), ez_term(":c")], None),
228            ([ez_term(":d"), ez_term(":e"), ez_term(":f")], None),
229            ([ez_term(":g"), ez_term(":h"), ez_term(":i")], None),
230        ];
231        let h: Result<Vec<String>, _> = d
232            .quads()
233            .map_quads(|q| q.s().iri().unwrap().to_string())
234            .into_iter()
235            .collect();
236        assert_eq!(
237            h.unwrap(),
238            vec![
239                "tag:a".to_string(),
240                "tag:d".to_string(),
241                "tag:g".to_string(),
242            ]
243        )
244    }
245}