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