Skip to main content

moirai_iter/parallel/adapters/
filter.rs

1use super::super::{Consumer, FilterConsumer, FilterMapConsumer, ParallelIterator, VecParIter};
2use super::map::Map;
3use super::pair::ZipEq;
4use std::ops::ControlFlow;
5
6/// Filter adapter for parallel iterators.
7pub struct Filter<I, F> {
8    pub(super) base: I,
9    pub(super) filter_fn: F,
10}
11
12impl<I, F> Filter<I, F> {
13    pub(crate) fn new(base: I, filter_fn: F) -> Self {
14        Self { base, filter_fn }
15    }
16}
17
18impl<I, J, MapFn, FilterFn, Mapped> Filter<Map<ZipEq<I, J>, MapFn>, FilterFn>
19where
20    I: ParallelIterator,
21    J: ParallelIterator,
22    I::Item: Sync + 'static,
23    J::Item: Sync + 'static,
24    MapFn: Fn((I::Item, J::Item)) -> Mapped + Send + Sync + Clone,
25    FilterFn: Fn(&Mapped) -> bool + Send + Sync + Clone,
26    Mapped: Send,
27{
28    /// Collect a zipped, mapped, filtered stream without intermediate pair vectors.
29    pub fn collect<C>(self) -> C
30    where
31        C: FromIterator<Mapped> + Send,
32    {
33        let filter_fn = self.filter_fn;
34        let map = self.base;
35        let map_fn = map.map_fn;
36        let zip = map.base;
37        let left = zip.left.seq_items();
38        let right = zip.right.seq_items();
39        assert_eq!(
40            left.len(),
41            right.len(),
42            "zip_eq requires equal input lengths"
43        );
44
45        left.into_iter()
46            .zip(right)
47            .map(map_fn)
48            .filter(filter_fn)
49            .collect()
50    }
51}
52
53impl<I, F> ParallelIterator for Filter<I, F>
54where
55    I: ParallelIterator,
56    F: Fn(&I::Item) -> bool + Send + Sync + Clone,
57{
58    type Item = I::Item;
59
60    fn seq_items(self) -> Vec<Self::Item> {
61        self.base
62            .seq_items()
63            .into_iter()
64            .filter(|x| (self.filter_fn)(x))
65            .collect()
66    }
67
68    fn seq_iter(self) -> impl Iterator<Item = Self::Item> {
69        self.base.seq_iter().filter(self.filter_fn)
70    }
71
72    fn seq_try_fold<Acc, B, FoldFn>(self, init: Acc, mut fold_fn: FoldFn) -> ControlFlow<B, Acc>
73    where
74        FoldFn: FnMut(Acc, Self::Item) -> ControlFlow<B, Acc>,
75    {
76        let filter_fn = self.filter_fn;
77        self.base.seq_try_fold(init, move |accumulator, item| {
78            if filter_fn(&item) {
79                fold_fn(accumulator, item)
80            } else {
81                ControlFlow::Continue(accumulator)
82            }
83        })
84    }
85
86    fn drive<C, R>(self, consumer: C) -> R
87    where
88        C: Consumer<Self::Item, Result = R> + Send + Sync,
89        R: Send,
90    {
91        self.base
92            .drive(FilterConsumer::new(consumer, self.filter_fn))
93    }
94}
95
96/// Filter-map adapter with value-semantic optional output.
97pub struct FilterMap<I, F> {
98    pub(super) base: I,
99    pub(super) filter_map_fn: F,
100}
101
102impl<I, F> FilterMap<I, F> {
103    pub(crate) fn new(base: I, filter_map_fn: F) -> Self {
104        Self {
105            base,
106            filter_map_fn,
107        }
108    }
109}
110
111impl<I, F, R> ParallelIterator for FilterMap<I, F>
112where
113    I: ParallelIterator,
114    F: Fn(I::Item) -> Option<R> + Send + Sync + Clone,
115    R: Send + Sync + 'static,
116{
117    type Item = R;
118
119    fn seq_try_fold<Acc, B, FoldFn>(self, init: Acc, mut fold_fn: FoldFn) -> ControlFlow<B, Acc>
120    where
121        FoldFn: FnMut(Acc, Self::Item) -> ControlFlow<B, Acc>,
122    {
123        let filter_map_fn = self.filter_map_fn;
124        self.base
125            .seq_try_fold(init, move |accumulator, item| match filter_map_fn(item) {
126                Some(mapped) => fold_fn(accumulator, mapped),
127                None => ControlFlow::Continue(accumulator),
128            })
129    }
130
131    fn seq_items(self) -> Vec<Self::Item> {
132        self.base
133            .seq_items()
134            .into_iter()
135            .filter_map(self.filter_map_fn)
136            .collect()
137    }
138
139    fn drive<C, R2>(self, consumer: C) -> R2
140    where
141        C: Consumer<Self::Item, Result = R2> + Send + Sync,
142        R2: Send,
143    {
144        // Push the filtering map into the consumer and drive the base, the way
145        // `Filter` and `Map` do. Materializing `seq_items()` first collected the
146        // whole logical stream into one vector before any split, discarding the
147        // source's shards for every chain containing `filter_map()`.
148        self.base
149            .drive(FilterMapConsumer::new(consumer, self.filter_map_fn))
150    }
151}
152
153/// While-some adapter with prefix-unwrapping semantics for optional streams.
154pub struct WhileSome<I> {
155    pub(super) base: I,
156}
157
158impl<I> WhileSome<I> {
159    pub(crate) fn new(base: I) -> Self {
160        Self { base }
161    }
162}
163
164impl<I, T> ParallelIterator for WhileSome<I>
165where
166    I: ParallelIterator<Item = Option<T>>,
167    T: Send + Sync + 'static,
168{
169    type Item = T;
170
171    fn seq_items(self) -> Vec<Self::Item> {
172        self.base
173            .seq_items()
174            .into_iter()
175            .map_while(|item| item)
176            .collect()
177    }
178
179    /// # Why this stays sequential
180    ///
181    /// `while_some` stops the whole logical stream at the first `None`, so
182    /// whether a shard's items survive depends on whether an earlier shard
183    /// already stopped — a cross-shard dependency the consumer protocol cannot
184    /// express. A shard that ran `map_while` over its own range alone would
185    /// keep items that follow an earlier shard's `None`, which is a different
186    /// stream, not a reordering of the same one. `take_any_while` and
187    /// `skip_any_while` stay sequential for this same prefix dependency.
188    fn drive<C, R>(self, consumer: C) -> R
189    where
190        C: Consumer<Self::Item, Result = R> + Send + Sync,
191        R: Send,
192    {
193        consumer.consume(VecParIter::new(self.seq_items()))
194    }
195}