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