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> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result19     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.
new(base: I, filter_op: P) -> Self28     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 
drive_unindexed<C>(self, consumer: C) -> C::Result where C: UnindexedConsumer<Self::Item>,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> {
new(base: C, filter_op: &'p P) -> Self59     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 
split_at(self, index: usize) -> (Self, Self, Self::Reducer)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 
into_folder(self) -> Self::Folder82     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 
full(&self) -> bool90     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 {
split_off_left(&self) -> Self100     fn split_off_left(&self) -> Self {
101         FilterMapConsumer::new(self.base.split_off_left(), &self.filter_op)
102     }
103 
to_reducer(&self) -> Self::Reducer104     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 
consume(self, item: T) -> Self121     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 
complete(self) -> C::Result135     fn complete(self) -> C::Result {
136         self.base.complete()
137     }
138 
full(&self) -> bool139     fn full(&self) -> bool {
140         self.base.full()
141     }
142 }
143