chj_rustbin/sequences.rs
1use genawaiter::rc::Gen;
2
3/// Build groups of items from the input stream. A group finishes when
4/// `belong`, being passed the previous and new item, returns
5/// false. Each group is first collected in a Vec, then passed to the
6/// `construct` function as a mutable reference via an `Option` (which
7/// is always `Some`), and the return value becomes the item in the
8/// resulting sequence. The reason the vector is passed via `Option`
9/// is so that `construct` can take it out via `.take().unwrap()` if
10/// it wishes; if it does, `group` creates a new Vec for the next
11/// group, otherwise it reuses the old one for efficiency.
12
13/// The resulting iterator is empty (no group is reported) if the
14/// input is empty.
15
16pub fn group<T, G>(
17 mut inp: impl Iterator<Item = T>,
18 belong: impl Fn(&T, &T) -> bool,
19 construct: impl Fn(&mut Option<Vec<T>>) -> G,
20) -> impl Iterator<Item = G> {
21 Gen::new(|co| async move {
22 let mut v = Some(Vec::new());
23 let mut last_item = None;
24 while let Some(item) = inp.next() {
25 if let Some(last) = last_item.take() {
26 let same = belong(&last, &item);
27 v.as_mut().unwrap().push(last);
28 if !same {
29 co.yield_(construct(&mut v)).await;
30 if let Some(vr) = v.as_mut() {
31 vr.clear();
32 } else {
33 v = Some(Vec::new());
34 }
35 }
36 }
37 last_item = Some(item);
38 }
39 if let Some(last) = last_item.take() {
40 v.as_mut().unwrap().push(last);
41 co.yield_(construct(&mut v)).await;
42 }
43 })
44 .into_iter()
45}
46
47/// Same as `group` but handles errors in the input stream, making it
48/// easier to use (and more efficient?) than group in that case. Also,
49/// continues building the group, so in case the receiver of the
50/// output stream continues to read past errors, they will still
51/// receive groups, and erros do not break up groups (this would not
52/// be possible to achieve via `group`).
53pub fn try_group<T, G, E>(
54 mut inp: impl Iterator<Item = Result<T, E>>,
55 belong: impl Fn(&T, &T) -> bool,
56 construct: impl Fn(&mut Option<Vec<T>>) -> G,
57) -> impl Iterator<Item = Result<G, E>> {
58 Gen::new(|co| async move {
59 let mut v = Some(Vec::new());
60 let mut last_item = None;
61 while let Some(result_item) = inp.next() {
62 match result_item {
63 Ok(item) => {
64 if let Some(last) = last_item.take() {
65 let same = belong(&last, &item);
66 v.as_mut().unwrap().push(last);
67 if !same {
68 co.yield_(Ok(construct(&mut v))).await;
69 if let Some(vr) = v.as_mut() {
70 vr.clear();
71 } else {
72 v = Some(Vec::new());
73 }
74 }
75 }
76 last_item = Some(item);
77 }
78 Err(e) => co.yield_(Err(e)).await,
79 }
80 }
81 if let Some(last) = last_item.take() {
82 v.as_mut().unwrap().push(last);
83 co.yield_(Ok(construct(&mut v))).await;
84 }
85 })
86 .into_iter()
87}