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