source/
lib.rs

1use std::fs;
2use std::io::BufReader;
3use std::path::Path;
4use utf8_chars::BufReadCharsExt;
5
6pub struct Source<A: 'static>(Box<dyn FnOnce() -> Option<(A, Source<A>)> + 'static>);
7
8impl<A: 'static> Source<A> {
9    #[allow(clippy::should_implement_trait)]
10    pub fn next(&mut self) -> Option<A> {
11        let original = std::mem::replace(self, Source::empty());
12        match original.0() {
13            Some((next_element, next_source)) => {
14                *self = next_source;
15                Some(next_element)
16            }
17            None => None,
18        }
19    }
20
21    pub fn has_next(&mut self) -> bool {
22        match self.next() {
23            Some(a) => {
24                let original = std::mem::replace(self, Source::empty());
25                *self = original.prepend(a);
26                true
27            }
28            None => false,
29        }
30    }
31
32    pub fn new<F: FnMut() -> Option<A> + 'static>(mut function: F) -> Source<A> {
33        Source(Box::new(move || {
34            function().map(|next| (next, Source::new(function)))
35        }))
36    }
37
38    pub fn empty() -> Source<A> {
39        Source(Box::new(|| None))
40    }
41
42    pub fn single(a: A) -> Source<A> {
43        Source(Box::new(|| Some((a, Source::empty()))))
44    }
45
46    pub fn map<B, F: FnMut(A) -> B + 'static>(mut self, mut function: F) -> Source<B> {
47        #[allow(clippy::redundant_closure)]
48        Source::new(move || self.next().map(|x| function(x)))
49    }
50
51    pub fn filter<F: FnMut(&A) -> bool + 'static>(mut self, mut function: F) -> Source<A> {
52        Source::new(move || loop {
53            match self.next() {
54                Some(a) if function(&a) => return Some(a),
55                Some(_) => {}
56                None => return None,
57            }
58        })
59    }
60
61    pub fn fold<Accumulator, F: FnMut(Accumulator, A) -> Accumulator>(
62        self,
63        initial: Accumulator,
64        mut function: F,
65    ) -> Accumulator {
66        let mut accumulator = initial;
67        for a in self {
68            accumulator = function(accumulator, a);
69        }
70        accumulator
71    }
72
73    pub fn flat_map<B, Next: FnMut(A) -> Source<B> + 'static>(self, next: Next) -> Source<B> {
74        self.map(next).flatten()
75    }
76
77    pub fn concat(self, other: Source<A>) -> Source<A> {
78        Source(Box::new(move || match self.0() {
79            Some((a, next)) => Some((a, next.concat(other))),
80            None => other.0(),
81        }))
82    }
83
84    pub fn append(self, last: A) -> Source<A> {
85        self.concat(Source::single(last))
86    }
87
88    pub fn prepend(self, head: A) -> Source<A> {
89        Source(Box::new(|| Some((head, self))))
90    }
91
92    pub fn count<F: Fn(A) -> bool>(self, predicate: F) -> i32 {
93        self.fold(0, |count, a| if predicate(a) { count + 1 } else { count })
94    }
95}
96
97impl<A, I: Iterator<Item = A> + 'static> From<I> for Source<A> {
98    fn from(mut iterator: I) -> Self {
99        Source::new(move || iterator.next())
100    }
101}
102
103impl<A> Source<Source<A>> {
104    pub fn flatten(mut self) -> Source<A> {
105        let mut current = Source::empty();
106        Source::new(move || loop {
107            match current.next() {
108                Some(a) => return Some(a),
109                None => match self.next() {
110                    Some(next_chunk) => {
111                        current = next_chunk;
112                    }
113                    None => return None,
114                },
115            }
116        })
117    }
118}
119
120impl<A: Clone> Source<A> {
121    pub fn peek(&mut self) -> Option<A> {
122        match self.next() {
123            Some(a) => {
124                let original = std::mem::replace(self, Source::empty());
125                *self = original.prepend(a.clone());
126                Some(a)
127            }
128            None => None,
129        }
130    }
131
132    pub fn replicate(n: u32, element: A) -> Source<A> {
133        let mut counter = 0;
134        Source::new(move || {
135            if counter < n {
136                counter += 1;
137                Some(element.clone())
138            } else {
139                None
140            }
141        })
142    }
143}
144
145impl Source<char> {
146    pub fn read_utf8_file(file: &Path) -> Result<Source<char>, std::io::Error> {
147        let mut file = BufReader::new(fs::File::open(file)?);
148        Ok(Source::new(move || match file.read_char() {
149            Ok(char) => char,
150            Err(_) => Some(std::char::REPLACEMENT_CHARACTER),
151        }))
152    }
153}
154
155impl<Snippet: Into<Box<str>>> Source<Snippet> {
156    pub fn join<Separator: Into<Box<str>>>(self, separator: Separator) -> String {
157        let separator: &str = &separator.into();
158        let mut first = true;
159        let mut result = "".to_string();
160        for string in self {
161            if !first {
162                result.push_str(separator);
163            } else {
164                first = false;
165            }
166            result.push_str(&string.into());
167        }
168        result
169    }
170}
171
172impl<A> IntoIterator for Source<A> {
173    type Item = A;
174    type IntoIter = SourceIterator<A>;
175
176    fn into_iter(self) -> SourceIterator<A> {
177        SourceIterator(self)
178    }
179}
180
181pub struct SourceIterator<A: 'static>(Source<A>);
182
183impl<A> Iterator for SourceIterator<A> {
184    type Item = A;
185
186    fn next(&mut self) -> Option<A> {
187        self.0.next()
188    }
189}
190
191#[macro_export]
192macro_rules! source {
193    ($($x:expr),*) => {
194        $crate::Source::from(vec![$($x),*].into_iter())
195    };
196    ($($x:expr,)*) => {
197        source![$($x),*]
198    };
199    ($element:expr; $n:expr) => {
200        $crate::Source::replicate($n, $element)
201    };
202}
203
204impl<A: std::fmt::Debug> Source<A> {
205    pub fn debug(self) -> String {
206        format!("source![{}]", self.map(|x| format!("{:?}", x)).join(", "))
207    }
208}
209
210#[cfg(test)]
211mod test {
212    use super::*;
213
214    impl<A> Source<A> {
215        pub fn to_vec(self) -> Vec<A> {
216            self.into_iter().collect()
217        }
218    }
219
220    mod conversions {
221        use super::*;
222
223        #[test]
224        fn allows_to_convert_from_iterator() {
225            let iter = vec![1, 2, 3].into_iter();
226            let from_next = Source::from(iter);
227            assert_eq!(from_next.to_vec(), vec![1, 2, 3]);
228        }
229
230        #[test]
231        fn allows_to_convert_into_iterator() {
232            let source = source!(1, 2, 3).into_iter();
233            assert_eq!(source.collect::<Vec<_>>(), vec![1, 2, 3]);
234        }
235    }
236
237    mod source_macro {
238        use super::*;
239
240        #[test]
241        fn allows_to_convert_from_elements() {
242            let source: Source<i32> = source![1, 2, 3];
243            assert_eq!(source.to_vec(), vec![1, 2, 3]);
244        }
245
246        #[test]
247        fn allows_to_create_empty_sources() {
248            let source: Source<i32> = Source::empty();
249            assert_eq!(source.to_vec(), vec![]);
250        }
251
252        #[test]
253        fn allows_to_create_sources_with_one_element() {
254            let source = Source::single("foo");
255            assert_eq!(source.to_vec(), vec!["foo"]);
256        }
257
258        #[test]
259        fn allows_to_trailing_commas() {
260            let source: Source<i32> = source![1, 2, 3,];
261            assert_eq!(source.to_vec(), vec![1, 2, 3]);
262        }
263
264        #[test]
265        fn allows_to_replicate_a_given_element() {
266            let source: Source<i32> = source![42; 3];
267            assert_eq!(source.to_vec(), vec![42, 42, 42]);
268        }
269    }
270
271    mod debug {
272        use super::*;
273
274        #[test]
275        fn debug_converts_into_source_macro() {
276            assert_eq!(source![1, 2, 3].debug(), "source![1, 2, 3]");
277            let empty: Source<i32> = source![];
278            assert_eq!(empty.debug(), "source![]");
279        }
280
281        #[test]
282        fn debug_uses_debug() {
283            assert_eq!(source!["foo", "bar"].debug(), r#"source!["foo", "bar"]"#);
284        }
285    }
286
287    mod has_next {
288        use super::*;
289
290        #[test]
291        fn returns_true_for_non_empty_sources() {
292            let mut source = source!["foo"];
293            assert_eq!(source.has_next(), true);
294        }
295
296        #[test]
297        fn returns_false_when_all_elements_are_consumed() {
298            let mut source = source!["foo"];
299            source.next();
300            assert_eq!(source.has_next(), false);
301        }
302
303        #[test]
304        fn returns_false_for_empty_sources() {
305            let mut source: Source<()> = source![];
306            assert_eq!(source.has_next(), false);
307        }
308
309        #[test]
310        fn does_not_modify_the_source_elements() {
311            let mut source = source!["foo"];
312            source.has_next();
313            assert_eq!(source.to_vec(), vec!["foo"]);
314        }
315    }
316
317    #[test]
318    fn map_works() {
319        let from_next: Source<i32> = source![1, 2, 3];
320        let mapped = from_next.map(|x| x.pow(2));
321        assert_eq!(vec![1, 4, 9], mapped.to_vec());
322    }
323
324    #[test]
325    fn filter_works() {
326        let source = Source::from(1..6).filter(|x| x % 2 == 1);
327        assert_eq!(source.to_vec(), vec![1, 3, 5]);
328    }
329
330    #[test]
331    fn fold_works() {
332        let sum = Source::from(1..6).fold(0, |sum: i32, a| sum + a);
333        assert_eq!(sum, 15);
334    }
335
336    #[test]
337    fn flatten_works() {
338        let flattened = source!["foo", "bar"]
339            .map(|x| Source::from(x.chars()))
340            .flatten();
341        assert_eq!(vec!['f', 'o', 'o', 'b', 'a', 'r'], flattened.to_vec());
342    }
343
344    #[test]
345    fn flatmap_works() {
346        let source = source!["foo", "bar"].flat_map(|x| Source::from(x.chars()));
347        assert_eq!(vec!['f', 'o', 'o', 'b', 'a', 'r'], source.to_vec());
348    }
349
350    #[test]
351    fn concat_works() {
352        let mut source = source!["foo", "bar"];
353        source = source.concat(source!["baz"]);
354        assert_eq!(vec!["foo", "bar", "baz"], source.to_vec());
355    }
356
357    #[test]
358    fn append_works() {
359        let mut source = source!["foo", "bar"];
360        source = source.append("baz");
361        assert_eq!(vec!["foo", "bar", "baz"], source.to_vec());
362    }
363
364    #[test]
365    fn prepend_works() {
366        let source = source!["bar", "baz"].prepend("foo");
367        assert_eq!(vec!["foo", "bar", "baz"], source.to_vec());
368    }
369
370    mod peek {
371        use super::*;
372
373        #[test]
374        fn peek_works() {
375            let mut source = source!["foo", "bar"];
376            assert_eq!(source.peek(), Some("foo"));
377            assert_eq!(vec!["foo", "bar"], source.to_vec());
378        }
379
380        #[test]
381        fn allows_to_peek_ahead() {
382            let mut source = Source::from("x".chars());
383            assert_eq!(source.peek(), Some('x'));
384        }
385
386        #[test]
387        fn peeking_does_not_consume_chars() {
388            let mut source = Source::from("x".chars());
389            source.peek();
390            assert_eq!(source.next(), Some('x'));
391        }
392
393        #[test]
394        fn peeking_works_twice() {
395            let mut source = Source::from("ab".chars());
396            source.peek();
397            assert_eq!(source.peek(), Some('a'));
398        }
399
400        #[test]
401        fn peeking_works_after_next() {
402            let mut source = Source::from("ab".chars());
403            source.next();
404            assert_eq!(source.peek(), Some('b'));
405        }
406    }
407
408    #[test]
409    fn count_works() {
410        let source = source![1, 2, 3, 4, 5, 6, 7];
411        assert_eq!(source.count(|x| x > 3), 4);
412    }
413
414    mod join {
415        use super::*;
416
417        #[test]
418        fn works() {
419            let source = source!("foo", "bar");
420            assert_eq!(source.join("#"), "foo#bar");
421        }
422
423        #[test]
424        fn works_with_both_str_and_string() {
425            let str_source: Source<&str> = source!();
426            str_source.join("");
427            let str_source: Source<&str> = source!();
428            str_source.join("".to_string());
429            let string_source: Source<String> = source!();
430            string_source.join("");
431            let string_source: Source<String> = source!();
432            string_source.join("".to_string());
433        }
434
435        #[test]
436        fn works_with_empty_inputs() {
437            assert_eq!(source!("", "foo").join("#"), "#foo");
438            assert_eq!(source!("foo", "").join("#"), "foo#");
439            assert_eq!(source!("", "foo", "").join("#"), "#foo#");
440        }
441    }
442}