1 | use super::plumbing::*; |
2 | use super::*; |
3 | |
4 | use std::fmt::{self, Debug}; |
5 | |
6 | /// `FilterMap` creates an iterator that uses `filter_op` to both filter and map elements. |
7 | /// This struct is created by the [`filter_map()`] method on [`ParallelIterator`]. |
8 | /// |
9 | /// [`filter_map()`]: trait.ParallelIterator.html#method.filter_map |
10 | /// [`ParallelIterator`]: trait.ParallelIterator.html |
11 | #[must_use = "iterator adaptors are lazy and do nothing unless consumed" ] |
12 | #[derive(Clone)] |
13 | pub struct FilterMap<I: ParallelIterator, P> { |
14 | base: I, |
15 | filter_op: P, |
16 | } |
17 | |
18 | impl<I: ParallelIterator + Debug, P> Debug for FilterMap<I, P> { |
19 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
20 | f.debug_struct("FilterMap" ) |
21 | .field("base" , &self.base) |
22 | .finish() |
23 | } |
24 | } |
25 | |
26 | impl<I: ParallelIterator, P> FilterMap<I, P> { |
27 | /// Creates a new `FilterMap` iterator. |
28 | pub(super) fn new(base: I, filter_op: P) -> Self { |
29 | FilterMap { base, filter_op } |
30 | } |
31 | } |
32 | |
33 | impl<I, P, R> ParallelIterator for FilterMap<I, P> |
34 | where |
35 | I: ParallelIterator, |
36 | P: Fn(I::Item) -> Option<R> + Sync + Send, |
37 | R: Send, |
38 | { |
39 | type Item = R; |
40 | |
41 | fn drive_unindexed<C>(self, consumer: C) -> C::Result |
42 | where |
43 | C: UnindexedConsumer<Self::Item>, |
44 | { |
45 | let consumer = FilterMapConsumer::new(consumer, &self.filter_op); |
46 | self.base.drive_unindexed(consumer) |
47 | } |
48 | } |
49 | |
50 | /// //////////////////////////////////////////////////////////////////////// |
51 | /// Consumer implementation |
52 | |
53 | struct FilterMapConsumer<'p, C, P> { |
54 | base: C, |
55 | filter_op: &'p P, |
56 | } |
57 | |
58 | impl<'p, C, P: 'p> FilterMapConsumer<'p, C, P> { |
59 | fn new(base: C, filter_op: &'p P) -> Self { |
60 | FilterMapConsumer { base, filter_op } |
61 | } |
62 | } |
63 | |
64 | impl<'p, T, U, C, P> Consumer<T> for FilterMapConsumer<'p, C, P> |
65 | where |
66 | C: Consumer<U>, |
67 | P: Fn(T) -> Option<U> + Sync + 'p, |
68 | { |
69 | type Folder = FilterMapFolder<'p, C::Folder, P>; |
70 | type Reducer = C::Reducer; |
71 | type Result = C::Result; |
72 | |
73 | fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) { |
74 | let (left, right, reducer) = self.base.split_at(index); |
75 | ( |
76 | FilterMapConsumer::new(left, self.filter_op), |
77 | FilterMapConsumer::new(right, self.filter_op), |
78 | reducer, |
79 | ) |
80 | } |
81 | |
82 | fn into_folder(self) -> Self::Folder { |
83 | let base = self.base.into_folder(); |
84 | FilterMapFolder { |
85 | base, |
86 | filter_op: self.filter_op, |
87 | } |
88 | } |
89 | |
90 | fn full(&self) -> bool { |
91 | self.base.full() |
92 | } |
93 | } |
94 | |
95 | impl<'p, T, U, C, P> UnindexedConsumer<T> for FilterMapConsumer<'p, C, P> |
96 | where |
97 | C: UnindexedConsumer<U>, |
98 | P: Fn(T) -> Option<U> + Sync + 'p, |
99 | { |
100 | fn split_off_left(&self) -> Self { |
101 | FilterMapConsumer::new(self.base.split_off_left(), self.filter_op) |
102 | } |
103 | |
104 | fn to_reducer(&self) -> Self::Reducer { |
105 | self.base.to_reducer() |
106 | } |
107 | } |
108 | |
109 | struct FilterMapFolder<'p, C, P> { |
110 | base: C, |
111 | filter_op: &'p P, |
112 | } |
113 | |
114 | impl<'p, T, U, C, P> Folder<T> for FilterMapFolder<'p, C, P> |
115 | where |
116 | C: Folder<U>, |
117 | P: Fn(T) -> Option<U> + Sync + 'p, |
118 | { |
119 | type Result = C::Result; |
120 | |
121 | fn consume(self, item: T) -> Self { |
122 | let filter_op = self.filter_op; |
123 | if let Some(mapped_item) = filter_op(item) { |
124 | let base = self.base.consume(mapped_item); |
125 | FilterMapFolder { base, filter_op } |
126 | } else { |
127 | self |
128 | } |
129 | } |
130 | |
131 | // This cannot easily specialize `consume_iter` to be better than |
132 | // the default, because that requires checking `self.base.full()` |
133 | // during a call to `self.base.consume_iter()`. (#632) |
134 | |
135 | fn complete(self) -> C::Result { |
136 | self.base.complete() |
137 | } |
138 | |
139 | fn full(&self) -> bool { |
140 | self.base.full() |
141 | } |
142 | } |
143 | |