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}