1 use super::plumbing::*; 2 use super::*; 3 use std::iter; 4 use std::ops::Range; 5 use std::usize; 6 7 /// `Enumerate` is an iterator that returns the current count along with the element. 8 /// This struct is created by the [`enumerate()`] method on [`IndexedParallelIterator`] 9 /// 10 /// [`enumerate()`]: trait.IndexedParallelIterator.html#method.enumerate 11 /// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html 12 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] 13 #[derive(Debug, Clone)] 14 pub struct Enumerate<I: IndexedParallelIterator> { 15 base: I, 16 } 17 18 impl<I> Enumerate<I> 19 where 20 I: IndexedParallelIterator, 21 { 22 /// Creates a new `Enumerate` iterator. new(base: I) -> Self23 pub(super) fn new(base: I) -> Self { 24 Enumerate { base } 25 } 26 } 27 28 impl<I> ParallelIterator for Enumerate<I> 29 where 30 I: IndexedParallelIterator, 31 { 32 type Item = (usize, I::Item); 33 drive_unindexed<C>(self, consumer: C) -> C::Result where C: UnindexedConsumer<Self::Item>,34 fn drive_unindexed<C>(self, consumer: C) -> C::Result 35 where 36 C: UnindexedConsumer<Self::Item>, 37 { 38 bridge(self, consumer) 39 } 40 opt_len(&self) -> Option<usize>41 fn opt_len(&self) -> Option<usize> { 42 Some(self.len()) 43 } 44 } 45 46 impl<I> IndexedParallelIterator for Enumerate<I> 47 where 48 I: IndexedParallelIterator, 49 { drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result50 fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result { 51 bridge(self, consumer) 52 } 53 len(&self) -> usize54 fn len(&self) -> usize { 55 self.base.len() 56 } 57 with_producer<CB>(self, callback: CB) -> CB::Output where CB: ProducerCallback<Self::Item>,58 fn with_producer<CB>(self, callback: CB) -> CB::Output 59 where 60 CB: ProducerCallback<Self::Item>, 61 { 62 return self.base.with_producer(Callback { callback }); 63 64 struct Callback<CB> { 65 callback: CB, 66 } 67 68 impl<I, CB> ProducerCallback<I> for Callback<CB> 69 where 70 CB: ProducerCallback<(usize, I)>, 71 { 72 type Output = CB::Output; 73 fn callback<P>(self, base: P) -> CB::Output 74 where 75 P: Producer<Item = I>, 76 { 77 let producer = EnumerateProducer { base, offset: 0 }; 78 self.callback.callback(producer) 79 } 80 } 81 } 82 } 83 84 /// //////////////////////////////////////////////////////////////////////// 85 /// Producer implementation 86 87 struct EnumerateProducer<P> { 88 base: P, 89 offset: usize, 90 } 91 92 impl<P> Producer for EnumerateProducer<P> 93 where 94 P: Producer, 95 { 96 type Item = (usize, P::Item); 97 type IntoIter = iter::Zip<Range<usize>, P::IntoIter>; 98 into_iter(self) -> Self::IntoIter99 fn into_iter(self) -> Self::IntoIter { 100 // Enumerate only works for IndexedParallelIterators. Since those 101 // have a max length of usize::MAX, their max index is 102 // usize::MAX - 1, so the range 0..usize::MAX includes all 103 // possible indices. 104 // 105 // However, we should to use a precise end to the range, otherwise 106 // reversing the iterator may have to walk back a long ways before 107 // `Zip::next_back` can produce anything. 108 let base = self.base.into_iter(); 109 let end = self.offset + base.len(); 110 (self.offset..end).zip(base) 111 } 112 min_len(&self) -> usize113 fn min_len(&self) -> usize { 114 self.base.min_len() 115 } max_len(&self) -> usize116 fn max_len(&self) -> usize { 117 self.base.max_len() 118 } 119 split_at(self, index: usize) -> (Self, Self)120 fn split_at(self, index: usize) -> (Self, Self) { 121 let (left, right) = self.base.split_at(index); 122 ( 123 EnumerateProducer { 124 base: left, 125 offset: self.offset, 126 }, 127 EnumerateProducer { 128 base: right, 129 offset: self.offset + index, 130 }, 131 ) 132 } 133 } 134