Skip to main content

moirai_iter/parallel/adapters/
position.rs

1use super::super::{Consumer, ParallelIterator, VecParIter};
2
3/// Position adapter that yields logical indices for matching items.
4pub struct Positions<I, F> {
5    base: I,
6    predicate: F,
7}
8
9/// Fused map-position adapter that yields logical indices without materializing mapped items.
10pub struct MapPositions<I, MapFn, Predicate> {
11    base: I,
12    map_fn: MapFn,
13    predicate: Predicate,
14}
15
16impl<I, F> Positions<I, F> {
17    pub(in crate::parallel) fn new(base: I, predicate: F) -> Self {
18        Self { base, predicate }
19    }
20}
21
22impl<I, MapFn, Predicate> MapPositions<I, MapFn, Predicate> {
23    pub(in crate::parallel) fn new(base: I, map_fn: MapFn, predicate: Predicate) -> Self {
24        Self {
25            base,
26            map_fn,
27            predicate,
28        }
29    }
30}
31
32impl<I, F> ParallelIterator for Positions<I, F>
33where
34    I: ParallelIterator,
35    F: Fn(I::Item) -> bool + Send + Sync + Clone,
36{
37    type Item = usize;
38
39    fn seq_items(self) -> Vec<Self::Item> {
40        self.base
41            .seq_items()
42            .into_iter()
43            .enumerate()
44            .filter_map(|(index, item)| (self.predicate)(item).then_some(index))
45            .collect()
46    }
47
48    /// # Why this stays sequential
49    ///
50    /// The yielded item *is* a logical index, so this adapter needs exactly the
51    /// offset documented as absent on
52    /// [`Enumerate`](super::ref_ops::Enumerate).
53    fn drive<C, R>(self, consumer: C) -> R
54    where
55        C: Consumer<Self::Item, Result = R> + Send + Sync,
56        R: Send,
57    {
58        consumer.consume(VecParIter::new(self.seq_items()))
59    }
60}
61
62impl<I, MapFn, Predicate, Mapped> ParallelIterator for MapPositions<I, MapFn, Predicate>
63where
64    I: ParallelIterator,
65    MapFn: Fn(I::Item) -> Mapped + Send + Sync + Clone,
66    Predicate: Fn(Mapped) -> bool + Send + Sync + Clone,
67    Mapped: Send,
68{
69    type Item = usize;
70
71    fn seq_items(self) -> Vec<Self::Item> {
72        let map_fn = self.map_fn;
73        let predicate = self.predicate;
74
75        self.base
76            .seq_items()
77            .into_iter()
78            .enumerate()
79            .filter_map(|(index, item)| predicate(map_fn(item)).then_some(index))
80            .collect()
81    }
82
83    /// # Why this stays sequential
84    ///
85    /// Yields logical indices, per [`Positions`].
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        consumer.consume(VecParIter::new(self.seq_items()))
92    }
93}