summaryrefslogtreecommitdiffstats
path: root/third_party/rust/rayon/src/iter
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/rayon/src/iter')
-rw-r--r--third_party/rust/rayon/src/iter/chain.rs268
-rw-r--r--third_party/rust/rayon/src/iter/chunks.rs226
-rw-r--r--third_party/rust/rayon/src/iter/cloned.rs223
-rw-r--r--third_party/rust/rayon/src/iter/collect/consumer.rs186
-rw-r--r--third_party/rust/rayon/src/iter/collect/mod.rs116
-rw-r--r--third_party/rust/rayon/src/iter/collect/test.rs371
-rw-r--r--third_party/rust/rayon/src/iter/copied.rs223
-rw-r--r--third_party/rust/rayon/src/iter/empty.rs104
-rw-r--r--third_party/rust/rayon/src/iter/enumerate.rs133
-rw-r--r--third_party/rust/rayon/src/iter/extend.rs604
-rw-r--r--third_party/rust/rayon/src/iter/filter.rs141
-rw-r--r--third_party/rust/rayon/src/iter/filter_map.rs142
-rw-r--r--third_party/rust/rayon/src/iter/find.rs120
-rw-r--r--third_party/rust/rayon/src/iter/find_first_last/mod.rs238
-rw-r--r--third_party/rust/rayon/src/iter/find_first_last/test.rs106
-rw-r--r--third_party/rust/rayon/src/iter/flat_map.rs154
-rw-r--r--third_party/rust/rayon/src/iter/flat_map_iter.rs147
-rw-r--r--third_party/rust/rayon/src/iter/flatten.rs140
-rw-r--r--third_party/rust/rayon/src/iter/flatten_iter.rs132
-rw-r--r--third_party/rust/rayon/src/iter/fold.rs302
-rw-r--r--third_party/rust/rayon/src/iter/fold_chunks.rs236
-rw-r--r--third_party/rust/rayon/src/iter/fold_chunks_with.rs231
-rw-r--r--third_party/rust/rayon/src/iter/for_each.rs77
-rw-r--r--third_party/rust/rayon/src/iter/from_par_iter.rs228
-rw-r--r--third_party/rust/rayon/src/iter/inspect.rs257
-rw-r--r--third_party/rust/rayon/src/iter/interleave.rs336
-rw-r--r--third_party/rust/rayon/src/iter/interleave_shortest.rs85
-rw-r--r--third_party/rust/rayon/src/iter/intersperse.rs410
-rw-r--r--third_party/rust/rayon/src/iter/len.rs271
-rw-r--r--third_party/rust/rayon/src/iter/map.rs259
-rw-r--r--third_party/rust/rayon/src/iter/map_with.rs573
-rw-r--r--third_party/rust/rayon/src/iter/mod.rs3385
-rw-r--r--third_party/rust/rayon/src/iter/multizip.rs338
-rw-r--r--third_party/rust/rayon/src/iter/noop.rs59
-rw-r--r--third_party/rust/rayon/src/iter/once.rs68
-rw-r--r--third_party/rust/rayon/src/iter/panic_fuse.rs342
-rw-r--r--third_party/rust/rayon/src/iter/par_bridge.rs162
-rw-r--r--third_party/rust/rayon/src/iter/plumbing/README.md315
-rw-r--r--third_party/rust/rayon/src/iter/plumbing/mod.rs484
-rw-r--r--third_party/rust/rayon/src/iter/positions.rs137
-rw-r--r--third_party/rust/rayon/src/iter/product.rs114
-rw-r--r--third_party/rust/rayon/src/iter/reduce.rs116
-rw-r--r--third_party/rust/rayon/src/iter/repeat.rs241
-rw-r--r--third_party/rust/rayon/src/iter/rev.rs123
-rw-r--r--third_party/rust/rayon/src/iter/skip.rs95
-rw-r--r--third_party/rust/rayon/src/iter/splitter.rs174
-rw-r--r--third_party/rust/rayon/src/iter/step_by.rs143
-rw-r--r--third_party/rust/rayon/src/iter/sum.rs110
-rw-r--r--third_party/rust/rayon/src/iter/take.rs86
-rw-r--r--third_party/rust/rayon/src/iter/test.rs2185
-rw-r--r--third_party/rust/rayon/src/iter/try_fold.rs298
-rw-r--r--third_party/rust/rayon/src/iter/try_reduce.rs131
-rw-r--r--third_party/rust/rayon/src/iter/try_reduce_with.rs132
-rw-r--r--third_party/rust/rayon/src/iter/unzip.rs525
-rw-r--r--third_party/rust/rayon/src/iter/update.rs327
-rw-r--r--third_party/rust/rayon/src/iter/while_some.rs154
-rw-r--r--third_party/rust/rayon/src/iter/zip.rs159
-rw-r--r--third_party/rust/rayon/src/iter/zip_eq.rs72
58 files changed, 17514 insertions, 0 deletions
diff --git a/third_party/rust/rayon/src/iter/chain.rs b/third_party/rust/rayon/src/iter/chain.rs
new file mode 100644
index 0000000000..48fce07ed8
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/chain.rs
@@ -0,0 +1,268 @@
+use super::plumbing::*;
+use super::*;
+use rayon_core::join;
+use std::cmp;
+use std::iter;
+
+/// `Chain` is an iterator that joins `b` after `a` in one continuous iterator.
+/// This struct is created by the [`chain()`] method on [`ParallelIterator`]
+///
+/// [`chain()`]: trait.ParallelIterator.html#method.chain
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct Chain<A, B>
+where
+ A: ParallelIterator,
+ B: ParallelIterator<Item = A::Item>,
+{
+ a: A,
+ b: B,
+}
+
+impl<A, B> Chain<A, B>
+where
+ A: ParallelIterator,
+ B: ParallelIterator<Item = A::Item>,
+{
+ /// Creates a new `Chain` iterator.
+ pub(super) fn new(a: A, b: B) -> Self {
+ Chain { a, b }
+ }
+}
+
+impl<A, B> ParallelIterator for Chain<A, B>
+where
+ A: ParallelIterator,
+ B: ParallelIterator<Item = A::Item>,
+{
+ type Item = A::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let Chain { a, b } = self;
+
+ // If we returned a value from our own `opt_len`, then the collect consumer in particular
+ // will balk at being treated like an actual `UnindexedConsumer`. But when we do know the
+ // length, we can use `Consumer::split_at` instead, and this is still harmless for other
+ // truly-unindexed consumers too.
+ let (left, right, reducer) = if let Some(len) = a.opt_len() {
+ consumer.split_at(len)
+ } else {
+ let reducer = consumer.to_reducer();
+ (consumer.split_off_left(), consumer, reducer)
+ };
+
+ let (a, b) = join(|| a.drive_unindexed(left), || b.drive_unindexed(right));
+ reducer.reduce(a, b)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ self.a.opt_len()?.checked_add(self.b.opt_len()?)
+ }
+}
+
+impl<A, B> IndexedParallelIterator for Chain<A, B>
+where
+ A: IndexedParallelIterator,
+ B: IndexedParallelIterator<Item = A::Item>,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ let Chain { a, b } = self;
+ let (left, right, reducer) = consumer.split_at(a.len());
+ let (a, b) = join(|| a.drive(left), || b.drive(right));
+ reducer.reduce(a, b)
+ }
+
+ fn len(&self) -> usize {
+ self.a.len().checked_add(self.b.len()).expect("overflow")
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ let a_len = self.a.len();
+ return self.a.with_producer(CallbackA {
+ callback,
+ a_len,
+ b: self.b,
+ });
+
+ struct CallbackA<CB, B> {
+ callback: CB,
+ a_len: usize,
+ b: B,
+ }
+
+ impl<CB, B> ProducerCallback<B::Item> for CallbackA<CB, B>
+ where
+ B: IndexedParallelIterator,
+ CB: ProducerCallback<B::Item>,
+ {
+ type Output = CB::Output;
+
+ fn callback<A>(self, a_producer: A) -> Self::Output
+ where
+ A: Producer<Item = B::Item>,
+ {
+ self.b.with_producer(CallbackB {
+ callback: self.callback,
+ a_len: self.a_len,
+ a_producer,
+ })
+ }
+ }
+
+ struct CallbackB<CB, A> {
+ callback: CB,
+ a_len: usize,
+ a_producer: A,
+ }
+
+ impl<CB, A> ProducerCallback<A::Item> for CallbackB<CB, A>
+ where
+ A: Producer,
+ CB: ProducerCallback<A::Item>,
+ {
+ type Output = CB::Output;
+
+ fn callback<B>(self, b_producer: B) -> Self::Output
+ where
+ B: Producer<Item = A::Item>,
+ {
+ let producer = ChainProducer::new(self.a_len, self.a_producer, b_producer);
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+
+struct ChainProducer<A, B>
+where
+ A: Producer,
+ B: Producer<Item = A::Item>,
+{
+ a_len: usize,
+ a: A,
+ b: B,
+}
+
+impl<A, B> ChainProducer<A, B>
+where
+ A: Producer,
+ B: Producer<Item = A::Item>,
+{
+ fn new(a_len: usize, a: A, b: B) -> Self {
+ ChainProducer { a_len, a, b }
+ }
+}
+
+impl<A, B> Producer for ChainProducer<A, B>
+where
+ A: Producer,
+ B: Producer<Item = A::Item>,
+{
+ type Item = A::Item;
+ type IntoIter = ChainSeq<A::IntoIter, B::IntoIter>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ ChainSeq::new(self.a.into_iter(), self.b.into_iter())
+ }
+
+ fn min_len(&self) -> usize {
+ cmp::max(self.a.min_len(), self.b.min_len())
+ }
+
+ fn max_len(&self) -> usize {
+ cmp::min(self.a.max_len(), self.b.max_len())
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ if index <= self.a_len {
+ let a_rem = self.a_len - index;
+ let (a_left, a_right) = self.a.split_at(index);
+ let (b_left, b_right) = self.b.split_at(0);
+ (
+ ChainProducer::new(index, a_left, b_left),
+ ChainProducer::new(a_rem, a_right, b_right),
+ )
+ } else {
+ let (a_left, a_right) = self.a.split_at(self.a_len);
+ let (b_left, b_right) = self.b.split_at(index - self.a_len);
+ (
+ ChainProducer::new(self.a_len, a_left, b_left),
+ ChainProducer::new(0, a_right, b_right),
+ )
+ }
+ }
+
+ fn fold_with<F>(self, mut folder: F) -> F
+ where
+ F: Folder<A::Item>,
+ {
+ folder = self.a.fold_with(folder);
+ if folder.full() {
+ folder
+ } else {
+ self.b.fold_with(folder)
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Wrapper for Chain to implement ExactSizeIterator
+
+struct ChainSeq<A, B> {
+ chain: iter::Chain<A, B>,
+}
+
+impl<A, B> ChainSeq<A, B> {
+ fn new(a: A, b: B) -> ChainSeq<A, B>
+ where
+ A: ExactSizeIterator,
+ B: ExactSizeIterator<Item = A::Item>,
+ {
+ ChainSeq { chain: a.chain(b) }
+ }
+}
+
+impl<A, B> Iterator for ChainSeq<A, B>
+where
+ A: Iterator,
+ B: Iterator<Item = A::Item>,
+{
+ type Item = A::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.chain.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.chain.size_hint()
+ }
+}
+
+impl<A, B> ExactSizeIterator for ChainSeq<A, B>
+where
+ A: ExactSizeIterator,
+ B: ExactSizeIterator<Item = A::Item>,
+{
+}
+
+impl<A, B> DoubleEndedIterator for ChainSeq<A, B>
+where
+ A: DoubleEndedIterator,
+ B: DoubleEndedIterator<Item = A::Item>,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.chain.next_back()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/chunks.rs b/third_party/rust/rayon/src/iter/chunks.rs
new file mode 100644
index 0000000000..ec48278d02
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/chunks.rs
@@ -0,0 +1,226 @@
+use std::cmp::min;
+
+use super::plumbing::*;
+use super::*;
+use crate::math::div_round_up;
+
+/// `Chunks` is an iterator that groups elements of an underlying iterator.
+///
+/// This struct is created by the [`chunks()`] method on [`IndexedParallelIterator`]
+///
+/// [`chunks()`]: trait.IndexedParallelIterator.html#method.chunks
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct Chunks<I>
+where
+ I: IndexedParallelIterator,
+{
+ size: usize,
+ i: I,
+}
+
+impl<I> Chunks<I>
+where
+ I: IndexedParallelIterator,
+{
+ /// Creates a new `Chunks` iterator
+ pub(super) fn new(i: I, size: usize) -> Self {
+ Chunks { i, size }
+ }
+}
+
+impl<I> ParallelIterator for Chunks<I>
+where
+ I: IndexedParallelIterator,
+{
+ type Item = Vec<I::Item>;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Vec<I::Item>>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I> IndexedParallelIterator for Chunks<I>
+where
+ I: IndexedParallelIterator,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn len(&self) -> usize {
+ div_round_up(self.i.len(), self.size)
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ let len = self.i.len();
+ return self.i.with_producer(Callback {
+ size: self.size,
+ len,
+ callback,
+ });
+
+ struct Callback<CB> {
+ size: usize,
+ len: usize,
+ callback: CB,
+ }
+
+ impl<T, CB> ProducerCallback<T> for Callback<CB>
+ where
+ CB: ProducerCallback<Vec<T>>,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let producer = ChunkProducer::new(self.size, self.len, base, Vec::from_iter);
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+pub(super) struct ChunkProducer<P, F> {
+ chunk_size: usize,
+ len: usize,
+ base: P,
+ map: F,
+}
+
+impl<P, F> ChunkProducer<P, F> {
+ pub(super) fn new(chunk_size: usize, len: usize, base: P, map: F) -> Self {
+ Self {
+ chunk_size,
+ len,
+ base,
+ map,
+ }
+ }
+}
+
+impl<P, F, T> Producer for ChunkProducer<P, F>
+where
+ P: Producer,
+ F: Fn(P::IntoIter) -> T + Send + Clone,
+{
+ type Item = T;
+ type IntoIter = std::iter::Map<ChunkSeq<P>, F>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ let chunks = ChunkSeq {
+ chunk_size: self.chunk_size,
+ len: self.len,
+ inner: if self.len > 0 { Some(self.base) } else { None },
+ };
+ chunks.map(self.map)
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let elem_index = min(index * self.chunk_size, self.len);
+ let (left, right) = self.base.split_at(elem_index);
+ (
+ ChunkProducer {
+ chunk_size: self.chunk_size,
+ len: elem_index,
+ base: left,
+ map: self.map.clone(),
+ },
+ ChunkProducer {
+ chunk_size: self.chunk_size,
+ len: self.len - elem_index,
+ base: right,
+ map: self.map,
+ },
+ )
+ }
+
+ fn min_len(&self) -> usize {
+ div_round_up(self.base.min_len(), self.chunk_size)
+ }
+
+ fn max_len(&self) -> usize {
+ self.base.max_len() / self.chunk_size
+ }
+}
+
+pub(super) struct ChunkSeq<P> {
+ chunk_size: usize,
+ len: usize,
+ inner: Option<P>,
+}
+
+impl<P> Iterator for ChunkSeq<P>
+where
+ P: Producer,
+{
+ type Item = P::IntoIter;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let producer = self.inner.take()?;
+ if self.len > self.chunk_size {
+ let (left, right) = producer.split_at(self.chunk_size);
+ self.inner = Some(right);
+ self.len -= self.chunk_size;
+ Some(left.into_iter())
+ } else {
+ debug_assert!(self.len > 0);
+ self.len = 0;
+ Some(producer.into_iter())
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl<P> ExactSizeIterator for ChunkSeq<P>
+where
+ P: Producer,
+{
+ #[inline]
+ fn len(&self) -> usize {
+ div_round_up(self.len, self.chunk_size)
+ }
+}
+
+impl<P> DoubleEndedIterator for ChunkSeq<P>
+where
+ P: Producer,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ let producer = self.inner.take()?;
+ if self.len > self.chunk_size {
+ let mut size = self.len % self.chunk_size;
+ if size == 0 {
+ size = self.chunk_size;
+ }
+ let (left, right) = producer.split_at(self.len - size);
+ self.inner = Some(left);
+ self.len -= size;
+ Some(right.into_iter())
+ } else {
+ debug_assert!(self.len > 0);
+ self.len = 0;
+ Some(producer.into_iter())
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/cloned.rs b/third_party/rust/rayon/src/iter/cloned.rs
new file mode 100644
index 0000000000..8d5f420efa
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/cloned.rs
@@ -0,0 +1,223 @@
+use super::plumbing::*;
+use super::*;
+
+use std::iter;
+
+/// `Cloned` is an iterator that clones the elements of an underlying iterator.
+///
+/// This struct is created by the [`cloned()`] method on [`ParallelIterator`]
+///
+/// [`cloned()`]: trait.ParallelIterator.html#method.cloned
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct Cloned<I: ParallelIterator> {
+ base: I,
+}
+
+impl<I> Cloned<I>
+where
+ I: ParallelIterator,
+{
+ /// Creates a new `Cloned` iterator.
+ pub(super) fn new(base: I) -> Self {
+ Cloned { base }
+ }
+}
+
+impl<'a, T, I> ParallelIterator for Cloned<I>
+where
+ I: ParallelIterator<Item = &'a T>,
+ T: 'a + Clone + Send + Sync,
+{
+ type Item = T;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = ClonedConsumer::new(consumer);
+ self.base.drive_unindexed(consumer1)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ self.base.opt_len()
+ }
+}
+
+impl<'a, T, I> IndexedParallelIterator for Cloned<I>
+where
+ I: IndexedParallelIterator<Item = &'a T>,
+ T: 'a + Clone + Send + Sync,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ let consumer1 = ClonedConsumer::new(consumer);
+ self.base.drive(consumer1)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback { callback });
+
+ struct Callback<CB> {
+ callback: CB,
+ }
+
+ impl<'a, T, CB> ProducerCallback<&'a T> for Callback<CB>
+ where
+ CB: ProducerCallback<T>,
+ T: 'a + Clone + Send,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = &'a T>,
+ {
+ let producer = ClonedProducer { base };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+
+struct ClonedProducer<P> {
+ base: P,
+}
+
+impl<'a, T, P> Producer for ClonedProducer<P>
+where
+ P: Producer<Item = &'a T>,
+ T: 'a + Clone,
+{
+ type Item = T;
+ type IntoIter = iter::Cloned<P::IntoIter>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.base.into_iter().cloned()
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(index);
+ (
+ ClonedProducer { base: left },
+ ClonedProducer { base: right },
+ )
+ }
+
+ fn fold_with<F>(self, folder: F) -> F
+ where
+ F: Folder<Self::Item>,
+ {
+ self.base.fold_with(ClonedFolder { base: folder }).base
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct ClonedConsumer<C> {
+ base: C,
+}
+
+impl<C> ClonedConsumer<C> {
+ fn new(base: C) -> Self {
+ ClonedConsumer { base }
+ }
+}
+
+impl<'a, T, C> Consumer<&'a T> for ClonedConsumer<C>
+where
+ C: Consumer<T>,
+ T: 'a + Clone,
+{
+ type Folder = ClonedFolder<C::Folder>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ ClonedConsumer::new(left),
+ ClonedConsumer::new(right),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ ClonedFolder {
+ base: self.base.into_folder(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'a, T, C> UnindexedConsumer<&'a T> for ClonedConsumer<C>
+where
+ C: UnindexedConsumer<T>,
+ T: 'a + Clone,
+{
+ fn split_off_left(&self) -> Self {
+ ClonedConsumer::new(self.base.split_off_left())
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct ClonedFolder<F> {
+ base: F,
+}
+
+impl<'a, T, F> Folder<&'a T> for ClonedFolder<F>
+where
+ F: Folder<T>,
+ T: 'a + Clone,
+{
+ type Result = F::Result;
+
+ fn consume(self, item: &'a T) -> Self {
+ ClonedFolder {
+ base: self.base.consume(item.clone()),
+ }
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = &'a T>,
+ {
+ self.base = self.base.consume_iter(iter.into_iter().cloned());
+ self
+ }
+
+ fn complete(self) -> F::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/collect/consumer.rs b/third_party/rust/rayon/src/iter/collect/consumer.rs
new file mode 100644
index 0000000000..acd67dffa7
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/collect/consumer.rs
@@ -0,0 +1,186 @@
+use super::super::plumbing::*;
+use crate::SendPtr;
+use std::marker::PhantomData;
+use std::ptr;
+use std::slice;
+
+pub(super) struct CollectConsumer<'c, T: Send> {
+ /// See `CollectResult` for explanation of why this is not a slice
+ start: SendPtr<T>,
+ len: usize,
+ marker: PhantomData<&'c mut T>,
+}
+
+impl<T: Send> CollectConsumer<'_, T> {
+ /// Create a collector for `len` items in the unused capacity of the vector.
+ pub(super) fn appender(vec: &mut Vec<T>, len: usize) -> CollectConsumer<'_, T> {
+ let start = vec.len();
+ assert!(vec.capacity() - start >= len);
+
+ // SAFETY: We already made sure to have the additional space allocated.
+ // The pointer is derived from `Vec` directly, not through a `Deref`,
+ // so it has provenance over the whole allocation.
+ unsafe { CollectConsumer::new(vec.as_mut_ptr().add(start), len) }
+ }
+}
+
+impl<'c, T: Send + 'c> CollectConsumer<'c, T> {
+ /// The target memory is considered uninitialized, and will be
+ /// overwritten without reading or dropping existing values.
+ unsafe fn new(start: *mut T, len: usize) -> Self {
+ CollectConsumer {
+ start: SendPtr(start),
+ len,
+ marker: PhantomData,
+ }
+ }
+}
+
+/// CollectResult represents an initialized part of the target slice.
+///
+/// This is a proxy owner of the elements in the slice; when it drops,
+/// the elements will be dropped, unless its ownership is released before then.
+#[must_use]
+pub(super) struct CollectResult<'c, T> {
+ /// This pointer and length has the same representation as a slice,
+ /// but retains the provenance of the entire array so that we can merge
+ /// these regions together in `CollectReducer`.
+ start: SendPtr<T>,
+ total_len: usize,
+ /// The current initialized length after `start`
+ initialized_len: usize,
+ /// Lifetime invariance guarantees that the data flows from consumer to result,
+ /// especially for the `scope_fn` callback in `Collect::with_consumer`.
+ invariant_lifetime: PhantomData<&'c mut &'c mut [T]>,
+}
+
+unsafe impl<'c, T> Send for CollectResult<'c, T> where T: Send {}
+
+impl<'c, T> CollectResult<'c, T> {
+ /// The current length of the collect result
+ pub(super) fn len(&self) -> usize {
+ self.initialized_len
+ }
+
+ /// Release ownership of the slice of elements, and return the length
+ pub(super) fn release_ownership(mut self) -> usize {
+ let ret = self.initialized_len;
+ self.initialized_len = 0;
+ ret
+ }
+}
+
+impl<'c, T> Drop for CollectResult<'c, T> {
+ fn drop(&mut self) {
+ // Drop the first `self.initialized_len` elements, which have been recorded
+ // to be initialized by the folder.
+ unsafe {
+ ptr::drop_in_place(slice::from_raw_parts_mut(
+ self.start.0,
+ self.initialized_len,
+ ));
+ }
+ }
+}
+
+impl<'c, T: Send + 'c> Consumer<T> for CollectConsumer<'c, T> {
+ type Folder = CollectResult<'c, T>;
+ type Reducer = CollectReducer;
+ type Result = CollectResult<'c, T>;
+
+ fn split_at(self, index: usize) -> (Self, Self, CollectReducer) {
+ let CollectConsumer { start, len, .. } = self;
+
+ // Produce new consumers.
+ // SAFETY: This assert checks that `index` is a valid offset for `start`
+ unsafe {
+ assert!(index <= len);
+ (
+ CollectConsumer::new(start.0, index),
+ CollectConsumer::new(start.0.add(index), len - index),
+ CollectReducer,
+ )
+ }
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ // Create a result/folder that consumes values and writes them
+ // into the region after start. The initial result has length 0.
+ CollectResult {
+ start: self.start,
+ total_len: self.len,
+ initialized_len: 0,
+ invariant_lifetime: PhantomData,
+ }
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl<'c, T: Send + 'c> Folder<T> for CollectResult<'c, T> {
+ type Result = Self;
+
+ fn consume(mut self, item: T) -> Self {
+ assert!(
+ self.initialized_len < self.total_len,
+ "too many values pushed to consumer"
+ );
+
+ // SAFETY: The assert above is a bounds check for this write, and we
+ // avoid assignment here so we do not drop an uninitialized T.
+ unsafe {
+ // Write item and increase the initialized length
+ self.start.0.add(self.initialized_len).write(item);
+ self.initialized_len += 1;
+ }
+
+ self
+ }
+
+ fn complete(self) -> Self::Result {
+ // NB: We don't explicitly check that the local writes were complete,
+ // but Collect will assert the total result length in the end.
+ self
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+/// Pretend to be unindexed for `special_collect_into_vec`,
+/// but we should never actually get used that way...
+impl<'c, T: Send + 'c> UnindexedConsumer<T> for CollectConsumer<'c, T> {
+ fn split_off_left(&self) -> Self {
+ unreachable!("CollectConsumer must be indexed!")
+ }
+ fn to_reducer(&self) -> Self::Reducer {
+ CollectReducer
+ }
+}
+
+/// CollectReducer combines adjacent chunks; the result must always
+/// be contiguous so that it is one combined slice.
+pub(super) struct CollectReducer;
+
+impl<'c, T> Reducer<CollectResult<'c, T>> for CollectReducer {
+ fn reduce(
+ self,
+ mut left: CollectResult<'c, T>,
+ right: CollectResult<'c, T>,
+ ) -> CollectResult<'c, T> {
+ // Merge if the CollectResults are adjacent and in left to right order
+ // else: drop the right piece now and total length will end up short in the end,
+ // when the correctness of the collected result is asserted.
+ unsafe {
+ let left_end = left.start.0.add(left.initialized_len);
+ if left_end == right.start.0 {
+ left.total_len += right.total_len;
+ left.initialized_len += right.release_ownership();
+ }
+ left
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/collect/mod.rs b/third_party/rust/rayon/src/iter/collect/mod.rs
new file mode 100644
index 0000000000..4044a685b8
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/collect/mod.rs
@@ -0,0 +1,116 @@
+use super::{IndexedParallelIterator, ParallelIterator};
+
+mod consumer;
+use self::consumer::CollectConsumer;
+use self::consumer::CollectResult;
+use super::unzip::unzip_indexed;
+
+mod test;
+
+/// Collects the results of the exact iterator into the specified vector.
+///
+/// This is called by `IndexedParallelIterator::collect_into_vec`.
+pub(super) fn collect_into_vec<I, T>(pi: I, v: &mut Vec<T>)
+where
+ I: IndexedParallelIterator<Item = T>,
+ T: Send,
+{
+ v.truncate(0); // clear any old data
+ let len = pi.len();
+ collect_with_consumer(v, len, |consumer| pi.drive(consumer));
+}
+
+/// Collects the results of the iterator into the specified vector.
+///
+/// Technically, this only works for `IndexedParallelIterator`, but we're faking a
+/// bit of specialization here until Rust can do that natively. Callers are
+/// using `opt_len` to find the length before calling this, and only exact
+/// iterators will return anything but `None` there.
+///
+/// Since the type system doesn't understand that contract, we have to allow
+/// *any* `ParallelIterator` here, and `CollectConsumer` has to also implement
+/// `UnindexedConsumer`. That implementation panics `unreachable!` in case
+/// there's a bug where we actually do try to use this unindexed.
+pub(super) fn special_extend<I, T>(pi: I, len: usize, v: &mut Vec<T>)
+where
+ I: ParallelIterator<Item = T>,
+ T: Send,
+{
+ collect_with_consumer(v, len, |consumer| pi.drive_unindexed(consumer));
+}
+
+/// Unzips the results of the exact iterator into the specified vectors.
+///
+/// This is called by `IndexedParallelIterator::unzip_into_vecs`.
+pub(super) fn unzip_into_vecs<I, A, B>(pi: I, left: &mut Vec<A>, right: &mut Vec<B>)
+where
+ I: IndexedParallelIterator<Item = (A, B)>,
+ A: Send,
+ B: Send,
+{
+ // clear any old data
+ left.truncate(0);
+ right.truncate(0);
+
+ let len = pi.len();
+ collect_with_consumer(right, len, |right_consumer| {
+ let mut right_result = None;
+ collect_with_consumer(left, len, |left_consumer| {
+ let (left_r, right_r) = unzip_indexed(pi, left_consumer, right_consumer);
+ right_result = Some(right_r);
+ left_r
+ });
+ right_result.unwrap()
+ });
+}
+
+/// Create a consumer on the slice of memory we are collecting into.
+///
+/// The consumer needs to be used inside the scope function, and the
+/// complete collect result passed back.
+///
+/// This method will verify the collect result, and panic if the slice
+/// was not fully written into. Otherwise, in the successful case,
+/// the vector is complete with the collected result.
+fn collect_with_consumer<T, F>(vec: &mut Vec<T>, len: usize, scope_fn: F)
+where
+ T: Send,
+ F: FnOnce(CollectConsumer<'_, T>) -> CollectResult<'_, T>,
+{
+ // Reserve space for `len` more elements in the vector,
+ vec.reserve(len);
+
+ // Create the consumer and run the callback for collection.
+ let result = scope_fn(CollectConsumer::appender(vec, len));
+
+ // The `CollectResult` represents a contiguous part of the slice, that has
+ // been written to. On unwind here, the `CollectResult` will be dropped. If
+ // some producers on the way did not produce enough elements, partial
+ // `CollectResult`s may have been dropped without being reduced to the final
+ // result, and we will see that as the length coming up short.
+ //
+ // Here, we assert that added length is fully initialized. This is checked
+ // by the following assert, which verifies if a complete `CollectResult`
+ // was produced; if the length is correct, it is necessarily covering the
+ // target slice. Since we know that the consumer cannot have escaped from
+ // `drive` (by parametricity, essentially), we know that any stores that
+ // will happen, have happened. Unless some code is buggy, that means we
+ // should have seen `len` total writes.
+ let actual_writes = result.len();
+ assert!(
+ actual_writes == len,
+ "expected {} total writes, but got {}",
+ len,
+ actual_writes
+ );
+
+ // Release the result's mutable borrow and "proxy ownership"
+ // of the elements, before the vector takes it over.
+ result.release_ownership();
+
+ let new_len = vec.len() + len;
+
+ unsafe {
+ vec.set_len(new_len);
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/collect/test.rs b/third_party/rust/rayon/src/iter/collect/test.rs
new file mode 100644
index 0000000000..b5f676f5de
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/collect/test.rs
@@ -0,0 +1,371 @@
+#![cfg(test)]
+#![allow(unused_assignments)]
+
+// These tests are primarily targeting "abusive" producers that will
+// try to drive the "collect consumer" incorrectly. These should
+// result in panics.
+
+use super::collect_with_consumer;
+use crate::iter::plumbing::*;
+use rayon_core::join;
+
+use std::fmt;
+use std::panic;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::thread::Result as ThreadResult;
+
+/// Promises to produce 2 items, but then produces 3. Does not do any
+/// splits at all.
+#[test]
+#[should_panic(expected = "too many values")]
+fn produce_too_many_items() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 2, |consumer| {
+ let mut folder = consumer.into_folder();
+ folder = folder.consume(22);
+ folder = folder.consume(23);
+ folder = folder.consume(24);
+ unreachable!("folder does not complete")
+ });
+}
+
+/// Produces fewer items than promised. Does not do any
+/// splits at all.
+#[test]
+#[should_panic(expected = "expected 5 total writes, but got 2")]
+fn produce_fewer_items() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 5, |consumer| {
+ let mut folder = consumer.into_folder();
+ folder = folder.consume(22);
+ folder = folder.consume(23);
+ folder.complete()
+ });
+}
+
+// Complete is not called by the consumer. Hence,the collection vector is not fully initialized.
+#[test]
+#[should_panic(expected = "expected 4 total writes, but got 2")]
+fn left_produces_items_with_no_complete() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let mut left_folder = left_consumer.into_folder();
+ let mut right_folder = right_consumer.into_folder();
+ left_folder = left_folder.consume(0).consume(1);
+ right_folder = right_folder.consume(2).consume(3);
+ right_folder.complete()
+ });
+}
+
+// Complete is not called by the right consumer. Hence,the
+// collection vector is not fully initialized.
+#[test]
+#[should_panic(expected = "expected 4 total writes, but got 2")]
+fn right_produces_items_with_no_complete() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let mut left_folder = left_consumer.into_folder();
+ let mut right_folder = right_consumer.into_folder();
+ left_folder = left_folder.consume(0).consume(1);
+ right_folder = right_folder.consume(2).consume(3);
+ left_folder.complete()
+ });
+}
+
+// Complete is not called by the consumer. Hence,the collection vector is not fully initialized.
+#[test]
+fn produces_items_with_no_complete() {
+ let counter = DropCounter::default();
+ let mut v = vec![];
+ let panic_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+ collect_with_consumer(&mut v, 2, |consumer| {
+ let mut folder = consumer.into_folder();
+ folder = folder.consume(counter.element());
+ folder = folder.consume(counter.element());
+ panic!("folder does not complete");
+ });
+ }));
+ assert!(v.is_empty());
+ assert_is_panic_with_message(&panic_result, "folder does not complete");
+ counter.assert_drop_count();
+}
+
+// The left consumer produces too many items while the right
+// consumer produces correct number.
+#[test]
+#[should_panic(expected = "too many values")]
+fn left_produces_too_many_items() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let mut left_folder = left_consumer.into_folder();
+ let mut right_folder = right_consumer.into_folder();
+ left_folder = left_folder.consume(0).consume(1).consume(2);
+ right_folder = right_folder.consume(2).consume(3);
+ let _ = right_folder.complete();
+ unreachable!("folder does not complete");
+ });
+}
+
+// The right consumer produces too many items while the left
+// consumer produces correct number.
+#[test]
+#[should_panic(expected = "too many values")]
+fn right_produces_too_many_items() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let mut left_folder = left_consumer.into_folder();
+ let mut right_folder = right_consumer.into_folder();
+ left_folder = left_folder.consume(0).consume(1);
+ right_folder = right_folder.consume(2).consume(3).consume(4);
+ let _ = left_folder.complete();
+ unreachable!("folder does not complete");
+ });
+}
+
+// The left consumer produces fewer items while the right
+// consumer produces correct number.
+#[test]
+#[should_panic(expected = "expected 4 total writes, but got 1")]
+fn left_produces_fewer_items() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let reducer = consumer.to_reducer();
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let mut left_folder = left_consumer.into_folder();
+ let mut right_folder = right_consumer.into_folder();
+ left_folder = left_folder.consume(0);
+ right_folder = right_folder.consume(2).consume(3);
+ let left_result = left_folder.complete();
+ let right_result = right_folder.complete();
+ reducer.reduce(left_result, right_result)
+ });
+}
+
+// The left and right consumer produce the correct number but
+// only left result is returned
+#[test]
+#[should_panic(expected = "expected 4 total writes, but got 2")]
+fn only_left_result() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let mut left_folder = left_consumer.into_folder();
+ let mut right_folder = right_consumer.into_folder();
+ left_folder = left_folder.consume(0).consume(1);
+ right_folder = right_folder.consume(2).consume(3);
+ let left_result = left_folder.complete();
+ let _ = right_folder.complete();
+ left_result
+ });
+}
+
+// The left and right consumer produce the correct number but
+// only right result is returned
+#[test]
+#[should_panic(expected = "expected 4 total writes, but got 2")]
+fn only_right_result() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let mut left_folder = left_consumer.into_folder();
+ let mut right_folder = right_consumer.into_folder();
+ left_folder = left_folder.consume(0).consume(1);
+ right_folder = right_folder.consume(2).consume(3);
+ let _ = left_folder.complete();
+ right_folder.complete()
+ });
+}
+
+// The left and right consumer produce the correct number but reduce
+// in the wrong order.
+#[test]
+#[should_panic(expected = "expected 4 total writes, but got 2")]
+fn reducer_does_not_preserve_order() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let reducer = consumer.to_reducer();
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let mut left_folder = left_consumer.into_folder();
+ let mut right_folder = right_consumer.into_folder();
+ left_folder = left_folder.consume(0).consume(1);
+ right_folder = right_folder.consume(2).consume(3);
+ let left_result = left_folder.complete();
+ let right_result = right_folder.complete();
+ reducer.reduce(right_result, left_result)
+ });
+}
+
+// The right consumer produces fewer items while the left
+// consumer produces correct number.
+#[test]
+#[should_panic(expected = "expected 4 total writes, but got 3")]
+fn right_produces_fewer_items() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let reducer = consumer.to_reducer();
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let mut left_folder = left_consumer.into_folder();
+ let mut right_folder = right_consumer.into_folder();
+ left_folder = left_folder.consume(0).consume(1);
+ right_folder = right_folder.consume(2);
+ let left_result = left_folder.complete();
+ let right_result = right_folder.complete();
+ reducer.reduce(left_result, right_result)
+ });
+}
+
+// The left consumer panics and the right stops short, like `panic_fuse()`.
+// We should get the left panic without finishing `collect_with_consumer`.
+#[test]
+#[should_panic(expected = "left consumer panic")]
+fn left_panics() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let reducer = consumer.to_reducer();
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let (left_result, right_result) = join(
+ || {
+ let mut left_folder = left_consumer.into_folder();
+ left_folder = left_folder.consume(0);
+ panic!("left consumer panic");
+ },
+ || {
+ let mut right_folder = right_consumer.into_folder();
+ right_folder = right_folder.consume(2);
+ right_folder.complete() // early return
+ },
+ );
+ reducer.reduce(left_result, right_result)
+ });
+ unreachable!();
+}
+
+// The right consumer panics and the left stops short, like `panic_fuse()`.
+// We should get the right panic without finishing `collect_with_consumer`.
+#[test]
+#[should_panic(expected = "right consumer panic")]
+fn right_panics() {
+ let mut v = vec![];
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let reducer = consumer.to_reducer();
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let (left_result, right_result) = join(
+ || {
+ let mut left_folder = left_consumer.into_folder();
+ left_folder = left_folder.consume(0);
+ left_folder.complete() // early return
+ },
+ || {
+ let mut right_folder = right_consumer.into_folder();
+ right_folder = right_folder.consume(2);
+ panic!("right consumer panic");
+ },
+ );
+ reducer.reduce(left_result, right_result)
+ });
+ unreachable!();
+}
+
+// The left consumer produces fewer items while the right
+// consumer produces correct number; check that created elements are dropped
+#[test]
+fn left_produces_fewer_items_drops() {
+ let counter = DropCounter::default();
+ let mut v = vec![];
+ let panic_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+ collect_with_consumer(&mut v, 4, |consumer| {
+ let reducer = consumer.to_reducer();
+ let (left_consumer, right_consumer, _) = consumer.split_at(2);
+ let mut left_folder = left_consumer.into_folder();
+ let mut right_folder = right_consumer.into_folder();
+ left_folder = left_folder.consume(counter.element());
+ right_folder = right_folder
+ .consume(counter.element())
+ .consume(counter.element());
+ let left_result = left_folder.complete();
+ let right_result = right_folder.complete();
+ reducer.reduce(left_result, right_result)
+ });
+ }));
+ assert!(v.is_empty());
+ assert_is_panic_with_message(&panic_result, "expected 4 total writes, but got 1");
+ counter.assert_drop_count();
+}
+
+/// This counter can create elements, and then count and verify
+/// the number of which have actually been dropped again.
+#[derive(Default)]
+struct DropCounter {
+ created: AtomicUsize,
+ dropped: AtomicUsize,
+}
+
+struct Element<'a>(&'a AtomicUsize);
+
+impl DropCounter {
+ fn created(&self) -> usize {
+ self.created.load(Ordering::SeqCst)
+ }
+
+ fn dropped(&self) -> usize {
+ self.dropped.load(Ordering::SeqCst)
+ }
+
+ fn element(&self) -> Element<'_> {
+ self.created.fetch_add(1, Ordering::SeqCst);
+ Element(&self.dropped)
+ }
+
+ fn assert_drop_count(&self) {
+ assert_eq!(
+ self.created(),
+ self.dropped(),
+ "Expected {} dropped elements, but found {}",
+ self.created(),
+ self.dropped()
+ );
+ }
+}
+
+impl<'a> Drop for Element<'a> {
+ fn drop(&mut self) {
+ self.0.fetch_add(1, Ordering::SeqCst);
+ }
+}
+
+/// Assert that the result from catch_unwind is a panic that contains expected message
+fn assert_is_panic_with_message<T>(result: &ThreadResult<T>, expected: &str)
+where
+ T: fmt::Debug,
+{
+ match result {
+ Ok(value) => {
+ panic!(
+ "assertion failure: Expected panic, got successful {:?}",
+ value
+ );
+ }
+ Err(error) => {
+ let message_str = error.downcast_ref::<&'static str>().cloned();
+ let message_string = error.downcast_ref::<String>().map(String::as_str);
+ if let Some(message) = message_str.or(message_string) {
+ if !message.contains(expected) {
+ panic!(
+ "assertion failure: Expected {:?}, but found panic with {:?}",
+ expected, message
+ );
+ }
+ // assertion passes
+ } else {
+ panic!(
+ "assertion failure: Expected {:?}, but found panic with unknown value",
+ expected
+ );
+ }
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/copied.rs b/third_party/rust/rayon/src/iter/copied.rs
new file mode 100644
index 0000000000..12c9c5b5bf
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/copied.rs
@@ -0,0 +1,223 @@
+use super::plumbing::*;
+use super::*;
+
+use std::iter;
+
+/// `Copied` is an iterator that copies the elements of an underlying iterator.
+///
+/// This struct is created by the [`copied()`] method on [`ParallelIterator`]
+///
+/// [`copied()`]: trait.ParallelIterator.html#method.copied
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct Copied<I: ParallelIterator> {
+ base: I,
+}
+
+impl<I> Copied<I>
+where
+ I: ParallelIterator,
+{
+ /// Creates a new `Copied` iterator.
+ pub(super) fn new(base: I) -> Self {
+ Copied { base }
+ }
+}
+
+impl<'a, T, I> ParallelIterator for Copied<I>
+where
+ I: ParallelIterator<Item = &'a T>,
+ T: 'a + Copy + Send + Sync,
+{
+ type Item = T;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = CopiedConsumer::new(consumer);
+ self.base.drive_unindexed(consumer1)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ self.base.opt_len()
+ }
+}
+
+impl<'a, T, I> IndexedParallelIterator for Copied<I>
+where
+ I: IndexedParallelIterator<Item = &'a T>,
+ T: 'a + Copy + Send + Sync,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ let consumer1 = CopiedConsumer::new(consumer);
+ self.base.drive(consumer1)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback { callback });
+
+ struct Callback<CB> {
+ callback: CB,
+ }
+
+ impl<'a, T, CB> ProducerCallback<&'a T> for Callback<CB>
+ where
+ CB: ProducerCallback<T>,
+ T: 'a + Copy + Send,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = &'a T>,
+ {
+ let producer = CopiedProducer { base };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+
+struct CopiedProducer<P> {
+ base: P,
+}
+
+impl<'a, T, P> Producer for CopiedProducer<P>
+where
+ P: Producer<Item = &'a T>,
+ T: 'a + Copy,
+{
+ type Item = T;
+ type IntoIter = iter::Copied<P::IntoIter>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.base.into_iter().copied()
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(index);
+ (
+ CopiedProducer { base: left },
+ CopiedProducer { base: right },
+ )
+ }
+
+ fn fold_with<F>(self, folder: F) -> F
+ where
+ F: Folder<Self::Item>,
+ {
+ self.base.fold_with(CopiedFolder { base: folder }).base
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct CopiedConsumer<C> {
+ base: C,
+}
+
+impl<C> CopiedConsumer<C> {
+ fn new(base: C) -> Self {
+ CopiedConsumer { base }
+ }
+}
+
+impl<'a, T, C> Consumer<&'a T> for CopiedConsumer<C>
+where
+ C: Consumer<T>,
+ T: 'a + Copy,
+{
+ type Folder = CopiedFolder<C::Folder>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ CopiedConsumer::new(left),
+ CopiedConsumer::new(right),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ CopiedFolder {
+ base: self.base.into_folder(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'a, T, C> UnindexedConsumer<&'a T> for CopiedConsumer<C>
+where
+ C: UnindexedConsumer<T>,
+ T: 'a + Copy,
+{
+ fn split_off_left(&self) -> Self {
+ CopiedConsumer::new(self.base.split_off_left())
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct CopiedFolder<F> {
+ base: F,
+}
+
+impl<'a, T, F> Folder<&'a T> for CopiedFolder<F>
+where
+ F: Folder<T>,
+ T: 'a + Copy,
+{
+ type Result = F::Result;
+
+ fn consume(self, &item: &'a T) -> Self {
+ CopiedFolder {
+ base: self.base.consume(item),
+ }
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = &'a T>,
+ {
+ self.base = self.base.consume_iter(iter.into_iter().copied());
+ self
+ }
+
+ fn complete(self) -> F::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/empty.rs b/third_party/rust/rayon/src/iter/empty.rs
new file mode 100644
index 0000000000..85a2e5fd93
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/empty.rs
@@ -0,0 +1,104 @@
+use crate::iter::plumbing::*;
+use crate::iter::*;
+
+use std::fmt;
+use std::marker::PhantomData;
+
+/// Creates a parallel iterator that produces nothing.
+///
+/// This admits no parallelism on its own, but it could be used for code that
+/// deals with generic parallel iterators.
+///
+/// # Examples
+///
+/// ```
+/// use rayon::prelude::*;
+/// use rayon::iter::empty;
+///
+/// let pi = (0..1234).into_par_iter()
+/// .chain(empty())
+/// .chain(1234..10_000);
+///
+/// assert_eq!(pi.count(), 10_000);
+/// ```
+pub fn empty<T: Send>() -> Empty<T> {
+ Empty {
+ marker: PhantomData,
+ }
+}
+
+/// Iterator adaptor for [the `empty()` function](fn.empty.html).
+pub struct Empty<T: Send> {
+ marker: PhantomData<T>,
+}
+
+impl<T: Send> Clone for Empty<T> {
+ fn clone(&self) -> Self {
+ empty()
+ }
+}
+
+impl<T: Send> fmt::Debug for Empty<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad("Empty")
+ }
+}
+
+impl<T: Send> ParallelIterator for Empty<T> {
+ type Item = T;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ self.drive(consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(0)
+ }
+}
+
+impl<T: Send> IndexedParallelIterator for Empty<T> {
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ consumer.into_folder().complete()
+ }
+
+ fn len(&self) -> usize {
+ 0
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ callback.callback(EmptyProducer(PhantomData))
+ }
+}
+
+/// Private empty producer
+struct EmptyProducer<T: Send>(PhantomData<T>);
+
+impl<T: Send> Producer for EmptyProducer<T> {
+ type Item = T;
+ type IntoIter = std::iter::Empty<T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ std::iter::empty()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ debug_assert_eq!(index, 0);
+ (self, EmptyProducer(PhantomData))
+ }
+
+ fn fold_with<F>(self, folder: F) -> F
+ where
+ F: Folder<Self::Item>,
+ {
+ folder
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/enumerate.rs b/third_party/rust/rayon/src/iter/enumerate.rs
new file mode 100644
index 0000000000..980ee7cc7d
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/enumerate.rs
@@ -0,0 +1,133 @@
+use super::plumbing::*;
+use super::*;
+use std::iter;
+use std::ops::Range;
+use std::usize;
+
+/// `Enumerate` is an iterator that returns the current count along with the element.
+/// This struct is created by the [`enumerate()`] method on [`IndexedParallelIterator`]
+///
+/// [`enumerate()`]: trait.IndexedParallelIterator.html#method.enumerate
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct Enumerate<I: IndexedParallelIterator> {
+ base: I,
+}
+
+impl<I> Enumerate<I>
+where
+ I: IndexedParallelIterator,
+{
+ /// Creates a new `Enumerate` iterator.
+ pub(super) fn new(base: I) -> Self {
+ Enumerate { base }
+ }
+}
+
+impl<I> ParallelIterator for Enumerate<I>
+where
+ I: IndexedParallelIterator,
+{
+ type Item = (usize, I::Item);
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I> IndexedParallelIterator for Enumerate<I>
+where
+ I: IndexedParallelIterator,
+{
+ fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
+ bridge(self, consumer)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback { callback });
+
+ struct Callback<CB> {
+ callback: CB,
+ }
+
+ impl<I, CB> ProducerCallback<I> for Callback<CB>
+ where
+ CB: ProducerCallback<(usize, I)>,
+ {
+ type Output = CB::Output;
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = I>,
+ {
+ let producer = EnumerateProducer { base, offset: 0 };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Producer implementation
+
+struct EnumerateProducer<P> {
+ base: P,
+ offset: usize,
+}
+
+impl<P> Producer for EnumerateProducer<P>
+where
+ P: Producer,
+{
+ type Item = (usize, P::Item);
+ type IntoIter = iter::Zip<Range<usize>, P::IntoIter>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ // Enumerate only works for IndexedParallelIterators. Since those
+ // have a max length of usize::MAX, their max index is
+ // usize::MAX - 1, so the range 0..usize::MAX includes all
+ // possible indices.
+ //
+ // However, we should to use a precise end to the range, otherwise
+ // reversing the iterator may have to walk back a long ways before
+ // `Zip::next_back` can produce anything.
+ let base = self.base.into_iter();
+ let end = self.offset + base.len();
+ (self.offset..end).zip(base)
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(index);
+ (
+ EnumerateProducer {
+ base: left,
+ offset: self.offset,
+ },
+ EnumerateProducer {
+ base: right,
+ offset: self.offset + index,
+ },
+ )
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/extend.rs b/third_party/rust/rayon/src/iter/extend.rs
new file mode 100644
index 0000000000..1769d476bd
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/extend.rs
@@ -0,0 +1,604 @@
+use super::noop::NoopConsumer;
+use super::plumbing::{Consumer, Folder, Reducer, UnindexedConsumer};
+use super::{IntoParallelIterator, ParallelExtend, ParallelIterator};
+
+use std::borrow::Cow;
+use std::collections::LinkedList;
+use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
+use std::collections::{BinaryHeap, VecDeque};
+use std::hash::{BuildHasher, Hash};
+
+/// Performs a generic `par_extend` by collecting to a `LinkedList<Vec<_>>` in
+/// parallel, then extending the collection sequentially.
+macro_rules! extend {
+ ($self:ident, $par_iter:ident, $extend:ident) => {
+ $extend(
+ $self,
+ $par_iter.into_par_iter().drive_unindexed(ListVecConsumer),
+ );
+ };
+}
+
+/// Computes the total length of a `LinkedList<Vec<_>>`.
+fn len<T>(list: &LinkedList<Vec<T>>) -> usize {
+ list.iter().map(Vec::len).sum()
+}
+
+struct ListVecConsumer;
+
+struct ListVecFolder<T> {
+ vec: Vec<T>,
+}
+
+impl<T: Send> Consumer<T> for ListVecConsumer {
+ type Folder = ListVecFolder<T>;
+ type Reducer = ListReducer;
+ type Result = LinkedList<Vec<T>>;
+
+ fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) {
+ (Self, Self, ListReducer)
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ ListVecFolder { vec: Vec::new() }
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl<T: Send> UnindexedConsumer<T> for ListVecConsumer {
+ fn split_off_left(&self) -> Self {
+ Self
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ ListReducer
+ }
+}
+
+impl<T> Folder<T> for ListVecFolder<T> {
+ type Result = LinkedList<Vec<T>>;
+
+ fn consume(mut self, item: T) -> Self {
+ self.vec.push(item);
+ self
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ self.vec.extend(iter);
+ self
+ }
+
+ fn complete(self) -> Self::Result {
+ let mut list = LinkedList::new();
+ if !self.vec.is_empty() {
+ list.push_back(self.vec);
+ }
+ list
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+fn heap_extend<T, Item>(heap: &mut BinaryHeap<T>, list: LinkedList<Vec<Item>>)
+where
+ BinaryHeap<T>: Extend<Item>,
+{
+ heap.reserve(len(&list));
+ for vec in list {
+ heap.extend(vec);
+ }
+}
+
+/// Extends a binary heap with items from a parallel iterator.
+impl<T> ParallelExtend<T> for BinaryHeap<T>
+where
+ T: Ord + Send,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ extend!(self, par_iter, heap_extend);
+ }
+}
+
+/// Extends a binary heap with copied items from a parallel iterator.
+impl<'a, T> ParallelExtend<&'a T> for BinaryHeap<T>
+where
+ T: 'a + Copy + Ord + Send + Sync,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = &'a T>,
+ {
+ extend!(self, par_iter, heap_extend);
+ }
+}
+
+fn btree_map_extend<K, V, Item>(map: &mut BTreeMap<K, V>, list: LinkedList<Vec<Item>>)
+where
+ BTreeMap<K, V>: Extend<Item>,
+{
+ for vec in list {
+ map.extend(vec);
+ }
+}
+
+/// Extends a B-tree map with items from a parallel iterator.
+impl<K, V> ParallelExtend<(K, V)> for BTreeMap<K, V>
+where
+ K: Ord + Send,
+ V: Send,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = (K, V)>,
+ {
+ extend!(self, par_iter, btree_map_extend);
+ }
+}
+
+/// Extends a B-tree map with copied items from a parallel iterator.
+impl<'a, K: 'a, V: 'a> ParallelExtend<(&'a K, &'a V)> for BTreeMap<K, V>
+where
+ K: Copy + Ord + Send + Sync,
+ V: Copy + Send + Sync,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = (&'a K, &'a V)>,
+ {
+ extend!(self, par_iter, btree_map_extend);
+ }
+}
+
+fn btree_set_extend<T, Item>(set: &mut BTreeSet<T>, list: LinkedList<Vec<Item>>)
+where
+ BTreeSet<T>: Extend<Item>,
+{
+ for vec in list {
+ set.extend(vec);
+ }
+}
+
+/// Extends a B-tree set with items from a parallel iterator.
+impl<T> ParallelExtend<T> for BTreeSet<T>
+where
+ T: Ord + Send,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ extend!(self, par_iter, btree_set_extend);
+ }
+}
+
+/// Extends a B-tree set with copied items from a parallel iterator.
+impl<'a, T> ParallelExtend<&'a T> for BTreeSet<T>
+where
+ T: 'a + Copy + Ord + Send + Sync,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = &'a T>,
+ {
+ extend!(self, par_iter, btree_set_extend);
+ }
+}
+
+fn hash_map_extend<K, V, S, Item>(map: &mut HashMap<K, V, S>, list: LinkedList<Vec<Item>>)
+where
+ HashMap<K, V, S>: Extend<Item>,
+ K: Eq + Hash,
+ S: BuildHasher,
+{
+ map.reserve(len(&list));
+ for vec in list {
+ map.extend(vec);
+ }
+}
+
+/// Extends a hash map with items from a parallel iterator.
+impl<K, V, S> ParallelExtend<(K, V)> for HashMap<K, V, S>
+where
+ K: Eq + Hash + Send,
+ V: Send,
+ S: BuildHasher + Send,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = (K, V)>,
+ {
+ // See the map_collect benchmarks in rayon-demo for different strategies.
+ extend!(self, par_iter, hash_map_extend);
+ }
+}
+
+/// Extends a hash map with copied items from a parallel iterator.
+impl<'a, K: 'a, V: 'a, S> ParallelExtend<(&'a K, &'a V)> for HashMap<K, V, S>
+where
+ K: Copy + Eq + Hash + Send + Sync,
+ V: Copy + Send + Sync,
+ S: BuildHasher + Send,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = (&'a K, &'a V)>,
+ {
+ extend!(self, par_iter, hash_map_extend);
+ }
+}
+
+fn hash_set_extend<T, S, Item>(set: &mut HashSet<T, S>, list: LinkedList<Vec<Item>>)
+where
+ HashSet<T, S>: Extend<Item>,
+ T: Eq + Hash,
+ S: BuildHasher,
+{
+ set.reserve(len(&list));
+ for vec in list {
+ set.extend(vec);
+ }
+}
+
+/// Extends a hash set with items from a parallel iterator.
+impl<T, S> ParallelExtend<T> for HashSet<T, S>
+where
+ T: Eq + Hash + Send,
+ S: BuildHasher + Send,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ extend!(self, par_iter, hash_set_extend);
+ }
+}
+
+/// Extends a hash set with copied items from a parallel iterator.
+impl<'a, T, S> ParallelExtend<&'a T> for HashSet<T, S>
+where
+ T: 'a + Copy + Eq + Hash + Send + Sync,
+ S: BuildHasher + Send,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = &'a T>,
+ {
+ extend!(self, par_iter, hash_set_extend);
+ }
+}
+
+/// Extends a linked list with items from a parallel iterator.
+impl<T> ParallelExtend<T> for LinkedList<T>
+where
+ T: Send,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ let mut list = par_iter.into_par_iter().drive_unindexed(ListConsumer);
+ self.append(&mut list);
+ }
+}
+
+/// Extends a linked list with copied items from a parallel iterator.
+impl<'a, T> ParallelExtend<&'a T> for LinkedList<T>
+where
+ T: 'a + Copy + Send + Sync,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = &'a T>,
+ {
+ self.par_extend(par_iter.into_par_iter().copied())
+ }
+}
+
+struct ListConsumer;
+
+struct ListFolder<T> {
+ list: LinkedList<T>,
+}
+
+struct ListReducer;
+
+impl<T: Send> Consumer<T> for ListConsumer {
+ type Folder = ListFolder<T>;
+ type Reducer = ListReducer;
+ type Result = LinkedList<T>;
+
+ fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) {
+ (Self, Self, ListReducer)
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ ListFolder {
+ list: LinkedList::new(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl<T: Send> UnindexedConsumer<T> for ListConsumer {
+ fn split_off_left(&self) -> Self {
+ Self
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ ListReducer
+ }
+}
+
+impl<T> Folder<T> for ListFolder<T> {
+ type Result = LinkedList<T>;
+
+ fn consume(mut self, item: T) -> Self {
+ self.list.push_back(item);
+ self
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ self.list.extend(iter);
+ self
+ }
+
+ fn complete(self) -> Self::Result {
+ self.list
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl<T> Reducer<LinkedList<T>> for ListReducer {
+ fn reduce(self, mut left: LinkedList<T>, mut right: LinkedList<T>) -> LinkedList<T> {
+ left.append(&mut right);
+ left
+ }
+}
+
+fn flat_string_extend(string: &mut String, list: LinkedList<String>) {
+ string.reserve(list.iter().map(String::len).sum());
+ string.extend(list);
+}
+
+/// Extends a string with characters from a parallel iterator.
+impl ParallelExtend<char> for String {
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = char>,
+ {
+ // This is like `extend`, but `Vec<char>` is less efficient to deal
+ // with than `String`, so instead collect to `LinkedList<String>`.
+ let list = par_iter.into_par_iter().drive_unindexed(ListStringConsumer);
+ flat_string_extend(self, list);
+ }
+}
+
+/// Extends a string with copied characters from a parallel iterator.
+impl<'a> ParallelExtend<&'a char> for String {
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = &'a char>,
+ {
+ self.par_extend(par_iter.into_par_iter().copied())
+ }
+}
+
+struct ListStringConsumer;
+
+struct ListStringFolder {
+ string: String,
+}
+
+impl Consumer<char> for ListStringConsumer {
+ type Folder = ListStringFolder;
+ type Reducer = ListReducer;
+ type Result = LinkedList<String>;
+
+ fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) {
+ (Self, Self, ListReducer)
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ ListStringFolder {
+ string: String::new(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl UnindexedConsumer<char> for ListStringConsumer {
+ fn split_off_left(&self) -> Self {
+ Self
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ ListReducer
+ }
+}
+
+impl Folder<char> for ListStringFolder {
+ type Result = LinkedList<String>;
+
+ fn consume(mut self, item: char) -> Self {
+ self.string.push(item);
+ self
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = char>,
+ {
+ self.string.extend(iter);
+ self
+ }
+
+ fn complete(self) -> Self::Result {
+ let mut list = LinkedList::new();
+ if !self.string.is_empty() {
+ list.push_back(self.string);
+ }
+ list
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+fn string_extend<Item>(string: &mut String, list: LinkedList<Vec<Item>>)
+where
+ String: Extend<Item>,
+ Item: AsRef<str>,
+{
+ let len = list.iter().flatten().map(Item::as_ref).map(str::len).sum();
+ string.reserve(len);
+ for vec in list {
+ string.extend(vec);
+ }
+}
+
+/// Extends a string with string slices from a parallel iterator.
+impl<'a> ParallelExtend<&'a str> for String {
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = &'a str>,
+ {
+ extend!(self, par_iter, string_extend);
+ }
+}
+
+/// Extends a string with strings from a parallel iterator.
+impl ParallelExtend<String> for String {
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = String>,
+ {
+ extend!(self, par_iter, string_extend);
+ }
+}
+
+/// Extends a string with string slices from a parallel iterator.
+impl<'a> ParallelExtend<Cow<'a, str>> for String {
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = Cow<'a, str>>,
+ {
+ extend!(self, par_iter, string_extend);
+ }
+}
+
+fn deque_extend<T, Item>(deque: &mut VecDeque<T>, list: LinkedList<Vec<Item>>)
+where
+ VecDeque<T>: Extend<Item>,
+{
+ deque.reserve(len(&list));
+ for vec in list {
+ deque.extend(vec);
+ }
+}
+
+/// Extends a deque with items from a parallel iterator.
+impl<T> ParallelExtend<T> for VecDeque<T>
+where
+ T: Send,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ extend!(self, par_iter, deque_extend);
+ }
+}
+
+/// Extends a deque with copied items from a parallel iterator.
+impl<'a, T> ParallelExtend<&'a T> for VecDeque<T>
+where
+ T: 'a + Copy + Send + Sync,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = &'a T>,
+ {
+ extend!(self, par_iter, deque_extend);
+ }
+}
+
+fn vec_append<T>(vec: &mut Vec<T>, list: LinkedList<Vec<T>>) {
+ vec.reserve(len(&list));
+ for mut other in list {
+ vec.append(&mut other);
+ }
+}
+
+/// Extends a vector with items from a parallel iterator.
+impl<T> ParallelExtend<T> for Vec<T>
+where
+ T: Send,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ // See the vec_collect benchmarks in rayon-demo for different strategies.
+ let par_iter = par_iter.into_par_iter();
+ match par_iter.opt_len() {
+ Some(len) => {
+ // When Rust gets specialization, we can get here for indexed iterators
+ // without relying on `opt_len`. Until then, `special_extend()` fakes
+ // an unindexed mode on the promise that `opt_len()` is accurate.
+ super::collect::special_extend(par_iter, len, self);
+ }
+ None => {
+ // This works like `extend`, but `Vec::append` is more efficient.
+ let list = par_iter.drive_unindexed(ListVecConsumer);
+ vec_append(self, list);
+ }
+ }
+ }
+}
+
+/// Extends a vector with copied items from a parallel iterator.
+impl<'a, T> ParallelExtend<&'a T> for Vec<T>
+where
+ T: 'a + Copy + Send + Sync,
+{
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = &'a T>,
+ {
+ self.par_extend(par_iter.into_par_iter().copied())
+ }
+}
+
+/// Collapses all unit items from a parallel iterator into one.
+impl ParallelExtend<()> for () {
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = ()>,
+ {
+ par_iter.into_par_iter().drive_unindexed(NoopConsumer)
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/filter.rs b/third_party/rust/rayon/src/iter/filter.rs
new file mode 100644
index 0000000000..e1b74ba520
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/filter.rs
@@ -0,0 +1,141 @@
+use super::plumbing::*;
+use super::*;
+
+use std::fmt::{self, Debug};
+
+/// `Filter` takes a predicate `filter_op` and filters out elements that match.
+/// This struct is created by the [`filter()`] method on [`ParallelIterator`]
+///
+/// [`filter()`]: trait.ParallelIterator.html#method.filter
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct Filter<I: ParallelIterator, P> {
+ base: I,
+ filter_op: P,
+}
+
+impl<I: ParallelIterator + Debug, P> Debug for Filter<I, P> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Filter").field("base", &self.base).finish()
+ }
+}
+
+impl<I, P> Filter<I, P>
+where
+ I: ParallelIterator,
+{
+ /// Creates a new `Filter` iterator.
+ pub(super) fn new(base: I, filter_op: P) -> Self {
+ Filter { base, filter_op }
+ }
+}
+
+impl<I, P> ParallelIterator for Filter<I, P>
+where
+ I: ParallelIterator,
+ P: Fn(&I::Item) -> bool + Sync + Send,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = FilterConsumer::new(consumer, &self.filter_op);
+ self.base.drive_unindexed(consumer1)
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct FilterConsumer<'p, C, P> {
+ base: C,
+ filter_op: &'p P,
+}
+
+impl<'p, C, P> FilterConsumer<'p, C, P> {
+ fn new(base: C, filter_op: &'p P) -> Self {
+ FilterConsumer { base, filter_op }
+ }
+}
+
+impl<'p, T, C, P: 'p> Consumer<T> for FilterConsumer<'p, C, P>
+where
+ C: Consumer<T>,
+ P: Fn(&T) -> bool + Sync,
+{
+ type Folder = FilterFolder<'p, C::Folder, P>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, C::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ FilterConsumer::new(left, self.filter_op),
+ FilterConsumer::new(right, self.filter_op),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ FilterFolder {
+ base: self.base.into_folder(),
+ filter_op: self.filter_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'p, T, C, P: 'p> UnindexedConsumer<T> for FilterConsumer<'p, C, P>
+where
+ C: UnindexedConsumer<T>,
+ P: Fn(&T) -> bool + Sync,
+{
+ fn split_off_left(&self) -> Self {
+ FilterConsumer::new(self.base.split_off_left(), self.filter_op)
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct FilterFolder<'p, C, P> {
+ base: C,
+ filter_op: &'p P,
+}
+
+impl<'p, C, P, T> Folder<T> for FilterFolder<'p, C, P>
+where
+ C: Folder<T>,
+ P: Fn(&T) -> bool + 'p,
+{
+ type Result = C::Result;
+
+ fn consume(self, item: T) -> Self {
+ let filter_op = self.filter_op;
+ if filter_op(&item) {
+ let base = self.base.consume(item);
+ FilterFolder { base, filter_op }
+ } else {
+ self
+ }
+ }
+
+ // This cannot easily specialize `consume_iter` to be better than
+ // the default, because that requires checking `self.base.full()`
+ // during a call to `self.base.consume_iter()`. (#632)
+
+ fn complete(self) -> Self::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/filter_map.rs b/third_party/rust/rayon/src/iter/filter_map.rs
new file mode 100644
index 0000000000..db1c7e3f02
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/filter_map.rs
@@ -0,0 +1,142 @@
+use super::plumbing::*;
+use super::*;
+
+use std::fmt::{self, Debug};
+
+/// `FilterMap` creates an iterator that uses `filter_op` to both filter and map elements.
+/// This struct is created by the [`filter_map()`] method on [`ParallelIterator`].
+///
+/// [`filter_map()`]: trait.ParallelIterator.html#method.filter_map
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct FilterMap<I: ParallelIterator, P> {
+ base: I,
+ filter_op: P,
+}
+
+impl<I: ParallelIterator + Debug, P> Debug for FilterMap<I, P> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FilterMap")
+ .field("base", &self.base)
+ .finish()
+ }
+}
+
+impl<I: ParallelIterator, P> FilterMap<I, P> {
+ /// Creates a new `FilterMap` iterator.
+ pub(super) fn new(base: I, filter_op: P) -> Self {
+ FilterMap { base, filter_op }
+ }
+}
+
+impl<I, P, R> ParallelIterator for FilterMap<I, P>
+where
+ I: ParallelIterator,
+ P: Fn(I::Item) -> Option<R> + Sync + Send,
+ R: Send,
+{
+ type Item = R;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer = FilterMapConsumer::new(consumer, &self.filter_op);
+ self.base.drive_unindexed(consumer)
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct FilterMapConsumer<'p, C, P> {
+ base: C,
+ filter_op: &'p P,
+}
+
+impl<'p, C, P: 'p> FilterMapConsumer<'p, C, P> {
+ fn new(base: C, filter_op: &'p P) -> Self {
+ FilterMapConsumer { base, filter_op }
+ }
+}
+
+impl<'p, T, U, C, P> Consumer<T> for FilterMapConsumer<'p, C, P>
+where
+ C: Consumer<U>,
+ P: Fn(T) -> Option<U> + Sync + 'p,
+{
+ type Folder = FilterMapFolder<'p, C::Folder, P>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ FilterMapConsumer::new(left, self.filter_op),
+ FilterMapConsumer::new(right, self.filter_op),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ let base = self.base.into_folder();
+ FilterMapFolder {
+ base,
+ filter_op: self.filter_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'p, T, U, C, P> UnindexedConsumer<T> for FilterMapConsumer<'p, C, P>
+where
+ C: UnindexedConsumer<U>,
+ P: Fn(T) -> Option<U> + Sync + 'p,
+{
+ fn split_off_left(&self) -> Self {
+ FilterMapConsumer::new(self.base.split_off_left(), self.filter_op)
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct FilterMapFolder<'p, C, P> {
+ base: C,
+ filter_op: &'p P,
+}
+
+impl<'p, T, U, C, P> Folder<T> for FilterMapFolder<'p, C, P>
+where
+ C: Folder<U>,
+ P: Fn(T) -> Option<U> + Sync + 'p,
+{
+ type Result = C::Result;
+
+ fn consume(self, item: T) -> Self {
+ let filter_op = self.filter_op;
+ if let Some(mapped_item) = filter_op(item) {
+ let base = self.base.consume(mapped_item);
+ FilterMapFolder { base, filter_op }
+ } else {
+ self
+ }
+ }
+
+ // This cannot easily specialize `consume_iter` to be better than
+ // the default, because that requires checking `self.base.full()`
+ // during a call to `self.base.consume_iter()`. (#632)
+
+ fn complete(self) -> C::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/find.rs b/third_party/rust/rayon/src/iter/find.rs
new file mode 100644
index 0000000000..b16ee84466
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/find.rs
@@ -0,0 +1,120 @@
+use super::plumbing::*;
+use super::*;
+use std::sync::atomic::{AtomicBool, Ordering};
+
+pub(super) fn find<I, P>(pi: I, find_op: P) -> Option<I::Item>
+where
+ I: ParallelIterator,
+ P: Fn(&I::Item) -> bool + Sync,
+{
+ let found = AtomicBool::new(false);
+ let consumer = FindConsumer::new(&find_op, &found);
+ pi.drive_unindexed(consumer)
+}
+
+struct FindConsumer<'p, P> {
+ find_op: &'p P,
+ found: &'p AtomicBool,
+}
+
+impl<'p, P> FindConsumer<'p, P> {
+ fn new(find_op: &'p P, found: &'p AtomicBool) -> Self {
+ FindConsumer { find_op, found }
+ }
+}
+
+impl<'p, T, P: 'p> Consumer<T> for FindConsumer<'p, P>
+where
+ T: Send,
+ P: Fn(&T) -> bool + Sync,
+{
+ type Folder = FindFolder<'p, T, P>;
+ type Reducer = FindReducer;
+ type Result = Option<T>;
+
+ fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) {
+ (self.split_off_left(), self, FindReducer)
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ FindFolder {
+ find_op: self.find_op,
+ found: self.found,
+ item: None,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.found.load(Ordering::Relaxed)
+ }
+}
+
+impl<'p, T, P: 'p> UnindexedConsumer<T> for FindConsumer<'p, P>
+where
+ T: Send,
+ P: Fn(&T) -> bool + Sync,
+{
+ fn split_off_left(&self) -> Self {
+ FindConsumer::new(self.find_op, self.found)
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ FindReducer
+ }
+}
+
+struct FindFolder<'p, T, P> {
+ find_op: &'p P,
+ found: &'p AtomicBool,
+ item: Option<T>,
+}
+
+impl<'p, T, P> Folder<T> for FindFolder<'p, T, P>
+where
+ P: Fn(&T) -> bool + 'p,
+{
+ type Result = Option<T>;
+
+ fn consume(mut self, item: T) -> Self {
+ if (self.find_op)(&item) {
+ self.found.store(true, Ordering::Relaxed);
+ self.item = Some(item);
+ }
+ self
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ fn not_full<T>(found: &AtomicBool) -> impl Fn(&T) -> bool + '_ {
+ move |_| !found.load(Ordering::Relaxed)
+ }
+
+ self.item = iter
+ .into_iter()
+ // stop iterating if another thread has found something
+ .take_while(not_full(self.found))
+ .find(self.find_op);
+ if self.item.is_some() {
+ self.found.store(true, Ordering::Relaxed)
+ }
+ self
+ }
+
+ fn complete(self) -> Self::Result {
+ self.item
+ }
+
+ fn full(&self) -> bool {
+ self.found.load(Ordering::Relaxed)
+ }
+}
+
+struct FindReducer;
+
+impl<T> Reducer<Option<T>> for FindReducer {
+ fn reduce(self, left: Option<T>, right: Option<T>) -> Option<T> {
+ left.or(right)
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/find_first_last/mod.rs b/third_party/rust/rayon/src/iter/find_first_last/mod.rs
new file mode 100644
index 0000000000..e5da8f0dd8
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/find_first_last/mod.rs
@@ -0,0 +1,238 @@
+use super::plumbing::*;
+use super::*;
+use std::cell::Cell;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+#[cfg(test)]
+mod test;
+
+// The key optimization for find_first is that a consumer can stop its search if
+// some consumer to its left already found a match (and similarly for consumers
+// to the right for find_last). To make this work, all consumers need some
+// notion of their position in the data relative to other consumers, including
+// unindexed consumers that have no built-in notion of position.
+//
+// To solve this, we assign each consumer a lower and upper bound for an
+// imaginary "range" of data that it consumes. The initial consumer starts with
+// the range 0..usize::max_value(). The split divides this range in half so that
+// one resulting consumer has the range 0..(usize::max_value() / 2), and the
+// other has (usize::max_value() / 2)..usize::max_value(). Every subsequent
+// split divides the range in half again until it cannot be split anymore
+// (i.e. its length is 1), in which case the split returns two consumers with
+// the same range. In that case both consumers will continue to consume all
+// their data regardless of whether a better match is found, but the reducer
+// will still return the correct answer.
+
+#[derive(Copy, Clone)]
+enum MatchPosition {
+ Leftmost,
+ Rightmost,
+}
+
+/// Returns true if pos1 is a better match than pos2 according to MatchPosition
+#[inline]
+fn better_position(pos1: usize, pos2: usize, mp: MatchPosition) -> bool {
+ match mp {
+ MatchPosition::Leftmost => pos1 < pos2,
+ MatchPosition::Rightmost => pos1 > pos2,
+ }
+}
+
+pub(super) fn find_first<I, P>(pi: I, find_op: P) -> Option<I::Item>
+where
+ I: ParallelIterator,
+ P: Fn(&I::Item) -> bool + Sync,
+{
+ let best_found = AtomicUsize::new(usize::max_value());
+ let consumer = FindConsumer::new(&find_op, MatchPosition::Leftmost, &best_found);
+ pi.drive_unindexed(consumer)
+}
+
+pub(super) fn find_last<I, P>(pi: I, find_op: P) -> Option<I::Item>
+where
+ I: ParallelIterator,
+ P: Fn(&I::Item) -> bool + Sync,
+{
+ let best_found = AtomicUsize::new(0);
+ let consumer = FindConsumer::new(&find_op, MatchPosition::Rightmost, &best_found);
+ pi.drive_unindexed(consumer)
+}
+
+struct FindConsumer<'p, P> {
+ find_op: &'p P,
+ lower_bound: Cell<usize>,
+ upper_bound: usize,
+ match_position: MatchPosition,
+ best_found: &'p AtomicUsize,
+}
+
+impl<'p, P> FindConsumer<'p, P> {
+ fn new(find_op: &'p P, match_position: MatchPosition, best_found: &'p AtomicUsize) -> Self {
+ FindConsumer {
+ find_op,
+ lower_bound: Cell::new(0),
+ upper_bound: usize::max_value(),
+ match_position,
+ best_found,
+ }
+ }
+
+ fn current_index(&self) -> usize {
+ match self.match_position {
+ MatchPosition::Leftmost => self.lower_bound.get(),
+ MatchPosition::Rightmost => self.upper_bound,
+ }
+ }
+}
+
+impl<'p, T, P> Consumer<T> for FindConsumer<'p, P>
+where
+ T: Send,
+ P: Fn(&T) -> bool + Sync,
+{
+ type Folder = FindFolder<'p, T, P>;
+ type Reducer = FindReducer;
+ type Result = Option<T>;
+
+ fn split_at(self, _index: usize) -> (Self, Self, Self::Reducer) {
+ let dir = self.match_position;
+ (
+ self.split_off_left(),
+ self,
+ FindReducer {
+ match_position: dir,
+ },
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ FindFolder {
+ find_op: self.find_op,
+ boundary: self.current_index(),
+ match_position: self.match_position,
+ best_found: self.best_found,
+ item: None,
+ }
+ }
+
+ fn full(&self) -> bool {
+ // can stop consuming if the best found index so far is *strictly*
+ // better than anything this consumer will find
+ better_position(
+ self.best_found.load(Ordering::Relaxed),
+ self.current_index(),
+ self.match_position,
+ )
+ }
+}
+
+impl<'p, T, P> UnindexedConsumer<T> for FindConsumer<'p, P>
+where
+ T: Send,
+ P: Fn(&T) -> bool + Sync,
+{
+ fn split_off_left(&self) -> Self {
+ // Upper bound for one consumer will be lower bound for the other. This
+ // overlap is okay, because only one of the bounds will be used for
+ // comparing against best_found; the other is kept only to be able to
+ // divide the range in half.
+ //
+ // When the resolution of usize has been exhausted (i.e. when
+ // upper_bound = lower_bound), both results of this split will have the
+ // same range. When that happens, we lose the ability to tell one
+ // consumer to stop working when the other finds a better match, but the
+ // reducer ensures that the best answer is still returned (see the test
+ // above).
+ let old_lower_bound = self.lower_bound.get();
+ let median = old_lower_bound + ((self.upper_bound - old_lower_bound) / 2);
+ self.lower_bound.set(median);
+
+ FindConsumer {
+ find_op: self.find_op,
+ lower_bound: Cell::new(old_lower_bound),
+ upper_bound: median,
+ match_position: self.match_position,
+ best_found: self.best_found,
+ }
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ FindReducer {
+ match_position: self.match_position,
+ }
+ }
+}
+
+struct FindFolder<'p, T, P> {
+ find_op: &'p P,
+ boundary: usize,
+ match_position: MatchPosition,
+ best_found: &'p AtomicUsize,
+ item: Option<T>,
+}
+
+impl<'p, P: 'p + Fn(&T) -> bool, T> Folder<T> for FindFolder<'p, T, P> {
+ type Result = Option<T>;
+
+ fn consume(mut self, item: T) -> Self {
+ let found_best_in_range = match self.match_position {
+ MatchPosition::Leftmost => self.item.is_some(),
+ MatchPosition::Rightmost => false,
+ };
+
+ if !found_best_in_range && (self.find_op)(&item) {
+ // Continuously try to set best_found until we succeed or we
+ // discover a better match was already found.
+ let mut current = self.best_found.load(Ordering::Relaxed);
+ loop {
+ if better_position(current, self.boundary, self.match_position) {
+ break;
+ }
+ match self.best_found.compare_exchange_weak(
+ current,
+ self.boundary,
+ Ordering::Relaxed,
+ Ordering::Relaxed,
+ ) {
+ Ok(_) => {
+ self.item = Some(item);
+ break;
+ }
+ Err(v) => current = v,
+ }
+ }
+ }
+ self
+ }
+
+ fn complete(self) -> Self::Result {
+ self.item
+ }
+
+ fn full(&self) -> bool {
+ let found_best_in_range = match self.match_position {
+ MatchPosition::Leftmost => self.item.is_some(),
+ MatchPosition::Rightmost => false,
+ };
+
+ found_best_in_range
+ || better_position(
+ self.best_found.load(Ordering::Relaxed),
+ self.boundary,
+ self.match_position,
+ )
+ }
+}
+
+struct FindReducer {
+ match_position: MatchPosition,
+}
+
+impl<T> Reducer<Option<T>> for FindReducer {
+ fn reduce(self, left: Option<T>, right: Option<T>) -> Option<T> {
+ match self.match_position {
+ MatchPosition::Leftmost => left.or(right),
+ MatchPosition::Rightmost => right.or(left),
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/find_first_last/test.rs b/third_party/rust/rayon/src/iter/find_first_last/test.rs
new file mode 100644
index 0000000000..05271bc5b3
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/find_first_last/test.rs
@@ -0,0 +1,106 @@
+use super::*;
+use std::sync::atomic::AtomicUsize;
+
+#[test]
+fn same_range_first_consumers_return_correct_answer() {
+ let find_op = |x: &i32| x % 2 == 0;
+ let first_found = AtomicUsize::new(usize::max_value());
+ let far_right_consumer = FindConsumer::new(&find_op, MatchPosition::Leftmost, &first_found);
+
+ // We save a consumer that will be far to the right of the main consumer (and therefore not
+ // sharing an index range with that consumer) for fullness testing
+ let consumer = far_right_consumer.split_off_left();
+
+ // split until we have an indivisible range
+ let bits_in_usize = usize::min_value().count_zeros();
+
+ for _ in 0..bits_in_usize {
+ consumer.split_off_left();
+ }
+
+ let reducer = consumer.to_reducer();
+ // the left and right folders should now have the same range, having
+ // exhausted the resolution of usize
+ let left_folder = consumer.split_off_left().into_folder();
+ let right_folder = consumer.into_folder();
+
+ let left_folder = left_folder.consume(0).consume(1);
+ assert_eq!(left_folder.boundary, right_folder.boundary);
+ // expect not full even though a better match has been found because the
+ // ranges are the same
+ assert!(!right_folder.full());
+ assert!(far_right_consumer.full());
+ let right_folder = right_folder.consume(2).consume(3);
+ assert_eq!(
+ reducer.reduce(left_folder.complete(), right_folder.complete()),
+ Some(0)
+ );
+}
+
+#[test]
+fn same_range_last_consumers_return_correct_answer() {
+ let find_op = |x: &i32| x % 2 == 0;
+ let last_found = AtomicUsize::new(0);
+ let consumer = FindConsumer::new(&find_op, MatchPosition::Rightmost, &last_found);
+
+ // We save a consumer that will be far to the left of the main consumer (and therefore not
+ // sharing an index range with that consumer) for fullness testing
+ let far_left_consumer = consumer.split_off_left();
+
+ // split until we have an indivisible range
+ let bits_in_usize = usize::min_value().count_zeros();
+ for _ in 0..bits_in_usize {
+ consumer.split_off_left();
+ }
+
+ let reducer = consumer.to_reducer();
+ // due to the exact calculation in split_off_left, the very last consumer has a
+ // range of width 2, so we use the second-to-last consumer instead to get
+ // the same boundary on both folders
+ let consumer = consumer.split_off_left();
+ let left_folder = consumer.split_off_left().into_folder();
+ let right_folder = consumer.into_folder();
+ let right_folder = right_folder.consume(2).consume(3);
+ assert_eq!(left_folder.boundary, right_folder.boundary);
+ // expect not full even though a better match has been found because the
+ // ranges are the same
+ assert!(!left_folder.full());
+ assert!(far_left_consumer.full());
+ let left_folder = left_folder.consume(0).consume(1);
+ assert_eq!(
+ reducer.reduce(left_folder.complete(), right_folder.complete()),
+ Some(2)
+ );
+}
+
+// These tests requires that a folder be assigned to an iterator with more than
+// one element. We can't necessarily determine when that will happen for a given
+// input to find_first/find_last, so we test the folder directly here instead.
+#[test]
+fn find_first_folder_does_not_clobber_first_found() {
+ let best_found = AtomicUsize::new(usize::max_value());
+ let f = FindFolder {
+ find_op: &(|&_: &i32| -> bool { true }),
+ boundary: 0,
+ match_position: MatchPosition::Leftmost,
+ best_found: &best_found,
+ item: None,
+ };
+ let f = f.consume(0_i32).consume(1_i32).consume(2_i32);
+ assert!(f.full());
+ assert_eq!(f.complete(), Some(0_i32));
+}
+
+#[test]
+fn find_last_folder_yields_last_match() {
+ let best_found = AtomicUsize::new(0);
+ let f = FindFolder {
+ find_op: &(|&_: &i32| -> bool { true }),
+ boundary: 0,
+ match_position: MatchPosition::Rightmost,
+ best_found: &best_found,
+ item: None,
+ };
+ let f = f.consume(0_i32).consume(1_i32).consume(2_i32);
+ assert_eq!(f.complete(), Some(2_i32));
+}
diff --git a/third_party/rust/rayon/src/iter/flat_map.rs b/third_party/rust/rayon/src/iter/flat_map.rs
new file mode 100644
index 0000000000..f264e1e144
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/flat_map.rs
@@ -0,0 +1,154 @@
+use super::plumbing::*;
+use super::*;
+
+use std::fmt::{self, Debug};
+
+/// `FlatMap` maps each element to a parallel iterator, then flattens these iterators together.
+/// This struct is created by the [`flat_map()`] method on [`ParallelIterator`]
+///
+/// [`flat_map()`]: trait.ParallelIterator.html#method.flat_map
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct FlatMap<I: ParallelIterator, F> {
+ base: I,
+ map_op: F,
+}
+
+impl<I: ParallelIterator + Debug, F> Debug for FlatMap<I, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FlatMap").field("base", &self.base).finish()
+ }
+}
+
+impl<I: ParallelIterator, F> FlatMap<I, F> {
+ /// Creates a new `FlatMap` iterator.
+ pub(super) fn new(base: I, map_op: F) -> Self {
+ FlatMap { base, map_op }
+ }
+}
+
+impl<I, F, PI> ParallelIterator for FlatMap<I, F>
+where
+ I: ParallelIterator,
+ F: Fn(I::Item) -> PI + Sync + Send,
+ PI: IntoParallelIterator,
+{
+ type Item = PI::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer = FlatMapConsumer::new(consumer, &self.map_op);
+ self.base.drive_unindexed(consumer)
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct FlatMapConsumer<'f, C, F> {
+ base: C,
+ map_op: &'f F,
+}
+
+impl<'f, C, F> FlatMapConsumer<'f, C, F> {
+ fn new(base: C, map_op: &'f F) -> Self {
+ FlatMapConsumer { base, map_op }
+ }
+}
+
+impl<'f, T, U, C, F> Consumer<T> for FlatMapConsumer<'f, C, F>
+where
+ C: UnindexedConsumer<U::Item>,
+ F: Fn(T) -> U + Sync,
+ U: IntoParallelIterator,
+{
+ type Folder = FlatMapFolder<'f, C, F, C::Result>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, C::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ FlatMapConsumer::new(left, self.map_op),
+ FlatMapConsumer::new(right, self.map_op),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ FlatMapFolder {
+ base: self.base,
+ map_op: self.map_op,
+ previous: None,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'f, T, U, C, F> UnindexedConsumer<T> for FlatMapConsumer<'f, C, F>
+where
+ C: UnindexedConsumer<U::Item>,
+ F: Fn(T) -> U + Sync,
+ U: IntoParallelIterator,
+{
+ fn split_off_left(&self) -> Self {
+ FlatMapConsumer::new(self.base.split_off_left(), self.map_op)
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct FlatMapFolder<'f, C, F, R> {
+ base: C,
+ map_op: &'f F,
+ previous: Option<R>,
+}
+
+impl<'f, T, U, C, F> Folder<T> for FlatMapFolder<'f, C, F, C::Result>
+where
+ C: UnindexedConsumer<U::Item>,
+ F: Fn(T) -> U + Sync,
+ U: IntoParallelIterator,
+{
+ type Result = C::Result;
+
+ fn consume(self, item: T) -> Self {
+ let map_op = self.map_op;
+ let par_iter = map_op(item).into_par_iter();
+ let consumer = self.base.split_off_left();
+ let result = par_iter.drive_unindexed(consumer);
+
+ let previous = match self.previous {
+ None => Some(result),
+ Some(previous) => {
+ let reducer = self.base.to_reducer();
+ Some(reducer.reduce(previous, result))
+ }
+ };
+
+ FlatMapFolder {
+ base: self.base,
+ map_op,
+ previous,
+ }
+ }
+
+ fn complete(self) -> Self::Result {
+ match self.previous {
+ Some(previous) => previous,
+ None => self.base.into_folder().complete(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/flat_map_iter.rs b/third_party/rust/rayon/src/iter/flat_map_iter.rs
new file mode 100644
index 0000000000..c76cf68381
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/flat_map_iter.rs
@@ -0,0 +1,147 @@
+use super::plumbing::*;
+use super::*;
+
+use std::fmt::{self, Debug};
+
+/// `FlatMapIter` maps each element to a serial iterator, then flattens these iterators together.
+/// This struct is created by the [`flat_map_iter()`] method on [`ParallelIterator`]
+///
+/// [`flat_map_iter()`]: trait.ParallelIterator.html#method.flat_map_iter
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct FlatMapIter<I: ParallelIterator, F> {
+ base: I,
+ map_op: F,
+}
+
+impl<I: ParallelIterator + Debug, F> Debug for FlatMapIter<I, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FlatMapIter")
+ .field("base", &self.base)
+ .finish()
+ }
+}
+
+impl<I: ParallelIterator, F> FlatMapIter<I, F> {
+ /// Creates a new `FlatMapIter` iterator.
+ pub(super) fn new(base: I, map_op: F) -> Self {
+ FlatMapIter { base, map_op }
+ }
+}
+
+impl<I, F, SI> ParallelIterator for FlatMapIter<I, F>
+where
+ I: ParallelIterator,
+ F: Fn(I::Item) -> SI + Sync + Send,
+ SI: IntoIterator,
+ SI::Item: Send,
+{
+ type Item = SI::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer = FlatMapIterConsumer::new(consumer, &self.map_op);
+ self.base.drive_unindexed(consumer)
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct FlatMapIterConsumer<'f, C, F> {
+ base: C,
+ map_op: &'f F,
+}
+
+impl<'f, C, F> FlatMapIterConsumer<'f, C, F> {
+ fn new(base: C, map_op: &'f F) -> Self {
+ FlatMapIterConsumer { base, map_op }
+ }
+}
+
+impl<'f, T, U, C, F> Consumer<T> for FlatMapIterConsumer<'f, C, F>
+where
+ C: UnindexedConsumer<U::Item>,
+ F: Fn(T) -> U + Sync,
+ U: IntoIterator,
+{
+ type Folder = FlatMapIterFolder<'f, C::Folder, F>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, C::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ FlatMapIterConsumer::new(left, self.map_op),
+ FlatMapIterConsumer::new(right, self.map_op),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ FlatMapIterFolder {
+ base: self.base.into_folder(),
+ map_op: self.map_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'f, T, U, C, F> UnindexedConsumer<T> for FlatMapIterConsumer<'f, C, F>
+where
+ C: UnindexedConsumer<U::Item>,
+ F: Fn(T) -> U + Sync,
+ U: IntoIterator,
+{
+ fn split_off_left(&self) -> Self {
+ FlatMapIterConsumer::new(self.base.split_off_left(), self.map_op)
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct FlatMapIterFolder<'f, C, F> {
+ base: C,
+ map_op: &'f F,
+}
+
+impl<'f, T, U, C, F> Folder<T> for FlatMapIterFolder<'f, C, F>
+where
+ C: Folder<U::Item>,
+ F: Fn(T) -> U,
+ U: IntoIterator,
+{
+ type Result = C::Result;
+
+ fn consume(self, item: T) -> Self {
+ let map_op = self.map_op;
+ let base = self.base.consume_iter(map_op(item));
+ FlatMapIterFolder { base, map_op }
+ }
+
+ fn consume_iter<I>(self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ let map_op = self.map_op;
+ let iter = iter.into_iter().flat_map(map_op);
+ let base = self.base.consume_iter(iter);
+ FlatMapIterFolder { base, map_op }
+ }
+
+ fn complete(self) -> Self::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/flatten.rs b/third_party/rust/rayon/src/iter/flatten.rs
new file mode 100644
index 0000000000..29d88f99ed
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/flatten.rs
@@ -0,0 +1,140 @@
+use super::plumbing::*;
+use super::*;
+
+/// `Flatten` turns each element to a parallel iterator, then flattens these iterators
+/// together. This struct is created by the [`flatten()`] method on [`ParallelIterator`].
+///
+/// [`flatten()`]: trait.ParallelIterator.html#method.flatten
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct Flatten<I: ParallelIterator> {
+ base: I,
+}
+
+impl<I> Flatten<I>
+where
+ I: ParallelIterator,
+ I::Item: IntoParallelIterator,
+{
+ /// Creates a new `Flatten` iterator.
+ pub(super) fn new(base: I) -> Self {
+ Flatten { base }
+ }
+}
+
+impl<I> ParallelIterator for Flatten<I>
+where
+ I: ParallelIterator,
+ I::Item: IntoParallelIterator,
+{
+ type Item = <I::Item as IntoParallelIterator>::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer = FlattenConsumer::new(consumer);
+ self.base.drive_unindexed(consumer)
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct FlattenConsumer<C> {
+ base: C,
+}
+
+impl<C> FlattenConsumer<C> {
+ fn new(base: C) -> Self {
+ FlattenConsumer { base }
+ }
+}
+
+impl<T, C> Consumer<T> for FlattenConsumer<C>
+where
+ C: UnindexedConsumer<T::Item>,
+ T: IntoParallelIterator,
+{
+ type Folder = FlattenFolder<C, C::Result>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, C::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ FlattenConsumer::new(left),
+ FlattenConsumer::new(right),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ FlattenFolder {
+ base: self.base,
+ previous: None,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<T, C> UnindexedConsumer<T> for FlattenConsumer<C>
+where
+ C: UnindexedConsumer<T::Item>,
+ T: IntoParallelIterator,
+{
+ fn split_off_left(&self) -> Self {
+ FlattenConsumer::new(self.base.split_off_left())
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct FlattenFolder<C, R> {
+ base: C,
+ previous: Option<R>,
+}
+
+impl<T, C> Folder<T> for FlattenFolder<C, C::Result>
+where
+ C: UnindexedConsumer<T::Item>,
+ T: IntoParallelIterator,
+{
+ type Result = C::Result;
+
+ fn consume(self, item: T) -> Self {
+ let par_iter = item.into_par_iter();
+ let consumer = self.base.split_off_left();
+ let result = par_iter.drive_unindexed(consumer);
+
+ let previous = match self.previous {
+ None => Some(result),
+ Some(previous) => {
+ let reducer = self.base.to_reducer();
+ Some(reducer.reduce(previous, result))
+ }
+ };
+
+ FlattenFolder {
+ base: self.base,
+ previous,
+ }
+ }
+
+ fn complete(self) -> Self::Result {
+ match self.previous {
+ Some(previous) => previous,
+ None => self.base.into_folder().complete(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/flatten_iter.rs b/third_party/rust/rayon/src/iter/flatten_iter.rs
new file mode 100644
index 0000000000..3ce0a3ce6d
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/flatten_iter.rs
@@ -0,0 +1,132 @@
+use super::plumbing::*;
+use super::*;
+
+/// `FlattenIter` turns each element to a serial iterator, then flattens these iterators
+/// together. This struct is created by the [`flatten_iter()`] method on [`ParallelIterator`].
+///
+/// [`flatten_iter()`]: trait.ParallelIterator.html#method.flatten_iter
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct FlattenIter<I: ParallelIterator> {
+ base: I,
+}
+
+impl<I> FlattenIter<I>
+where
+ I: ParallelIterator,
+ I::Item: IntoIterator,
+ <I::Item as IntoIterator>::Item: Send,
+{
+ /// Creates a new `FlattenIter` iterator.
+ pub(super) fn new(base: I) -> Self {
+ FlattenIter { base }
+ }
+}
+
+impl<I> ParallelIterator for FlattenIter<I>
+where
+ I: ParallelIterator,
+ I::Item: IntoIterator,
+ <I::Item as IntoIterator>::Item: Send,
+{
+ type Item = <I::Item as IntoIterator>::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer = FlattenIterConsumer::new(consumer);
+ self.base.drive_unindexed(consumer)
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct FlattenIterConsumer<C> {
+ base: C,
+}
+
+impl<C> FlattenIterConsumer<C> {
+ fn new(base: C) -> Self {
+ FlattenIterConsumer { base }
+ }
+}
+
+impl<T, C> Consumer<T> for FlattenIterConsumer<C>
+where
+ C: UnindexedConsumer<T::Item>,
+ T: IntoIterator,
+{
+ type Folder = FlattenIterFolder<C::Folder>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, C::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ FlattenIterConsumer::new(left),
+ FlattenIterConsumer::new(right),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ FlattenIterFolder {
+ base: self.base.into_folder(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<T, C> UnindexedConsumer<T> for FlattenIterConsumer<C>
+where
+ C: UnindexedConsumer<T::Item>,
+ T: IntoIterator,
+{
+ fn split_off_left(&self) -> Self {
+ FlattenIterConsumer::new(self.base.split_off_left())
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct FlattenIterFolder<C> {
+ base: C,
+}
+
+impl<T, C> Folder<T> for FlattenIterFolder<C>
+where
+ C: Folder<T::Item>,
+ T: IntoIterator,
+{
+ type Result = C::Result;
+
+ fn consume(self, item: T) -> Self {
+ let base = self.base.consume_iter(item);
+ FlattenIterFolder { base }
+ }
+
+ fn consume_iter<I>(self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ let iter = iter.into_iter().flatten();
+ let base = self.base.consume_iter(iter);
+ FlattenIterFolder { base }
+ }
+
+ fn complete(self) -> Self::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/fold.rs b/third_party/rust/rayon/src/iter/fold.rs
new file mode 100644
index 0000000000..345afbd501
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/fold.rs
@@ -0,0 +1,302 @@
+use super::plumbing::*;
+use super::*;
+
+use std::fmt::{self, Debug};
+
+impl<U, I, ID, F> Fold<I, ID, F>
+where
+ I: ParallelIterator,
+ F: Fn(U, I::Item) -> U + Sync + Send,
+ ID: Fn() -> U + Sync + Send,
+ U: Send,
+{
+ pub(super) fn new(base: I, identity: ID, fold_op: F) -> Self {
+ Fold {
+ base,
+ identity,
+ fold_op,
+ }
+ }
+}
+
+/// `Fold` is an iterator that applies a function over an iterator producing a single value.
+/// This struct is created by the [`fold()`] method on [`ParallelIterator`]
+///
+/// [`fold()`]: trait.ParallelIterator.html#method.fold
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct Fold<I, ID, F> {
+ base: I,
+ identity: ID,
+ fold_op: F,
+}
+
+impl<I: ParallelIterator + Debug, ID, F> Debug for Fold<I, ID, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Fold").field("base", &self.base).finish()
+ }
+}
+
+impl<U, I, ID, F> ParallelIterator for Fold<I, ID, F>
+where
+ I: ParallelIterator,
+ F: Fn(U, I::Item) -> U + Sync + Send,
+ ID: Fn() -> U + Sync + Send,
+ U: Send,
+{
+ type Item = U;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = FoldConsumer {
+ base: consumer,
+ fold_op: &self.fold_op,
+ identity: &self.identity,
+ };
+ self.base.drive_unindexed(consumer1)
+ }
+}
+
+struct FoldConsumer<'c, C, ID, F> {
+ base: C,
+ fold_op: &'c F,
+ identity: &'c ID,
+}
+
+impl<'r, U, T, C, ID, F> Consumer<T> for FoldConsumer<'r, C, ID, F>
+where
+ C: Consumer<U>,
+ F: Fn(U, T) -> U + Sync,
+ ID: Fn() -> U + Sync,
+ U: Send,
+{
+ type Folder = FoldFolder<'r, C::Folder, U, F>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ FoldConsumer { base: left, ..self },
+ FoldConsumer {
+ base: right,
+ ..self
+ },
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ FoldFolder {
+ base: self.base.into_folder(),
+ item: (self.identity)(),
+ fold_op: self.fold_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'r, U, T, C, ID, F> UnindexedConsumer<T> for FoldConsumer<'r, C, ID, F>
+where
+ C: UnindexedConsumer<U>,
+ F: Fn(U, T) -> U + Sync,
+ ID: Fn() -> U + Sync,
+ U: Send,
+{
+ fn split_off_left(&self) -> Self {
+ FoldConsumer {
+ base: self.base.split_off_left(),
+ ..*self
+ }
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct FoldFolder<'r, C, ID, F> {
+ base: C,
+ fold_op: &'r F,
+ item: ID,
+}
+
+impl<'r, C, ID, F, T> Folder<T> for FoldFolder<'r, C, ID, F>
+where
+ C: Folder<ID>,
+ F: Fn(ID, T) -> ID + Sync,
+{
+ type Result = C::Result;
+
+ fn consume(self, item: T) -> Self {
+ let item = (self.fold_op)(self.item, item);
+ FoldFolder {
+ base: self.base,
+ fold_op: self.fold_op,
+ item,
+ }
+ }
+
+ fn consume_iter<I>(self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ fn not_full<C, ID, T>(base: &C) -> impl Fn(&T) -> bool + '_
+ where
+ C: Folder<ID>,
+ {
+ move |_| !base.full()
+ }
+
+ let base = self.base;
+ let item = iter
+ .into_iter()
+ // stop iterating if another thread has finished
+ .take_while(not_full(&base))
+ .fold(self.item, self.fold_op);
+
+ FoldFolder {
+ base,
+ item,
+ fold_op: self.fold_op,
+ }
+ }
+
+ fn complete(self) -> C::Result {
+ self.base.consume(self.item).complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+// ///////////////////////////////////////////////////////////////////////////
+
+impl<U, I, F> FoldWith<I, U, F>
+where
+ I: ParallelIterator,
+ F: Fn(U, I::Item) -> U + Sync + Send,
+ U: Send + Clone,
+{
+ pub(super) fn new(base: I, item: U, fold_op: F) -> Self {
+ FoldWith {
+ base,
+ item,
+ fold_op,
+ }
+ }
+}
+
+/// `FoldWith` is an iterator that applies a function over an iterator producing a single value.
+/// This struct is created by the [`fold_with()`] method on [`ParallelIterator`]
+///
+/// [`fold_with()`]: trait.ParallelIterator.html#method.fold_with
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct FoldWith<I, U, F> {
+ base: I,
+ item: U,
+ fold_op: F,
+}
+
+impl<I: ParallelIterator + Debug, U: Debug, F> Debug for FoldWith<I, U, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FoldWith")
+ .field("base", &self.base)
+ .field("item", &self.item)
+ .finish()
+ }
+}
+
+impl<U, I, F> ParallelIterator for FoldWith<I, U, F>
+where
+ I: ParallelIterator,
+ F: Fn(U, I::Item) -> U + Sync + Send,
+ U: Send + Clone,
+{
+ type Item = U;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = FoldWithConsumer {
+ base: consumer,
+ item: self.item,
+ fold_op: &self.fold_op,
+ };
+ self.base.drive_unindexed(consumer1)
+ }
+}
+
+struct FoldWithConsumer<'c, C, U, F> {
+ base: C,
+ item: U,
+ fold_op: &'c F,
+}
+
+impl<'r, U, T, C, F> Consumer<T> for FoldWithConsumer<'r, C, U, F>
+where
+ C: Consumer<U>,
+ F: Fn(U, T) -> U + Sync,
+ U: Send + Clone,
+{
+ type Folder = FoldFolder<'r, C::Folder, U, F>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ FoldWithConsumer {
+ base: left,
+ item: self.item.clone(),
+ ..self
+ },
+ FoldWithConsumer {
+ base: right,
+ ..self
+ },
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ FoldFolder {
+ base: self.base.into_folder(),
+ item: self.item,
+ fold_op: self.fold_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'r, U, T, C, F> UnindexedConsumer<T> for FoldWithConsumer<'r, C, U, F>
+where
+ C: UnindexedConsumer<U>,
+ F: Fn(U, T) -> U + Sync,
+ U: Send + Clone,
+{
+ fn split_off_left(&self) -> Self {
+ FoldWithConsumer {
+ base: self.base.split_off_left(),
+ item: self.item.clone(),
+ ..*self
+ }
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/fold_chunks.rs b/third_party/rust/rayon/src/iter/fold_chunks.rs
new file mode 100644
index 0000000000..185fb1a65d
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/fold_chunks.rs
@@ -0,0 +1,236 @@
+use std::fmt::{self, Debug};
+
+use super::chunks::ChunkProducer;
+use super::plumbing::*;
+use super::*;
+use crate::math::div_round_up;
+
+/// `FoldChunks` is an iterator that groups elements of an underlying iterator and applies a
+/// function over them, producing a single value for each group.
+///
+/// This struct is created by the [`fold_chunks()`] method on [`IndexedParallelIterator`]
+///
+/// [`fold_chunks()`]: trait.IndexedParallelIterator.html#method.fold_chunks
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct FoldChunks<I, ID, F>
+where
+ I: IndexedParallelIterator,
+{
+ base: I,
+ chunk_size: usize,
+ fold_op: F,
+ identity: ID,
+}
+
+impl<I: IndexedParallelIterator + Debug, ID, F> Debug for FoldChunks<I, ID, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Fold")
+ .field("base", &self.base)
+ .field("chunk_size", &self.chunk_size)
+ .finish()
+ }
+}
+
+impl<I, ID, U, F> FoldChunks<I, ID, F>
+where
+ I: IndexedParallelIterator,
+ ID: Fn() -> U + Send + Sync,
+ F: Fn(U, I::Item) -> U + Send + Sync,
+ U: Send,
+{
+ /// Creates a new `FoldChunks` iterator
+ pub(super) fn new(base: I, chunk_size: usize, identity: ID, fold_op: F) -> Self {
+ FoldChunks {
+ base,
+ chunk_size,
+ identity,
+ fold_op,
+ }
+ }
+}
+
+impl<I, ID, U, F> ParallelIterator for FoldChunks<I, ID, F>
+where
+ I: IndexedParallelIterator,
+ ID: Fn() -> U + Send + Sync,
+ F: Fn(U, I::Item) -> U + Send + Sync,
+ U: Send,
+{
+ type Item = U;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<U>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I, ID, U, F> IndexedParallelIterator for FoldChunks<I, ID, F>
+where
+ I: IndexedParallelIterator,
+ ID: Fn() -> U + Send + Sync,
+ F: Fn(U, I::Item) -> U + Send + Sync,
+ U: Send,
+{
+ fn len(&self) -> usize {
+ div_round_up(self.base.len(), self.chunk_size)
+ }
+
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ let len = self.base.len();
+ return self.base.with_producer(Callback {
+ chunk_size: self.chunk_size,
+ len,
+ identity: self.identity,
+ fold_op: self.fold_op,
+ callback,
+ });
+
+ struct Callback<CB, ID, F> {
+ chunk_size: usize,
+ len: usize,
+ identity: ID,
+ fold_op: F,
+ callback: CB,
+ }
+
+ impl<T, CB, ID, U, F> ProducerCallback<T> for Callback<CB, ID, F>
+ where
+ CB: ProducerCallback<U>,
+ ID: Fn() -> U + Send + Sync,
+ F: Fn(U, T) -> U + Send + Sync,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let identity = &self.identity;
+ let fold_op = &self.fold_op;
+ let fold_iter = move |iter: P::IntoIter| iter.fold(identity(), fold_op);
+ let producer = ChunkProducer::new(self.chunk_size, self.len, base, fold_iter);
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::ops::Add;
+
+ #[test]
+ fn check_fold_chunks() {
+ let words = "bishbashbosh!"
+ .chars()
+ .collect::<Vec<_>>()
+ .into_par_iter()
+ .fold_chunks(4, String::new, |mut s, c| {
+ s.push(c);
+ s
+ })
+ .collect::<Vec<_>>();
+
+ assert_eq!(words, vec!["bish", "bash", "bosh", "!"]);
+ }
+
+ // 'closure' values for tests below
+ fn id() -> i32 {
+ 0
+ }
+ fn sum<T, U>(x: T, y: U) -> T
+ where
+ T: Add<U, Output = T>,
+ {
+ x + y
+ }
+
+ #[test]
+ #[should_panic(expected = "chunk_size must not be zero")]
+ fn check_fold_chunks_zero_size() {
+ let _: Vec<i32> = vec![1, 2, 3]
+ .into_par_iter()
+ .fold_chunks(0, id, sum)
+ .collect();
+ }
+
+ #[test]
+ fn check_fold_chunks_even_size() {
+ assert_eq!(
+ vec![1 + 2 + 3, 4 + 5 + 6, 7 + 8 + 9],
+ (1..10)
+ .into_par_iter()
+ .fold_chunks(3, id, sum)
+ .collect::<Vec<i32>>()
+ );
+ }
+
+ #[test]
+ fn check_fold_chunks_empty() {
+ let v: Vec<i32> = vec![];
+ let expected: Vec<i32> = vec![];
+ assert_eq!(
+ expected,
+ v.into_par_iter()
+ .fold_chunks(2, id, sum)
+ .collect::<Vec<i32>>()
+ );
+ }
+
+ #[test]
+ fn check_fold_chunks_len() {
+ assert_eq!(4, (0..8).into_par_iter().fold_chunks(2, id, sum).len());
+ assert_eq!(3, (0..9).into_par_iter().fold_chunks(3, id, sum).len());
+ assert_eq!(3, (0..8).into_par_iter().fold_chunks(3, id, sum).len());
+ assert_eq!(1, (&[1]).par_iter().fold_chunks(3, id, sum).len());
+ assert_eq!(0, (0..0).into_par_iter().fold_chunks(3, id, sum).len());
+ }
+
+ #[test]
+ fn check_fold_chunks_uneven() {
+ let cases: Vec<(Vec<u32>, usize, Vec<u32>)> = vec![
+ ((0..5).collect(), 3, vec![0 + 1 + 2, 3 + 4]),
+ (vec![1], 5, vec![1]),
+ ((0..4).collect(), 3, vec![0 + 1 + 2, 3]),
+ ];
+
+ for (i, (v, n, expected)) in cases.into_iter().enumerate() {
+ let mut res: Vec<u32> = vec![];
+ v.par_iter()
+ .fold_chunks(n, || 0, sum)
+ .collect_into_vec(&mut res);
+ assert_eq!(expected, res, "Case {} failed", i);
+
+ res.truncate(0);
+ v.into_par_iter()
+ .fold_chunks(n, || 0, sum)
+ .rev()
+ .collect_into_vec(&mut res);
+ assert_eq!(
+ expected.into_iter().rev().collect::<Vec<u32>>(),
+ res,
+ "Case {} reversed failed",
+ i
+ );
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/fold_chunks_with.rs b/third_party/rust/rayon/src/iter/fold_chunks_with.rs
new file mode 100644
index 0000000000..af120aec47
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/fold_chunks_with.rs
@@ -0,0 +1,231 @@
+use std::fmt::{self, Debug};
+
+use super::chunks::ChunkProducer;
+use super::plumbing::*;
+use super::*;
+use crate::math::div_round_up;
+
+/// `FoldChunksWith` is an iterator that groups elements of an underlying iterator and applies a
+/// function over them, producing a single value for each group.
+///
+/// This struct is created by the [`fold_chunks_with()`] method on [`IndexedParallelIterator`]
+///
+/// [`fold_chunks_with()`]: trait.IndexedParallelIterator.html#method.fold_chunks
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct FoldChunksWith<I, U, F>
+where
+ I: IndexedParallelIterator,
+{
+ base: I,
+ chunk_size: usize,
+ item: U,
+ fold_op: F,
+}
+
+impl<I: IndexedParallelIterator + Debug, U: Debug, F> Debug for FoldChunksWith<I, U, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Fold")
+ .field("base", &self.base)
+ .field("chunk_size", &self.chunk_size)
+ .field("item", &self.item)
+ .finish()
+ }
+}
+
+impl<I, U, F> FoldChunksWith<I, U, F>
+where
+ I: IndexedParallelIterator,
+ U: Send + Clone,
+ F: Fn(U, I::Item) -> U + Send + Sync,
+{
+ /// Creates a new `FoldChunksWith` iterator
+ pub(super) fn new(base: I, chunk_size: usize, item: U, fold_op: F) -> Self {
+ FoldChunksWith {
+ base,
+ chunk_size,
+ item,
+ fold_op,
+ }
+ }
+}
+
+impl<I, U, F> ParallelIterator for FoldChunksWith<I, U, F>
+where
+ I: IndexedParallelIterator,
+ U: Send + Clone,
+ F: Fn(U, I::Item) -> U + Send + Sync,
+{
+ type Item = U;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<U>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I, U, F> IndexedParallelIterator for FoldChunksWith<I, U, F>
+where
+ I: IndexedParallelIterator,
+ U: Send + Clone,
+ F: Fn(U, I::Item) -> U + Send + Sync,
+{
+ fn len(&self) -> usize {
+ div_round_up(self.base.len(), self.chunk_size)
+ }
+
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ let len = self.base.len();
+ return self.base.with_producer(Callback {
+ chunk_size: self.chunk_size,
+ len,
+ item: self.item,
+ fold_op: self.fold_op,
+ callback,
+ });
+
+ struct Callback<CB, T, F> {
+ chunk_size: usize,
+ len: usize,
+ item: T,
+ fold_op: F,
+ callback: CB,
+ }
+
+ impl<T, U, F, CB> ProducerCallback<T> for Callback<CB, U, F>
+ where
+ CB: ProducerCallback<U>,
+ U: Send + Clone,
+ F: Fn(U, T) -> U + Send + Sync,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let item = self.item;
+ let fold_op = &self.fold_op;
+ let fold_iter = move |iter: P::IntoIter| iter.fold(item.clone(), fold_op);
+ let producer = ChunkProducer::new(self.chunk_size, self.len, base, fold_iter);
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::ops::Add;
+
+ #[test]
+ fn check_fold_chunks_with() {
+ let words = "bishbashbosh!"
+ .chars()
+ .collect::<Vec<_>>()
+ .into_par_iter()
+ .fold_chunks_with(4, String::new(), |mut s, c| {
+ s.push(c);
+ s
+ })
+ .collect::<Vec<_>>();
+
+ assert_eq!(words, vec!["bish", "bash", "bosh", "!"]);
+ }
+
+ // 'closure' value for tests below
+ fn sum<T, U>(x: T, y: U) -> T
+ where
+ T: Add<U, Output = T>,
+ {
+ x + y
+ }
+
+ #[test]
+ #[should_panic(expected = "chunk_size must not be zero")]
+ fn check_fold_chunks_zero_size() {
+ let _: Vec<i32> = vec![1, 2, 3]
+ .into_par_iter()
+ .fold_chunks_with(0, 0, sum)
+ .collect();
+ }
+
+ #[test]
+ fn check_fold_chunks_even_size() {
+ assert_eq!(
+ vec![1 + 2 + 3, 4 + 5 + 6, 7 + 8 + 9],
+ (1..10)
+ .into_par_iter()
+ .fold_chunks_with(3, 0, sum)
+ .collect::<Vec<i32>>()
+ );
+ }
+
+ #[test]
+ fn check_fold_chunks_with_empty() {
+ let v: Vec<i32> = vec![];
+ let expected: Vec<i32> = vec![];
+ assert_eq!(
+ expected,
+ v.into_par_iter()
+ .fold_chunks_with(2, 0, sum)
+ .collect::<Vec<i32>>()
+ );
+ }
+
+ #[test]
+ fn check_fold_chunks_len() {
+ assert_eq!(4, (0..8).into_par_iter().fold_chunks_with(2, 0, sum).len());
+ assert_eq!(3, (0..9).into_par_iter().fold_chunks_with(3, 0, sum).len());
+ assert_eq!(3, (0..8).into_par_iter().fold_chunks_with(3, 0, sum).len());
+ assert_eq!(1, (&[1]).par_iter().fold_chunks_with(3, 0, sum).len());
+ assert_eq!(0, (0..0).into_par_iter().fold_chunks_with(3, 0, sum).len());
+ }
+
+ #[test]
+ fn check_fold_chunks_uneven() {
+ let cases: Vec<(Vec<u32>, usize, Vec<u32>)> = vec![
+ ((0..5).collect(), 3, vec![0 + 1 + 2, 3 + 4]),
+ (vec![1], 5, vec![1]),
+ ((0..4).collect(), 3, vec![0 + 1 + 2, 3]),
+ ];
+
+ for (i, (v, n, expected)) in cases.into_iter().enumerate() {
+ let mut res: Vec<u32> = vec![];
+ v.par_iter()
+ .fold_chunks_with(n, 0, sum)
+ .collect_into_vec(&mut res);
+ assert_eq!(expected, res, "Case {} failed", i);
+
+ res.truncate(0);
+ v.into_par_iter()
+ .fold_chunks_with(n, 0, sum)
+ .rev()
+ .collect_into_vec(&mut res);
+ assert_eq!(
+ expected.into_iter().rev().collect::<Vec<u32>>(),
+ res,
+ "Case {} reversed failed",
+ i
+ );
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/for_each.rs b/third_party/rust/rayon/src/iter/for_each.rs
new file mode 100644
index 0000000000..3b77bebe1b
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/for_each.rs
@@ -0,0 +1,77 @@
+use super::noop::*;
+use super::plumbing::*;
+use super::ParallelIterator;
+
+pub(super) fn for_each<I, F, T>(pi: I, op: &F)
+where
+ I: ParallelIterator<Item = T>,
+ F: Fn(T) + Sync,
+ T: Send,
+{
+ let consumer = ForEachConsumer { op };
+ pi.drive_unindexed(consumer)
+}
+
+struct ForEachConsumer<'f, F> {
+ op: &'f F,
+}
+
+impl<'f, F, T> Consumer<T> for ForEachConsumer<'f, F>
+where
+ F: Fn(T) + Sync,
+{
+ type Folder = ForEachConsumer<'f, F>;
+ type Reducer = NoopReducer;
+ type Result = ();
+
+ fn split_at(self, _index: usize) -> (Self, Self, NoopReducer) {
+ (self.split_off_left(), self, NoopReducer)
+ }
+
+ fn into_folder(self) -> Self {
+ self
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl<'f, F, T> Folder<T> for ForEachConsumer<'f, F>
+where
+ F: Fn(T) + Sync,
+{
+ type Result = ();
+
+ fn consume(self, item: T) -> Self {
+ (self.op)(item);
+ self
+ }
+
+ fn consume_iter<I>(self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ iter.into_iter().for_each(self.op);
+ self
+ }
+
+ fn complete(self) {}
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl<'f, F, T> UnindexedConsumer<T> for ForEachConsumer<'f, F>
+where
+ F: Fn(T) + Sync,
+{
+ fn split_off_left(&self) -> Self {
+ ForEachConsumer { op: self.op }
+ }
+
+ fn to_reducer(&self) -> NoopReducer {
+ NoopReducer
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/from_par_iter.rs b/third_party/rust/rayon/src/iter/from_par_iter.rs
new file mode 100644
index 0000000000..3240f32e21
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/from_par_iter.rs
@@ -0,0 +1,228 @@
+use super::noop::NoopConsumer;
+use super::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator};
+
+use std::borrow::Cow;
+use std::collections::LinkedList;
+use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
+use std::collections::{BinaryHeap, VecDeque};
+use std::hash::{BuildHasher, Hash};
+
+/// Creates an empty default collection and extends it.
+fn collect_extended<C, I>(par_iter: I) -> C
+where
+ I: IntoParallelIterator,
+ C: ParallelExtend<I::Item> + Default,
+{
+ let mut collection = C::default();
+ collection.par_extend(par_iter);
+ collection
+}
+
+/// Collects items from a parallel iterator into a vector.
+impl<T> FromParallelIterator<T> for Vec<T>
+where
+ T: Send,
+{
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ collect_extended(par_iter)
+ }
+}
+
+/// Collects items from a parallel iterator into a vecdeque.
+impl<T> FromParallelIterator<T> for VecDeque<T>
+where
+ T: Send,
+{
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ Vec::from_par_iter(par_iter).into()
+ }
+}
+
+/// Collects items from a parallel iterator into a binaryheap.
+/// The heap-ordering is calculated serially after all items are collected.
+impl<T> FromParallelIterator<T> for BinaryHeap<T>
+where
+ T: Ord + Send,
+{
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ Vec::from_par_iter(par_iter).into()
+ }
+}
+
+/// Collects items from a parallel iterator into a freshly allocated
+/// linked list.
+impl<T> FromParallelIterator<T> for LinkedList<T>
+where
+ T: Send,
+{
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ collect_extended(par_iter)
+ }
+}
+
+/// Collects (key, value) pairs from a parallel iterator into a
+/// hashmap. If multiple pairs correspond to the same key, then the
+/// ones produced earlier in the parallel iterator will be
+/// overwritten, just as with a sequential iterator.
+impl<K, V, S> FromParallelIterator<(K, V)> for HashMap<K, V, S>
+where
+ K: Eq + Hash + Send,
+ V: Send,
+ S: BuildHasher + Default + Send,
+{
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = (K, V)>,
+ {
+ collect_extended(par_iter)
+ }
+}
+
+/// Collects (key, value) pairs from a parallel iterator into a
+/// btreemap. If multiple pairs correspond to the same key, then the
+/// ones produced earlier in the parallel iterator will be
+/// overwritten, just as with a sequential iterator.
+impl<K, V> FromParallelIterator<(K, V)> for BTreeMap<K, V>
+where
+ K: Ord + Send,
+ V: Send,
+{
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = (K, V)>,
+ {
+ collect_extended(par_iter)
+ }
+}
+
+/// Collects values from a parallel iterator into a hashset.
+impl<V, S> FromParallelIterator<V> for HashSet<V, S>
+where
+ V: Eq + Hash + Send,
+ S: BuildHasher + Default + Send,
+{
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = V>,
+ {
+ collect_extended(par_iter)
+ }
+}
+
+/// Collects values from a parallel iterator into a btreeset.
+impl<V> FromParallelIterator<V> for BTreeSet<V>
+where
+ V: Send + Ord,
+{
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = V>,
+ {
+ collect_extended(par_iter)
+ }
+}
+
+/// Collects characters from a parallel iterator into a string.
+impl FromParallelIterator<char> for String {
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = char>,
+ {
+ collect_extended(par_iter)
+ }
+}
+
+/// Collects characters from a parallel iterator into a string.
+impl<'a> FromParallelIterator<&'a char> for String {
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = &'a char>,
+ {
+ collect_extended(par_iter)
+ }
+}
+
+/// Collects string slices from a parallel iterator into a string.
+impl<'a> FromParallelIterator<&'a str> for String {
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = &'a str>,
+ {
+ collect_extended(par_iter)
+ }
+}
+
+/// Collects strings from a parallel iterator into one large string.
+impl FromParallelIterator<String> for String {
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = String>,
+ {
+ collect_extended(par_iter)
+ }
+}
+
+/// Collects string slices from a parallel iterator into a string.
+impl<'a> FromParallelIterator<Cow<'a, str>> for String {
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = Cow<'a, str>>,
+ {
+ collect_extended(par_iter)
+ }
+}
+
+/// Collects an arbitrary `Cow` collection.
+///
+/// Note, the standard library only has `FromIterator` for `Cow<'a, str>` and
+/// `Cow<'a, [T]>`, because no one thought to add a blanket implementation
+/// before it was stabilized.
+impl<'a, C: ?Sized, T> FromParallelIterator<T> for Cow<'a, C>
+where
+ C: ToOwned,
+ C::Owned: FromParallelIterator<T>,
+ T: Send,
+{
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ Cow::Owned(C::Owned::from_par_iter(par_iter))
+ }
+}
+
+/// Collapses all unit items from a parallel iterator into one.
+///
+/// This is more useful when combined with higher-level abstractions, like
+/// collecting to a `Result<(), E>` where you only care about errors:
+///
+/// ```
+/// use std::io::*;
+/// use rayon::prelude::*;
+///
+/// let data = vec![1, 2, 3, 4, 5];
+/// let res: Result<()> = data.par_iter()
+/// .map(|x| writeln!(stdout(), "{}", x))
+/// .collect();
+/// assert!(res.is_ok());
+/// ```
+impl FromParallelIterator<()> for () {
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = ()>,
+ {
+ par_iter.into_par_iter().drive_unindexed(NoopConsumer)
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/inspect.rs b/third_party/rust/rayon/src/iter/inspect.rs
new file mode 100644
index 0000000000..c50ca022da
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/inspect.rs
@@ -0,0 +1,257 @@
+use super::plumbing::*;
+use super::*;
+
+use std::fmt::{self, Debug};
+use std::iter;
+
+/// `Inspect` is an iterator that calls a function with a reference to each
+/// element before yielding it.
+///
+/// This struct is created by the [`inspect()`] method on [`ParallelIterator`]
+///
+/// [`inspect()`]: trait.ParallelIterator.html#method.inspect
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct Inspect<I: ParallelIterator, F> {
+ base: I,
+ inspect_op: F,
+}
+
+impl<I: ParallelIterator + Debug, F> Debug for Inspect<I, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Inspect").field("base", &self.base).finish()
+ }
+}
+
+impl<I, F> Inspect<I, F>
+where
+ I: ParallelIterator,
+{
+ /// Creates a new `Inspect` iterator.
+ pub(super) fn new(base: I, inspect_op: F) -> Self {
+ Inspect { base, inspect_op }
+ }
+}
+
+impl<I, F> ParallelIterator for Inspect<I, F>
+where
+ I: ParallelIterator,
+ F: Fn(&I::Item) + Sync + Send,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = InspectConsumer::new(consumer, &self.inspect_op);
+ self.base.drive_unindexed(consumer1)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ self.base.opt_len()
+ }
+}
+
+impl<I, F> IndexedParallelIterator for Inspect<I, F>
+where
+ I: IndexedParallelIterator,
+ F: Fn(&I::Item) + Sync + Send,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ let consumer1 = InspectConsumer::new(consumer, &self.inspect_op);
+ self.base.drive(consumer1)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback {
+ callback,
+ inspect_op: self.inspect_op,
+ });
+
+ struct Callback<CB, F> {
+ callback: CB,
+ inspect_op: F,
+ }
+
+ impl<T, F, CB> ProducerCallback<T> for Callback<CB, F>
+ where
+ CB: ProducerCallback<T>,
+ F: Fn(&T) + Sync,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let producer = InspectProducer {
+ base,
+ inspect_op: &self.inspect_op,
+ };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+
+struct InspectProducer<'f, P, F> {
+ base: P,
+ inspect_op: &'f F,
+}
+
+impl<'f, P, F> Producer for InspectProducer<'f, P, F>
+where
+ P: Producer,
+ F: Fn(&P::Item) + Sync,
+{
+ type Item = P::Item;
+ type IntoIter = iter::Inspect<P::IntoIter, &'f F>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.base.into_iter().inspect(self.inspect_op)
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(index);
+ (
+ InspectProducer {
+ base: left,
+ inspect_op: self.inspect_op,
+ },
+ InspectProducer {
+ base: right,
+ inspect_op: self.inspect_op,
+ },
+ )
+ }
+
+ fn fold_with<G>(self, folder: G) -> G
+ where
+ G: Folder<Self::Item>,
+ {
+ let folder1 = InspectFolder {
+ base: folder,
+ inspect_op: self.inspect_op,
+ };
+ self.base.fold_with(folder1).base
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct InspectConsumer<'f, C, F> {
+ base: C,
+ inspect_op: &'f F,
+}
+
+impl<'f, C, F> InspectConsumer<'f, C, F> {
+ fn new(base: C, inspect_op: &'f F) -> Self {
+ InspectConsumer { base, inspect_op }
+ }
+}
+
+impl<'f, T, C, F> Consumer<T> for InspectConsumer<'f, C, F>
+where
+ C: Consumer<T>,
+ F: Fn(&T) + Sync,
+{
+ type Folder = InspectFolder<'f, C::Folder, F>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ InspectConsumer::new(left, self.inspect_op),
+ InspectConsumer::new(right, self.inspect_op),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ InspectFolder {
+ base: self.base.into_folder(),
+ inspect_op: self.inspect_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'f, T, C, F> UnindexedConsumer<T> for InspectConsumer<'f, C, F>
+where
+ C: UnindexedConsumer<T>,
+ F: Fn(&T) + Sync,
+{
+ fn split_off_left(&self) -> Self {
+ InspectConsumer::new(self.base.split_off_left(), self.inspect_op)
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct InspectFolder<'f, C, F> {
+ base: C,
+ inspect_op: &'f F,
+}
+
+impl<'f, T, C, F> Folder<T> for InspectFolder<'f, C, F>
+where
+ C: Folder<T>,
+ F: Fn(&T),
+{
+ type Result = C::Result;
+
+ fn consume(self, item: T) -> Self {
+ (self.inspect_op)(&item);
+ InspectFolder {
+ base: self.base.consume(item),
+ inspect_op: self.inspect_op,
+ }
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ self.base = self
+ .base
+ .consume_iter(iter.into_iter().inspect(self.inspect_op));
+ self
+ }
+
+ fn complete(self) -> C::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/interleave.rs b/third_party/rust/rayon/src/iter/interleave.rs
new file mode 100644
index 0000000000..3cacc49f95
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/interleave.rs
@@ -0,0 +1,336 @@
+use super::plumbing::*;
+use super::*;
+use std::cmp;
+use std::iter::Fuse;
+
+/// `Interleave` is an iterator that interleaves elements of iterators
+/// `i` and `j` in one continuous iterator. This struct is created by
+/// the [`interleave()`] method on [`IndexedParallelIterator`]
+///
+/// [`interleave()`]: trait.IndexedParallelIterator.html#method.interleave
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct Interleave<I, J>
+where
+ I: IndexedParallelIterator,
+ J: IndexedParallelIterator<Item = I::Item>,
+{
+ i: I,
+ j: J,
+}
+
+impl<I, J> Interleave<I, J>
+where
+ I: IndexedParallelIterator,
+ J: IndexedParallelIterator<Item = I::Item>,
+{
+ /// Creates a new `Interleave` iterator
+ pub(super) fn new(i: I, j: J) -> Self {
+ Interleave { i, j }
+ }
+}
+
+impl<I, J> ParallelIterator for Interleave<I, J>
+where
+ I: IndexedParallelIterator,
+ J: IndexedParallelIterator<Item = I::Item>,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<I::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I, J> IndexedParallelIterator for Interleave<I, J>
+where
+ I: IndexedParallelIterator,
+ J: IndexedParallelIterator<Item = I::Item>,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn len(&self) -> usize {
+ self.i.len().checked_add(self.j.len()).expect("overflow")
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ let (i_len, j_len) = (self.i.len(), self.j.len());
+ return self.i.with_producer(CallbackI {
+ callback,
+ i_len,
+ j_len,
+ i_next: false,
+ j: self.j,
+ });
+
+ struct CallbackI<CB, J> {
+ callback: CB,
+ i_len: usize,
+ j_len: usize,
+ i_next: bool,
+ j: J,
+ }
+
+ impl<CB, J> ProducerCallback<J::Item> for CallbackI<CB, J>
+ where
+ J: IndexedParallelIterator,
+ CB: ProducerCallback<J::Item>,
+ {
+ type Output = CB::Output;
+
+ fn callback<I>(self, i_producer: I) -> Self::Output
+ where
+ I: Producer<Item = J::Item>,
+ {
+ self.j.with_producer(CallbackJ {
+ i_producer,
+ i_len: self.i_len,
+ j_len: self.j_len,
+ i_next: self.i_next,
+ callback: self.callback,
+ })
+ }
+ }
+
+ struct CallbackJ<CB, I> {
+ callback: CB,
+ i_len: usize,
+ j_len: usize,
+ i_next: bool,
+ i_producer: I,
+ }
+
+ impl<CB, I> ProducerCallback<I::Item> for CallbackJ<CB, I>
+ where
+ I: Producer,
+ CB: ProducerCallback<I::Item>,
+ {
+ type Output = CB::Output;
+
+ fn callback<J>(self, j_producer: J) -> Self::Output
+ where
+ J: Producer<Item = I::Item>,
+ {
+ let producer = InterleaveProducer::new(
+ self.i_producer,
+ j_producer,
+ self.i_len,
+ self.j_len,
+ self.i_next,
+ );
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+struct InterleaveProducer<I, J>
+where
+ I: Producer,
+ J: Producer<Item = I::Item>,
+{
+ i: I,
+ j: J,
+ i_len: usize,
+ j_len: usize,
+ i_next: bool,
+}
+
+impl<I, J> InterleaveProducer<I, J>
+where
+ I: Producer,
+ J: Producer<Item = I::Item>,
+{
+ fn new(i: I, j: J, i_len: usize, j_len: usize, i_next: bool) -> InterleaveProducer<I, J> {
+ InterleaveProducer {
+ i,
+ j,
+ i_len,
+ j_len,
+ i_next,
+ }
+ }
+}
+
+impl<I, J> Producer for InterleaveProducer<I, J>
+where
+ I: Producer,
+ J: Producer<Item = I::Item>,
+{
+ type Item = I::Item;
+ type IntoIter = InterleaveSeq<I::IntoIter, J::IntoIter>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ InterleaveSeq {
+ i: self.i.into_iter().fuse(),
+ j: self.j.into_iter().fuse(),
+ i_next: self.i_next,
+ }
+ }
+
+ fn min_len(&self) -> usize {
+ cmp::max(self.i.min_len(), self.j.min_len())
+ }
+
+ fn max_len(&self) -> usize {
+ cmp::min(self.i.max_len(), self.j.max_len())
+ }
+
+ /// We know 0 < index <= self.i_len + self.j_len
+ ///
+ /// Find a, b satisfying:
+ ///
+ /// (1) 0 < a <= self.i_len
+ /// (2) 0 < b <= self.j_len
+ /// (3) a + b == index
+ ///
+ /// For even splits, set a = b = index/2.
+ /// For odd splits, set a = (index/2)+1, b = index/2, if `i`
+ /// should yield the next element, otherwise, if `j` should yield
+ /// the next element, set a = index/2 and b = (index/2)+1
+ fn split_at(self, index: usize) -> (Self, Self) {
+ #[inline]
+ fn odd_offset(flag: bool) -> usize {
+ (!flag) as usize
+ }
+
+ let even = index % 2 == 0;
+ let idx = index >> 1;
+
+ // desired split
+ let (i_idx, j_idx) = (
+ idx + odd_offset(even || self.i_next),
+ idx + odd_offset(even || !self.i_next),
+ );
+
+ let (i_split, j_split) = if self.i_len >= i_idx && self.j_len >= j_idx {
+ (i_idx, j_idx)
+ } else if self.i_len >= i_idx {
+ // j too short
+ (index - self.j_len, self.j_len)
+ } else {
+ // i too short
+ (self.i_len, index - self.i_len)
+ };
+
+ let trailing_i_next = even == self.i_next;
+ let (i_left, i_right) = self.i.split_at(i_split);
+ let (j_left, j_right) = self.j.split_at(j_split);
+
+ (
+ InterleaveProducer::new(i_left, j_left, i_split, j_split, self.i_next),
+ InterleaveProducer::new(
+ i_right,
+ j_right,
+ self.i_len - i_split,
+ self.j_len - j_split,
+ trailing_i_next,
+ ),
+ )
+ }
+}
+
+/// Wrapper for Interleave to implement DoubleEndedIterator and
+/// ExactSizeIterator.
+///
+/// This iterator is fused.
+struct InterleaveSeq<I, J> {
+ i: Fuse<I>,
+ j: Fuse<J>,
+
+ /// Flag to control which iterator should provide the next element. When
+ /// `false` then `i` produces the next element, otherwise `j` produces the
+ /// next element.
+ i_next: bool,
+}
+
+/// Iterator implementation for InterleaveSeq. This implementation is
+/// taken more or less verbatim from itertools. It is replicated here
+/// (instead of calling itertools directly), because we also need to
+/// implement `DoubledEndedIterator` and `ExactSizeIterator`.
+impl<I, J> Iterator for InterleaveSeq<I, J>
+where
+ I: Iterator,
+ J: Iterator<Item = I::Item>,
+{
+ type Item = I::Item;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ self.i_next = !self.i_next;
+ if self.i_next {
+ match self.i.next() {
+ None => self.j.next(),
+ r => r,
+ }
+ } else {
+ match self.j.next() {
+ None => self.i.next(),
+ r => r,
+ }
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (ih, jh) = (self.i.size_hint(), self.j.size_hint());
+ let min = ih.0.saturating_add(jh.0);
+ let max = match (ih.1, jh.1) {
+ (Some(x), Some(y)) => x.checked_add(y),
+ _ => None,
+ };
+ (min, max)
+ }
+}
+
+// The implementation for DoubleEndedIterator requires
+// ExactSizeIterator to provide `next_back()`. The last element will
+// come from the iterator that runs out last (ie has the most elements
+// in it). If the iterators have the same number of elements, then the
+// last iterator will provide the last element.
+impl<I, J> DoubleEndedIterator for InterleaveSeq<I, J>
+where
+ I: DoubleEndedIterator + ExactSizeIterator,
+ J: DoubleEndedIterator<Item = I::Item> + ExactSizeIterator<Item = I::Item>,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<I::Item> {
+ match self.i.len().cmp(&self.j.len()) {
+ Ordering::Less => self.j.next_back(),
+ Ordering::Equal => {
+ if self.i_next {
+ self.i.next_back()
+ } else {
+ self.j.next_back()
+ }
+ }
+ Ordering::Greater => self.i.next_back(),
+ }
+ }
+}
+
+impl<I, J> ExactSizeIterator for InterleaveSeq<I, J>
+where
+ I: ExactSizeIterator,
+ J: ExactSizeIterator<Item = I::Item>,
+{
+ #[inline]
+ fn len(&self) -> usize {
+ self.i.len() + self.j.len()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/interleave_shortest.rs b/third_party/rust/rayon/src/iter/interleave_shortest.rs
new file mode 100644
index 0000000000..7d81369807
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/interleave_shortest.rs
@@ -0,0 +1,85 @@
+use super::plumbing::*;
+use super::*;
+
+/// `InterleaveShortest` is an iterator that works similarly to
+/// `Interleave`, but this version stops returning elements once one
+/// of the iterators run out.
+///
+/// This struct is created by the [`interleave_shortest()`] method on
+/// [`IndexedParallelIterator`].
+///
+/// [`interleave_shortest()`]: trait.IndexedParallelIterator.html#method.interleave_shortest
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct InterleaveShortest<I, J>
+where
+ I: IndexedParallelIterator,
+ J: IndexedParallelIterator<Item = I::Item>,
+{
+ interleave: Interleave<Take<I>, Take<J>>,
+}
+
+impl<I, J> InterleaveShortest<I, J>
+where
+ I: IndexedParallelIterator,
+ J: IndexedParallelIterator<Item = I::Item>,
+{
+ /// Creates a new `InterleaveShortest` iterator
+ pub(super) fn new(i: I, j: J) -> Self {
+ InterleaveShortest {
+ interleave: if i.len() <= j.len() {
+ // take equal lengths from both iterators
+ let n = i.len();
+ i.take(n).interleave(j.take(n))
+ } else {
+ // take one extra item from the first iterator
+ let n = j.len();
+ i.take(n + 1).interleave(j.take(n))
+ },
+ }
+ }
+}
+
+impl<I, J> ParallelIterator for InterleaveShortest<I, J>
+where
+ I: IndexedParallelIterator,
+ J: IndexedParallelIterator<Item = I::Item>,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<I::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I, J> IndexedParallelIterator for InterleaveShortest<I, J>
+where
+ I: IndexedParallelIterator,
+ J: IndexedParallelIterator<Item = I::Item>,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn len(&self) -> usize {
+ self.interleave.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ self.interleave.with_producer(callback)
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/intersperse.rs b/third_party/rust/rayon/src/iter/intersperse.rs
new file mode 100644
index 0000000000..798bdc1d67
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/intersperse.rs
@@ -0,0 +1,410 @@
+use super::plumbing::*;
+use super::*;
+use std::cell::Cell;
+use std::iter::{self, Fuse};
+
+/// `Intersperse` is an iterator that inserts a particular item between each
+/// item of the adapted iterator. This struct is created by the
+/// [`intersperse()`] method on [`ParallelIterator`]
+///
+/// [`intersperse()`]: trait.ParallelIterator.html#method.intersperse
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone, Debug)]
+pub struct Intersperse<I>
+where
+ I: ParallelIterator,
+ I::Item: Clone,
+{
+ base: I,
+ item: I::Item,
+}
+
+impl<I> Intersperse<I>
+where
+ I: ParallelIterator,
+ I::Item: Clone,
+{
+ /// Creates a new `Intersperse` iterator
+ pub(super) fn new(base: I, item: I::Item) -> Self {
+ Intersperse { base, item }
+ }
+}
+
+impl<I> ParallelIterator for Intersperse<I>
+where
+ I: ParallelIterator,
+ I::Item: Clone + Send,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<I::Item>,
+ {
+ let consumer1 = IntersperseConsumer::new(consumer, self.item);
+ self.base.drive_unindexed(consumer1)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ match self.base.opt_len()? {
+ 0 => Some(0),
+ len => len.checked_add(len - 1),
+ }
+ }
+}
+
+impl<I> IndexedParallelIterator for Intersperse<I>
+where
+ I: IndexedParallelIterator,
+ I::Item: Clone + Send,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ let consumer1 = IntersperseConsumer::new(consumer, self.item);
+ self.base.drive(consumer1)
+ }
+
+ fn len(&self) -> usize {
+ let len = self.base.len();
+ if len > 0 {
+ len.checked_add(len - 1).expect("overflow")
+ } else {
+ 0
+ }
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ let len = self.len();
+ return self.base.with_producer(Callback {
+ callback,
+ item: self.item,
+ len,
+ });
+
+ struct Callback<CB, T> {
+ callback: CB,
+ item: T,
+ len: usize,
+ }
+
+ impl<T, CB> ProducerCallback<T> for Callback<CB, T>
+ where
+ CB: ProducerCallback<T>,
+ T: Clone + Send,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let producer = IntersperseProducer::new(base, self.item, self.len);
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+struct IntersperseProducer<P>
+where
+ P: Producer,
+{
+ base: P,
+ item: P::Item,
+ len: usize,
+ clone_first: bool,
+}
+
+impl<P> IntersperseProducer<P>
+where
+ P: Producer,
+{
+ fn new(base: P, item: P::Item, len: usize) -> Self {
+ IntersperseProducer {
+ base,
+ item,
+ len,
+ clone_first: false,
+ }
+ }
+}
+
+impl<P> Producer for IntersperseProducer<P>
+where
+ P: Producer,
+ P::Item: Clone + Send,
+{
+ type Item = P::Item;
+ type IntoIter = IntersperseIter<P::IntoIter>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ IntersperseIter {
+ base: self.base.into_iter().fuse(),
+ item: self.item,
+ clone_first: self.len > 0 && self.clone_first,
+
+ // If there's more than one item, then even lengths end the opposite
+ // of how they started with respect to interspersed clones.
+ clone_last: self.len > 1 && ((self.len & 1 == 0) ^ self.clone_first),
+ }
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ debug_assert!(index <= self.len);
+
+ // The left needs half of the items from the base producer, and the
+ // other half will be our interspersed item. If we're not leading with
+ // a cloned item, then we need to round up the base number of items,
+ // otherwise round down.
+ let base_index = (index + !self.clone_first as usize) / 2;
+ let (left_base, right_base) = self.base.split_at(base_index);
+
+ let left = IntersperseProducer {
+ base: left_base,
+ item: self.item.clone(),
+ len: index,
+ clone_first: self.clone_first,
+ };
+
+ let right = IntersperseProducer {
+ base: right_base,
+ item: self.item,
+ len: self.len - index,
+
+ // If the index is odd, the right side toggles `clone_first`.
+ clone_first: (index & 1 == 1) ^ self.clone_first,
+ };
+
+ (left, right)
+ }
+
+ fn fold_with<F>(self, folder: F) -> F
+ where
+ F: Folder<Self::Item>,
+ {
+ let folder1 = IntersperseFolder {
+ base: folder,
+ item: self.item,
+ clone_first: self.clone_first,
+ };
+ self.base.fold_with(folder1).base
+ }
+}
+
+struct IntersperseIter<I>
+where
+ I: Iterator,
+{
+ base: Fuse<I>,
+ item: I::Item,
+ clone_first: bool,
+ clone_last: bool,
+}
+
+impl<I> Iterator for IntersperseIter<I>
+where
+ I: DoubleEndedIterator + ExactSizeIterator,
+ I::Item: Clone,
+{
+ type Item = I::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.clone_first {
+ self.clone_first = false;
+ Some(self.item.clone())
+ } else if let next @ Some(_) = self.base.next() {
+ // If there are any items left, we'll need another clone in front.
+ self.clone_first = self.base.len() != 0;
+ next
+ } else if self.clone_last {
+ self.clone_last = false;
+ Some(self.item.clone())
+ } else {
+ None
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl<I> DoubleEndedIterator for IntersperseIter<I>
+where
+ I: DoubleEndedIterator + ExactSizeIterator,
+ I::Item: Clone,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.clone_last {
+ self.clone_last = false;
+ Some(self.item.clone())
+ } else if let next_back @ Some(_) = self.base.next_back() {
+ // If there are any items left, we'll need another clone in back.
+ self.clone_last = self.base.len() != 0;
+ next_back
+ } else if self.clone_first {
+ self.clone_first = false;
+ Some(self.item.clone())
+ } else {
+ None
+ }
+ }
+}
+
+impl<I> ExactSizeIterator for IntersperseIter<I>
+where
+ I: DoubleEndedIterator + ExactSizeIterator,
+ I::Item: Clone,
+{
+ fn len(&self) -> usize {
+ let len = self.base.len();
+ len + len.saturating_sub(1) + self.clone_first as usize + self.clone_last as usize
+ }
+}
+
+struct IntersperseConsumer<C, T> {
+ base: C,
+ item: T,
+ clone_first: Cell<bool>,
+}
+
+impl<C, T> IntersperseConsumer<C, T>
+where
+ C: Consumer<T>,
+{
+ fn new(base: C, item: T) -> Self {
+ IntersperseConsumer {
+ base,
+ item,
+ clone_first: false.into(),
+ }
+ }
+}
+
+impl<C, T> Consumer<T> for IntersperseConsumer<C, T>
+where
+ C: Consumer<T>,
+ T: Clone + Send,
+{
+ type Folder = IntersperseFolder<C::Folder, T>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(mut self, index: usize) -> (Self, Self, Self::Reducer) {
+ // We'll feed twice as many items to the base consumer, except if we're
+ // not currently leading with a cloned item, then it's one less.
+ let base_index = index + index.saturating_sub(!self.clone_first.get() as usize);
+ let (left, right, reducer) = self.base.split_at(base_index);
+
+ let right = IntersperseConsumer {
+ base: right,
+ item: self.item.clone(),
+ clone_first: true.into(),
+ };
+ self.base = left;
+ (self, right, reducer)
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ IntersperseFolder {
+ base: self.base.into_folder(),
+ item: self.item,
+ clone_first: self.clone_first.get(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<C, T> UnindexedConsumer<T> for IntersperseConsumer<C, T>
+where
+ C: UnindexedConsumer<T>,
+ T: Clone + Send,
+{
+ fn split_off_left(&self) -> Self {
+ let left = IntersperseConsumer {
+ base: self.base.split_off_left(),
+ item: self.item.clone(),
+ clone_first: self.clone_first.clone(),
+ };
+ self.clone_first.set(true);
+ left
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct IntersperseFolder<C, T> {
+ base: C,
+ item: T,
+ clone_first: bool,
+}
+
+impl<C, T> Folder<T> for IntersperseFolder<C, T>
+where
+ C: Folder<T>,
+ T: Clone,
+{
+ type Result = C::Result;
+
+ fn consume(mut self, item: T) -> Self {
+ if self.clone_first {
+ self.base = self.base.consume(self.item.clone());
+ if self.base.full() {
+ return self;
+ }
+ } else {
+ self.clone_first = true;
+ }
+ self.base = self.base.consume(item);
+ self
+ }
+
+ fn consume_iter<I>(self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ let mut clone_first = self.clone_first;
+ let between_item = self.item;
+ let base = self.base.consume_iter(iter.into_iter().flat_map(|item| {
+ let first = if clone_first {
+ Some(between_item.clone())
+ } else {
+ clone_first = true;
+ None
+ };
+ first.into_iter().chain(iter::once(item))
+ }));
+ IntersperseFolder {
+ base,
+ item: between_item,
+ clone_first,
+ }
+ }
+
+ fn complete(self) -> C::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/len.rs b/third_party/rust/rayon/src/iter/len.rs
new file mode 100644
index 0000000000..8ec7f33a15
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/len.rs
@@ -0,0 +1,271 @@
+use super::plumbing::*;
+use super::*;
+use std::cmp;
+
+/// `MinLen` is an iterator that imposes a minimum length on iterator splits.
+/// This struct is created by the [`with_min_len()`] method on [`IndexedParallelIterator`]
+///
+/// [`with_min_len()`]: trait.IndexedParallelIterator.html#method.with_min_len
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct MinLen<I: IndexedParallelIterator> {
+ base: I,
+ min: usize,
+}
+
+impl<I> MinLen<I>
+where
+ I: IndexedParallelIterator,
+{
+ /// Creates a new `MinLen` iterator.
+ pub(super) fn new(base: I, min: usize) -> Self {
+ MinLen { base, min }
+ }
+}
+
+impl<I> ParallelIterator for MinLen<I>
+where
+ I: IndexedParallelIterator,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I> IndexedParallelIterator for MinLen<I>
+where
+ I: IndexedParallelIterator,
+{
+ fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
+ bridge(self, consumer)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback {
+ callback,
+ min: self.min,
+ });
+
+ struct Callback<CB> {
+ callback: CB,
+ min: usize,
+ }
+
+ impl<T, CB> ProducerCallback<T> for Callback<CB>
+ where
+ CB: ProducerCallback<T>,
+ {
+ type Output = CB::Output;
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let producer = MinLenProducer {
+ base,
+ min: self.min,
+ };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// `MinLenProducer` implementation
+
+struct MinLenProducer<P> {
+ base: P,
+ min: usize,
+}
+
+impl<P> Producer for MinLenProducer<P>
+where
+ P: Producer,
+{
+ type Item = P::Item;
+ type IntoIter = P::IntoIter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.base.into_iter()
+ }
+
+ fn min_len(&self) -> usize {
+ cmp::max(self.min, self.base.min_len())
+ }
+
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(index);
+ (
+ MinLenProducer {
+ base: left,
+ min: self.min,
+ },
+ MinLenProducer {
+ base: right,
+ min: self.min,
+ },
+ )
+ }
+
+ fn fold_with<F>(self, folder: F) -> F
+ where
+ F: Folder<Self::Item>,
+ {
+ self.base.fold_with(folder)
+ }
+}
+
+/// `MaxLen` is an iterator that imposes a maximum length on iterator splits.
+/// This struct is created by the [`with_max_len()`] method on [`IndexedParallelIterator`]
+///
+/// [`with_max_len()`]: trait.IndexedParallelIterator.html#method.with_max_len
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct MaxLen<I: IndexedParallelIterator> {
+ base: I,
+ max: usize,
+}
+
+impl<I> MaxLen<I>
+where
+ I: IndexedParallelIterator,
+{
+ /// Creates a new `MaxLen` iterator.
+ pub(super) fn new(base: I, max: usize) -> Self {
+ MaxLen { base, max }
+ }
+}
+
+impl<I> ParallelIterator for MaxLen<I>
+where
+ I: IndexedParallelIterator,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I> IndexedParallelIterator for MaxLen<I>
+where
+ I: IndexedParallelIterator,
+{
+ fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
+ bridge(self, consumer)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback {
+ callback,
+ max: self.max,
+ });
+
+ struct Callback<CB> {
+ callback: CB,
+ max: usize,
+ }
+
+ impl<T, CB> ProducerCallback<T> for Callback<CB>
+ where
+ CB: ProducerCallback<T>,
+ {
+ type Output = CB::Output;
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let producer = MaxLenProducer {
+ base,
+ max: self.max,
+ };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// `MaxLenProducer` implementation
+
+struct MaxLenProducer<P> {
+ base: P,
+ max: usize,
+}
+
+impl<P> Producer for MaxLenProducer<P>
+where
+ P: Producer,
+{
+ type Item = P::Item;
+ type IntoIter = P::IntoIter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.base.into_iter()
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+
+ fn max_len(&self) -> usize {
+ cmp::min(self.max, self.base.max_len())
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(index);
+ (
+ MaxLenProducer {
+ base: left,
+ max: self.max,
+ },
+ MaxLenProducer {
+ base: right,
+ max: self.max,
+ },
+ )
+ }
+
+ fn fold_with<F>(self, folder: F) -> F
+ where
+ F: Folder<Self::Item>,
+ {
+ self.base.fold_with(folder)
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/map.rs b/third_party/rust/rayon/src/iter/map.rs
new file mode 100644
index 0000000000..da14d4082c
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/map.rs
@@ -0,0 +1,259 @@
+use super::plumbing::*;
+use super::*;
+
+use std::fmt::{self, Debug};
+use std::iter;
+
+/// `Map` is an iterator that transforms the elements of an underlying iterator.
+///
+/// This struct is created by the [`map()`] method on [`ParallelIterator`]
+///
+/// [`map()`]: trait.ParallelIterator.html#method.map
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct Map<I: ParallelIterator, F> {
+ base: I,
+ map_op: F,
+}
+
+impl<I: ParallelIterator + Debug, F> Debug for Map<I, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Map").field("base", &self.base).finish()
+ }
+}
+
+impl<I, F> Map<I, F>
+where
+ I: ParallelIterator,
+{
+ /// Creates a new `Map` iterator.
+ pub(super) fn new(base: I, map_op: F) -> Self {
+ Map { base, map_op }
+ }
+}
+
+impl<I, F, R> ParallelIterator for Map<I, F>
+where
+ I: ParallelIterator,
+ F: Fn(I::Item) -> R + Sync + Send,
+ R: Send,
+{
+ type Item = F::Output;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = MapConsumer::new(consumer, &self.map_op);
+ self.base.drive_unindexed(consumer1)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ self.base.opt_len()
+ }
+}
+
+impl<I, F, R> IndexedParallelIterator for Map<I, F>
+where
+ I: IndexedParallelIterator,
+ F: Fn(I::Item) -> R + Sync + Send,
+ R: Send,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ let consumer1 = MapConsumer::new(consumer, &self.map_op);
+ self.base.drive(consumer1)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback {
+ callback,
+ map_op: self.map_op,
+ });
+
+ struct Callback<CB, F> {
+ callback: CB,
+ map_op: F,
+ }
+
+ impl<T, F, R, CB> ProducerCallback<T> for Callback<CB, F>
+ where
+ CB: ProducerCallback<R>,
+ F: Fn(T) -> R + Sync,
+ R: Send,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let producer = MapProducer {
+ base,
+ map_op: &self.map_op,
+ };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+
+struct MapProducer<'f, P, F> {
+ base: P,
+ map_op: &'f F,
+}
+
+impl<'f, P, F, R> Producer for MapProducer<'f, P, F>
+where
+ P: Producer,
+ F: Fn(P::Item) -> R + Sync,
+ R: Send,
+{
+ type Item = F::Output;
+ type IntoIter = iter::Map<P::IntoIter, &'f F>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.base.into_iter().map(self.map_op)
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(index);
+ (
+ MapProducer {
+ base: left,
+ map_op: self.map_op,
+ },
+ MapProducer {
+ base: right,
+ map_op: self.map_op,
+ },
+ )
+ }
+
+ fn fold_with<G>(self, folder: G) -> G
+ where
+ G: Folder<Self::Item>,
+ {
+ let folder1 = MapFolder {
+ base: folder,
+ map_op: self.map_op,
+ };
+ self.base.fold_with(folder1).base
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct MapConsumer<'f, C, F> {
+ base: C,
+ map_op: &'f F,
+}
+
+impl<'f, C, F> MapConsumer<'f, C, F> {
+ fn new(base: C, map_op: &'f F) -> Self {
+ MapConsumer { base, map_op }
+ }
+}
+
+impl<'f, T, R, C, F> Consumer<T> for MapConsumer<'f, C, F>
+where
+ C: Consumer<F::Output>,
+ F: Fn(T) -> R + Sync,
+ R: Send,
+{
+ type Folder = MapFolder<'f, C::Folder, F>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ MapConsumer::new(left, self.map_op),
+ MapConsumer::new(right, self.map_op),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ MapFolder {
+ base: self.base.into_folder(),
+ map_op: self.map_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'f, T, R, C, F> UnindexedConsumer<T> for MapConsumer<'f, C, F>
+where
+ C: UnindexedConsumer<F::Output>,
+ F: Fn(T) -> R + Sync,
+ R: Send,
+{
+ fn split_off_left(&self) -> Self {
+ MapConsumer::new(self.base.split_off_left(), self.map_op)
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct MapFolder<'f, C, F> {
+ base: C,
+ map_op: &'f F,
+}
+
+impl<'f, T, R, C, F> Folder<T> for MapFolder<'f, C, F>
+where
+ C: Folder<F::Output>,
+ F: Fn(T) -> R,
+{
+ type Result = C::Result;
+
+ fn consume(self, item: T) -> Self {
+ let mapped_item = (self.map_op)(item);
+ MapFolder {
+ base: self.base.consume(mapped_item),
+ map_op: self.map_op,
+ }
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ self.base = self.base.consume_iter(iter.into_iter().map(self.map_op));
+ self
+ }
+
+ fn complete(self) -> C::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/map_with.rs b/third_party/rust/rayon/src/iter/map_with.rs
new file mode 100644
index 0000000000..10b1b4caca
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/map_with.rs
@@ -0,0 +1,573 @@
+use super::plumbing::*;
+use super::*;
+
+use std::fmt::{self, Debug};
+
+/// `MapWith` is an iterator that transforms the elements of an underlying iterator.
+///
+/// This struct is created by the [`map_with()`] method on [`ParallelIterator`]
+///
+/// [`map_with()`]: trait.ParallelIterator.html#method.map_with
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct MapWith<I: ParallelIterator, T, F> {
+ base: I,
+ item: T,
+ map_op: F,
+}
+
+impl<I: ParallelIterator + Debug, T: Debug, F> Debug for MapWith<I, T, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MapWith")
+ .field("base", &self.base)
+ .field("item", &self.item)
+ .finish()
+ }
+}
+
+impl<I, T, F> MapWith<I, T, F>
+where
+ I: ParallelIterator,
+{
+ /// Creates a new `MapWith` iterator.
+ pub(super) fn new(base: I, item: T, map_op: F) -> Self {
+ MapWith { base, item, map_op }
+ }
+}
+
+impl<I, T, F, R> ParallelIterator for MapWith<I, T, F>
+where
+ I: ParallelIterator,
+ T: Send + Clone,
+ F: Fn(&mut T, I::Item) -> R + Sync + Send,
+ R: Send,
+{
+ type Item = R;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = MapWithConsumer::new(consumer, self.item, &self.map_op);
+ self.base.drive_unindexed(consumer1)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ self.base.opt_len()
+ }
+}
+
+impl<I, T, F, R> IndexedParallelIterator for MapWith<I, T, F>
+where
+ I: IndexedParallelIterator,
+ T: Send + Clone,
+ F: Fn(&mut T, I::Item) -> R + Sync + Send,
+ R: Send,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ let consumer1 = MapWithConsumer::new(consumer, self.item, &self.map_op);
+ self.base.drive(consumer1)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback {
+ callback,
+ item: self.item,
+ map_op: self.map_op,
+ });
+
+ struct Callback<CB, U, F> {
+ callback: CB,
+ item: U,
+ map_op: F,
+ }
+
+ impl<T, U, F, R, CB> ProducerCallback<T> for Callback<CB, U, F>
+ where
+ CB: ProducerCallback<R>,
+ U: Send + Clone,
+ F: Fn(&mut U, T) -> R + Sync,
+ R: Send,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let producer = MapWithProducer {
+ base,
+ item: self.item,
+ map_op: &self.map_op,
+ };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+
+struct MapWithProducer<'f, P, U, F> {
+ base: P,
+ item: U,
+ map_op: &'f F,
+}
+
+impl<'f, P, U, F, R> Producer for MapWithProducer<'f, P, U, F>
+where
+ P: Producer,
+ U: Send + Clone,
+ F: Fn(&mut U, P::Item) -> R + Sync,
+ R: Send,
+{
+ type Item = R;
+ type IntoIter = MapWithIter<'f, P::IntoIter, U, F>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ MapWithIter {
+ base: self.base.into_iter(),
+ item: self.item,
+ map_op: self.map_op,
+ }
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(index);
+ (
+ MapWithProducer {
+ base: left,
+ item: self.item.clone(),
+ map_op: self.map_op,
+ },
+ MapWithProducer {
+ base: right,
+ item: self.item,
+ map_op: self.map_op,
+ },
+ )
+ }
+
+ fn fold_with<G>(self, folder: G) -> G
+ where
+ G: Folder<Self::Item>,
+ {
+ let folder1 = MapWithFolder {
+ base: folder,
+ item: self.item,
+ map_op: self.map_op,
+ };
+ self.base.fold_with(folder1).base
+ }
+}
+
+struct MapWithIter<'f, I, U, F> {
+ base: I,
+ item: U,
+ map_op: &'f F,
+}
+
+impl<'f, I, U, F, R> Iterator for MapWithIter<'f, I, U, F>
+where
+ I: Iterator,
+ F: Fn(&mut U, I::Item) -> R + Sync,
+ R: Send,
+{
+ type Item = R;
+
+ fn next(&mut self) -> Option<R> {
+ let item = self.base.next()?;
+ Some((self.map_op)(&mut self.item, item))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.base.size_hint()
+ }
+}
+
+impl<'f, I, U, F, R> DoubleEndedIterator for MapWithIter<'f, I, U, F>
+where
+ I: DoubleEndedIterator,
+ F: Fn(&mut U, I::Item) -> R + Sync,
+ R: Send,
+{
+ fn next_back(&mut self) -> Option<R> {
+ let item = self.base.next_back()?;
+ Some((self.map_op)(&mut self.item, item))
+ }
+}
+
+impl<'f, I, U, F, R> ExactSizeIterator for MapWithIter<'f, I, U, F>
+where
+ I: ExactSizeIterator,
+ F: Fn(&mut U, I::Item) -> R + Sync,
+ R: Send,
+{
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct MapWithConsumer<'f, C, U, F> {
+ base: C,
+ item: U,
+ map_op: &'f F,
+}
+
+impl<'f, C, U, F> MapWithConsumer<'f, C, U, F> {
+ fn new(base: C, item: U, map_op: &'f F) -> Self {
+ MapWithConsumer { base, item, map_op }
+ }
+}
+
+impl<'f, T, U, R, C, F> Consumer<T> for MapWithConsumer<'f, C, U, F>
+where
+ C: Consumer<R>,
+ U: Send + Clone,
+ F: Fn(&mut U, T) -> R + Sync,
+ R: Send,
+{
+ type Folder = MapWithFolder<'f, C::Folder, U, F>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ MapWithConsumer::new(left, self.item.clone(), self.map_op),
+ MapWithConsumer::new(right, self.item, self.map_op),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ MapWithFolder {
+ base: self.base.into_folder(),
+ item: self.item,
+ map_op: self.map_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'f, T, U, R, C, F> UnindexedConsumer<T> for MapWithConsumer<'f, C, U, F>
+where
+ C: UnindexedConsumer<R>,
+ U: Send + Clone,
+ F: Fn(&mut U, T) -> R + Sync,
+ R: Send,
+{
+ fn split_off_left(&self) -> Self {
+ MapWithConsumer::new(self.base.split_off_left(), self.item.clone(), self.map_op)
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct MapWithFolder<'f, C, U, F> {
+ base: C,
+ item: U,
+ map_op: &'f F,
+}
+
+impl<'f, T, U, R, C, F> Folder<T> for MapWithFolder<'f, C, U, F>
+where
+ C: Folder<R>,
+ F: Fn(&mut U, T) -> R,
+{
+ type Result = C::Result;
+
+ fn consume(mut self, item: T) -> Self {
+ let mapped_item = (self.map_op)(&mut self.item, item);
+ self.base = self.base.consume(mapped_item);
+ self
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ fn with<'f, T, U, R>(
+ item: &'f mut U,
+ map_op: impl Fn(&mut U, T) -> R + 'f,
+ ) -> impl FnMut(T) -> R + 'f {
+ move |x| map_op(item, x)
+ }
+
+ {
+ let mapped_iter = iter.into_iter().map(with(&mut self.item, self.map_op));
+ self.base = self.base.consume_iter(mapped_iter);
+ }
+ self
+ }
+
+ fn complete(self) -> C::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+
+/// `MapInit` is an iterator that transforms the elements of an underlying iterator.
+///
+/// This struct is created by the [`map_init()`] method on [`ParallelIterator`]
+///
+/// [`map_init()`]: trait.ParallelIterator.html#method.map_init
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct MapInit<I: ParallelIterator, INIT, F> {
+ base: I,
+ init: INIT,
+ map_op: F,
+}
+
+impl<I: ParallelIterator + Debug, INIT, F> Debug for MapInit<I, INIT, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MapInit").field("base", &self.base).finish()
+ }
+}
+
+impl<I, INIT, F> MapInit<I, INIT, F>
+where
+ I: ParallelIterator,
+{
+ /// Creates a new `MapInit` iterator.
+ pub(super) fn new(base: I, init: INIT, map_op: F) -> Self {
+ MapInit { base, init, map_op }
+ }
+}
+
+impl<I, INIT, T, F, R> ParallelIterator for MapInit<I, INIT, F>
+where
+ I: ParallelIterator,
+ INIT: Fn() -> T + Sync + Send,
+ F: Fn(&mut T, I::Item) -> R + Sync + Send,
+ R: Send,
+{
+ type Item = R;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = MapInitConsumer::new(consumer, &self.init, &self.map_op);
+ self.base.drive_unindexed(consumer1)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ self.base.opt_len()
+ }
+}
+
+impl<I, INIT, T, F, R> IndexedParallelIterator for MapInit<I, INIT, F>
+where
+ I: IndexedParallelIterator,
+ INIT: Fn() -> T + Sync + Send,
+ F: Fn(&mut T, I::Item) -> R + Sync + Send,
+ R: Send,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ let consumer1 = MapInitConsumer::new(consumer, &self.init, &self.map_op);
+ self.base.drive(consumer1)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback {
+ callback,
+ init: self.init,
+ map_op: self.map_op,
+ });
+
+ struct Callback<CB, INIT, F> {
+ callback: CB,
+ init: INIT,
+ map_op: F,
+ }
+
+ impl<T, INIT, U, F, R, CB> ProducerCallback<T> for Callback<CB, INIT, F>
+ where
+ CB: ProducerCallback<R>,
+ INIT: Fn() -> U + Sync,
+ F: Fn(&mut U, T) -> R + Sync,
+ R: Send,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let producer = MapInitProducer {
+ base,
+ init: &self.init,
+ map_op: &self.map_op,
+ };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+
+struct MapInitProducer<'f, P, INIT, F> {
+ base: P,
+ init: &'f INIT,
+ map_op: &'f F,
+}
+
+impl<'f, P, INIT, U, F, R> Producer for MapInitProducer<'f, P, INIT, F>
+where
+ P: Producer,
+ INIT: Fn() -> U + Sync,
+ F: Fn(&mut U, P::Item) -> R + Sync,
+ R: Send,
+{
+ type Item = R;
+ type IntoIter = MapWithIter<'f, P::IntoIter, U, F>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ MapWithIter {
+ base: self.base.into_iter(),
+ item: (self.init)(),
+ map_op: self.map_op,
+ }
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(index);
+ (
+ MapInitProducer {
+ base: left,
+ init: self.init,
+ map_op: self.map_op,
+ },
+ MapInitProducer {
+ base: right,
+ init: self.init,
+ map_op: self.map_op,
+ },
+ )
+ }
+
+ fn fold_with<G>(self, folder: G) -> G
+ where
+ G: Folder<Self::Item>,
+ {
+ let folder1 = MapWithFolder {
+ base: folder,
+ item: (self.init)(),
+ map_op: self.map_op,
+ };
+ self.base.fold_with(folder1).base
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct MapInitConsumer<'f, C, INIT, F> {
+ base: C,
+ init: &'f INIT,
+ map_op: &'f F,
+}
+
+impl<'f, C, INIT, F> MapInitConsumer<'f, C, INIT, F> {
+ fn new(base: C, init: &'f INIT, map_op: &'f F) -> Self {
+ MapInitConsumer { base, init, map_op }
+ }
+}
+
+impl<'f, T, INIT, U, R, C, F> Consumer<T> for MapInitConsumer<'f, C, INIT, F>
+where
+ C: Consumer<R>,
+ INIT: Fn() -> U + Sync,
+ F: Fn(&mut U, T) -> R + Sync,
+ R: Send,
+{
+ type Folder = MapWithFolder<'f, C::Folder, U, F>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ MapInitConsumer::new(left, self.init, self.map_op),
+ MapInitConsumer::new(right, self.init, self.map_op),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ MapWithFolder {
+ base: self.base.into_folder(),
+ item: (self.init)(),
+ map_op: self.map_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'f, T, INIT, U, R, C, F> UnindexedConsumer<T> for MapInitConsumer<'f, C, INIT, F>
+where
+ C: UnindexedConsumer<R>,
+ INIT: Fn() -> U + Sync,
+ F: Fn(&mut U, T) -> R + Sync,
+ R: Send,
+{
+ fn split_off_left(&self) -> Self {
+ MapInitConsumer::new(self.base.split_off_left(), self.init, self.map_op)
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/mod.rs b/third_party/rust/rayon/src/iter/mod.rs
new file mode 100644
index 0000000000..98c93267f4
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/mod.rs
@@ -0,0 +1,3385 @@
+//! Traits for writing parallel programs using an iterator-style interface
+//!
+//! You will rarely need to interact with this module directly unless you have
+//! need to name one of the iterator types.
+//!
+//! Parallel iterators make it easy to write iterator-like chains that
+//! execute in parallel: typically all you have to do is convert the
+//! first `.iter()` (or `iter_mut()`, `into_iter()`, etc) method into
+//! `par_iter()` (or `par_iter_mut()`, `into_par_iter()`, etc). For
+//! example, to compute the sum of the squares of a sequence of
+//! integers, one might write:
+//!
+//! ```rust
+//! use rayon::prelude::*;
+//! fn sum_of_squares(input: &[i32]) -> i32 {
+//! input.par_iter()
+//! .map(|i| i * i)
+//! .sum()
+//! }
+//! ```
+//!
+//! Or, to increment all the integers in a slice, you could write:
+//!
+//! ```rust
+//! use rayon::prelude::*;
+//! fn increment_all(input: &mut [i32]) {
+//! input.par_iter_mut()
+//! .for_each(|p| *p += 1);
+//! }
+//! ```
+//!
+//! To use parallel iterators, first import the traits by adding
+//! something like `use rayon::prelude::*` to your module. You can
+//! then call `par_iter`, `par_iter_mut`, or `into_par_iter` to get a
+//! parallel iterator. Like a [regular iterator][], parallel
+//! iterators work by first constructing a computation and then
+//! executing it.
+//!
+//! In addition to `par_iter()` and friends, some types offer other
+//! ways to create (or consume) parallel iterators:
+//!
+//! - Slices (`&[T]`, `&mut [T]`) offer methods like `par_split` and
+//! `par_windows`, as well as various parallel sorting
+//! operations. See [the `ParallelSlice` trait] for the full list.
+//! - Strings (`&str`) offer methods like `par_split` and `par_lines`.
+//! See [the `ParallelString` trait] for the full list.
+//! - Various collections offer [`par_extend`], which grows a
+//! collection given a parallel iterator. (If you don't have a
+//! collection to extend, you can use [`collect()`] to create a new
+//! one from scratch.)
+//!
+//! [the `ParallelSlice` trait]: ../slice/trait.ParallelSlice.html
+//! [the `ParallelString` trait]: ../str/trait.ParallelString.html
+//! [`par_extend`]: trait.ParallelExtend.html
+//! [`collect()`]: trait.ParallelIterator.html#method.collect
+//!
+//! To see the full range of methods available on parallel iterators,
+//! check out the [`ParallelIterator`] and [`IndexedParallelIterator`]
+//! traits.
+//!
+//! If you'd like to build a custom parallel iterator, or to write your own
+//! combinator, then check out the [split] function and the [plumbing] module.
+//!
+//! [regular iterator]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
+//! [`ParallelIterator`]: trait.ParallelIterator.html
+//! [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+//! [split]: fn.split.html
+//! [plumbing]: plumbing/index.html
+//!
+//! Note: Several of the `ParallelIterator` methods rely on a `Try` trait which
+//! has been deliberately obscured from the public API. This trait is intended
+//! to mirror the unstable `std::ops::Try` with implementations for `Option` and
+//! `Result`, where `Some`/`Ok` values will let those iterators continue, but
+//! `None`/`Err` values will exit early.
+//!
+//! A note about object safety: It is currently _not_ possible to wrap
+//! a `ParallelIterator` (or any trait that depends on it) using a
+//! `Box<dyn ParallelIterator>` or other kind of dynamic allocation,
+//! because `ParallelIterator` is **not object-safe**.
+//! (This keeps the implementation simpler and allows extra optimizations.)
+
+use self::plumbing::*;
+use self::private::Try;
+pub use either::Either;
+use std::cmp::{self, Ordering};
+use std::iter::{Product, Sum};
+use std::ops::{Fn, RangeBounds};
+
+pub mod plumbing;
+
+#[cfg(test)]
+mod test;
+
+// There is a method to the madness here:
+//
+// - These modules are private but expose certain types to the end-user
+// (e.g., `enumerate::Enumerate`) -- specifically, the types that appear in the
+// public API surface of the `ParallelIterator` traits.
+// - In **this** module, those public types are always used unprefixed, which forces
+// us to add a `pub use` and helps identify if we missed anything.
+// - In contrast, items that appear **only** in the body of a method,
+// e.g. `find::find()`, are always used **prefixed**, so that they
+// can be readily distinguished.
+
+mod chain;
+mod chunks;
+mod cloned;
+mod collect;
+mod copied;
+mod empty;
+mod enumerate;
+mod extend;
+mod filter;
+mod filter_map;
+mod find;
+mod find_first_last;
+mod flat_map;
+mod flat_map_iter;
+mod flatten;
+mod flatten_iter;
+mod fold;
+mod fold_chunks;
+mod fold_chunks_with;
+mod for_each;
+mod from_par_iter;
+mod inspect;
+mod interleave;
+mod interleave_shortest;
+mod intersperse;
+mod len;
+mod map;
+mod map_with;
+mod multizip;
+mod noop;
+mod once;
+mod panic_fuse;
+mod par_bridge;
+mod positions;
+mod product;
+mod reduce;
+mod repeat;
+mod rev;
+mod skip;
+mod splitter;
+mod step_by;
+mod sum;
+mod take;
+mod try_fold;
+mod try_reduce;
+mod try_reduce_with;
+mod unzip;
+mod update;
+mod while_some;
+mod zip;
+mod zip_eq;
+
+pub use self::{
+ chain::Chain,
+ chunks::Chunks,
+ cloned::Cloned,
+ copied::Copied,
+ empty::{empty, Empty},
+ enumerate::Enumerate,
+ filter::Filter,
+ filter_map::FilterMap,
+ flat_map::FlatMap,
+ flat_map_iter::FlatMapIter,
+ flatten::Flatten,
+ flatten_iter::FlattenIter,
+ fold::{Fold, FoldWith},
+ fold_chunks::FoldChunks,
+ fold_chunks_with::FoldChunksWith,
+ inspect::Inspect,
+ interleave::Interleave,
+ interleave_shortest::InterleaveShortest,
+ intersperse::Intersperse,
+ len::{MaxLen, MinLen},
+ map::Map,
+ map_with::{MapInit, MapWith},
+ multizip::MultiZip,
+ once::{once, Once},
+ panic_fuse::PanicFuse,
+ par_bridge::{IterBridge, ParallelBridge},
+ positions::Positions,
+ repeat::{repeat, repeatn, Repeat, RepeatN},
+ rev::Rev,
+ skip::Skip,
+ splitter::{split, Split},
+ step_by::StepBy,
+ take::Take,
+ try_fold::{TryFold, TryFoldWith},
+ update::Update,
+ while_some::WhileSome,
+ zip::Zip,
+ zip_eq::ZipEq,
+};
+
+/// `IntoParallelIterator` implements the conversion to a [`ParallelIterator`].
+///
+/// By implementing `IntoParallelIterator` for a type, you define how it will
+/// transformed into an iterator. This is a parallel version of the standard
+/// library's [`std::iter::IntoIterator`] trait.
+///
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+/// [`std::iter::IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
+pub trait IntoParallelIterator {
+ /// The parallel iterator type that will be created.
+ type Iter: ParallelIterator<Item = Self::Item>;
+
+ /// The type of item that the parallel iterator will produce.
+ type Item: Send;
+
+ /// Converts `self` into a parallel iterator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// println!("counting in parallel:");
+ /// (0..100).into_par_iter()
+ /// .for_each(|i| println!("{}", i));
+ /// ```
+ ///
+ /// This conversion is often implicit for arguments to methods like [`zip`].
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let v: Vec<_> = (0..5).into_par_iter().zip(5..10).collect();
+ /// assert_eq!(v, [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]);
+ /// ```
+ ///
+ /// [`zip`]: trait.IndexedParallelIterator.html#method.zip
+ fn into_par_iter(self) -> Self::Iter;
+}
+
+/// `IntoParallelRefIterator` implements the conversion to a
+/// [`ParallelIterator`], providing shared references to the data.
+///
+/// This is a parallel version of the `iter()` method
+/// defined by various collections.
+///
+/// This trait is automatically implemented
+/// `for I where &I: IntoParallelIterator`. In most cases, users
+/// will want to implement [`IntoParallelIterator`] rather than implement
+/// this trait directly.
+///
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+/// [`IntoParallelIterator`]: trait.IntoParallelIterator.html
+pub trait IntoParallelRefIterator<'data> {
+ /// The type of the parallel iterator that will be returned.
+ type Iter: ParallelIterator<Item = Self::Item>;
+
+ /// The type of item that the parallel iterator will produce.
+ /// This will typically be an `&'data T` reference type.
+ type Item: Send + 'data;
+
+ /// Converts `self` into a parallel iterator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let v: Vec<_> = (0..100).collect();
+ /// assert_eq!(v.par_iter().sum::<i32>(), 100 * 99 / 2);
+ ///
+ /// // `v.par_iter()` is shorthand for `(&v).into_par_iter()`,
+ /// // producing the exact same references.
+ /// assert!(v.par_iter().zip(&v)
+ /// .all(|(a, b)| std::ptr::eq(a, b)));
+ /// ```
+ fn par_iter(&'data self) -> Self::Iter;
+}
+
+impl<'data, I: 'data + ?Sized> IntoParallelRefIterator<'data> for I
+where
+ &'data I: IntoParallelIterator,
+{
+ type Iter = <&'data I as IntoParallelIterator>::Iter;
+ type Item = <&'data I as IntoParallelIterator>::Item;
+
+ fn par_iter(&'data self) -> Self::Iter {
+ self.into_par_iter()
+ }
+}
+
+/// `IntoParallelRefMutIterator` implements the conversion to a
+/// [`ParallelIterator`], providing mutable references to the data.
+///
+/// This is a parallel version of the `iter_mut()` method
+/// defined by various collections.
+///
+/// This trait is automatically implemented
+/// `for I where &mut I: IntoParallelIterator`. In most cases, users
+/// will want to implement [`IntoParallelIterator`] rather than implement
+/// this trait directly.
+///
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+/// [`IntoParallelIterator`]: trait.IntoParallelIterator.html
+pub trait IntoParallelRefMutIterator<'data> {
+ /// The type of iterator that will be created.
+ type Iter: ParallelIterator<Item = Self::Item>;
+
+ /// The type of item that will be produced; this is typically an
+ /// `&'data mut T` reference.
+ type Item: Send + 'data;
+
+ /// Creates the parallel iterator from `self`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let mut v = vec![0usize; 5];
+ /// v.par_iter_mut().enumerate().for_each(|(i, x)| *x = i);
+ /// assert_eq!(v, [0, 1, 2, 3, 4]);
+ /// ```
+ fn par_iter_mut(&'data mut self) -> Self::Iter;
+}
+
+impl<'data, I: 'data + ?Sized> IntoParallelRefMutIterator<'data> for I
+where
+ &'data mut I: IntoParallelIterator,
+{
+ type Iter = <&'data mut I as IntoParallelIterator>::Iter;
+ type Item = <&'data mut I as IntoParallelIterator>::Item;
+
+ fn par_iter_mut(&'data mut self) -> Self::Iter {
+ self.into_par_iter()
+ }
+}
+
+/// Parallel version of the standard iterator trait.
+///
+/// The combinators on this trait are available on **all** parallel
+/// iterators. Additional methods can be found on the
+/// [`IndexedParallelIterator`] trait: those methods are only
+/// available for parallel iterators where the number of items is
+/// known in advance (so, e.g., after invoking `filter`, those methods
+/// become unavailable).
+///
+/// For examples of using parallel iterators, see [the docs on the
+/// `iter` module][iter].
+///
+/// [iter]: index.html
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+pub trait ParallelIterator: Sized + Send {
+ /// The type of item that this parallel iterator produces.
+ /// For example, if you use the [`for_each`] method, this is the type of
+ /// item that your closure will be invoked with.
+ ///
+ /// [`for_each`]: #method.for_each
+ type Item: Send;
+
+ /// Executes `OP` on each item produced by the iterator, in parallel.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// (0..100).into_par_iter().for_each(|x| println!("{:?}", x));
+ /// ```
+ fn for_each<OP>(self, op: OP)
+ where
+ OP: Fn(Self::Item) + Sync + Send,
+ {
+ for_each::for_each(self, &op)
+ }
+
+ /// Executes `OP` on the given `init` value with each item produced by
+ /// the iterator, in parallel.
+ ///
+ /// The `init` value will be cloned only as needed to be paired with
+ /// the group of items in each rayon job. It does not require the type
+ /// to be `Sync`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::mpsc::channel;
+ /// use rayon::prelude::*;
+ ///
+ /// let (sender, receiver) = channel();
+ ///
+ /// (0..5).into_par_iter().for_each_with(sender, |s, x| s.send(x).unwrap());
+ ///
+ /// let mut res: Vec<_> = receiver.iter().collect();
+ ///
+ /// res.sort();
+ ///
+ /// assert_eq!(&res[..], &[0, 1, 2, 3, 4])
+ /// ```
+ fn for_each_with<OP, T>(self, init: T, op: OP)
+ where
+ OP: Fn(&mut T, Self::Item) + Sync + Send,
+ T: Send + Clone,
+ {
+ self.map_with(init, op).collect()
+ }
+
+ /// Executes `OP` on a value returned by `init` with each item produced by
+ /// the iterator, in parallel.
+ ///
+ /// The `init` function will be called only as needed for a value to be
+ /// paired with the group of items in each rayon job. There is no
+ /// constraint on that returned type at all!
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rand::Rng;
+ /// use rayon::prelude::*;
+ ///
+ /// let mut v = vec![0u8; 1_000_000];
+ ///
+ /// v.par_chunks_mut(1000)
+ /// .for_each_init(
+ /// || rand::thread_rng(),
+ /// |rng, chunk| rng.fill(chunk),
+ /// );
+ ///
+ /// // There's a remote chance that this will fail...
+ /// for i in 0u8..=255 {
+ /// assert!(v.contains(&i));
+ /// }
+ /// ```
+ fn for_each_init<OP, INIT, T>(self, init: INIT, op: OP)
+ where
+ OP: Fn(&mut T, Self::Item) + Sync + Send,
+ INIT: Fn() -> T + Sync + Send,
+ {
+ self.map_init(init, op).collect()
+ }
+
+ /// Executes a fallible `OP` on each item produced by the iterator, in parallel.
+ ///
+ /// If the `OP` returns `Result::Err` or `Option::None`, we will attempt to
+ /// stop processing the rest of the items in the iterator as soon as
+ /// possible, and we will return that terminating value. Otherwise, we will
+ /// return an empty `Result::Ok(())` or `Option::Some(())`. If there are
+ /// multiple errors in parallel, it is not specified which will be returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// use std::io::{self, Write};
+ ///
+ /// // This will stop iteration early if there's any write error, like
+ /// // having piped output get closed on the other end.
+ /// (0..100).into_par_iter()
+ /// .try_for_each(|x| writeln!(io::stdout(), "{:?}", x))
+ /// .expect("expected no write errors");
+ /// ```
+ fn try_for_each<OP, R>(self, op: OP) -> R
+ where
+ OP: Fn(Self::Item) -> R + Sync + Send,
+ R: Try<Output = ()> + Send,
+ {
+ fn ok<R: Try<Output = ()>>(_: (), _: ()) -> R {
+ R::from_output(())
+ }
+
+ self.map(op).try_reduce(<()>::default, ok)
+ }
+
+ /// Executes a fallible `OP` on the given `init` value with each item
+ /// produced by the iterator, in parallel.
+ ///
+ /// This combines the `init` semantics of [`for_each_with()`] and the
+ /// failure semantics of [`try_for_each()`].
+ ///
+ /// [`for_each_with()`]: #method.for_each_with
+ /// [`try_for_each()`]: #method.try_for_each
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::mpsc::channel;
+ /// use rayon::prelude::*;
+ ///
+ /// let (sender, receiver) = channel();
+ ///
+ /// (0..5).into_par_iter()
+ /// .try_for_each_with(sender, |s, x| s.send(x))
+ /// .expect("expected no send errors");
+ ///
+ /// let mut res: Vec<_> = receiver.iter().collect();
+ ///
+ /// res.sort();
+ ///
+ /// assert_eq!(&res[..], &[0, 1, 2, 3, 4])
+ /// ```
+ fn try_for_each_with<OP, T, R>(self, init: T, op: OP) -> R
+ where
+ OP: Fn(&mut T, Self::Item) -> R + Sync + Send,
+ T: Send + Clone,
+ R: Try<Output = ()> + Send,
+ {
+ fn ok<R: Try<Output = ()>>(_: (), _: ()) -> R {
+ R::from_output(())
+ }
+
+ self.map_with(init, op).try_reduce(<()>::default, ok)
+ }
+
+ /// Executes a fallible `OP` on a value returned by `init` with each item
+ /// produced by the iterator, in parallel.
+ ///
+ /// This combines the `init` semantics of [`for_each_init()`] and the
+ /// failure semantics of [`try_for_each()`].
+ ///
+ /// [`for_each_init()`]: #method.for_each_init
+ /// [`try_for_each()`]: #method.try_for_each
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rand::Rng;
+ /// use rayon::prelude::*;
+ ///
+ /// let mut v = vec![0u8; 1_000_000];
+ ///
+ /// v.par_chunks_mut(1000)
+ /// .try_for_each_init(
+ /// || rand::thread_rng(),
+ /// |rng, chunk| rng.try_fill(chunk),
+ /// )
+ /// .expect("expected no rand errors");
+ ///
+ /// // There's a remote chance that this will fail...
+ /// for i in 0u8..=255 {
+ /// assert!(v.contains(&i));
+ /// }
+ /// ```
+ fn try_for_each_init<OP, INIT, T, R>(self, init: INIT, op: OP) -> R
+ where
+ OP: Fn(&mut T, Self::Item) -> R + Sync + Send,
+ INIT: Fn() -> T + Sync + Send,
+ R: Try<Output = ()> + Send,
+ {
+ fn ok<R: Try<Output = ()>>(_: (), _: ()) -> R {
+ R::from_output(())
+ }
+
+ self.map_init(init, op).try_reduce(<()>::default, ok)
+ }
+
+ /// Counts the number of items in this parallel iterator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let count = (0..100).into_par_iter().count();
+ ///
+ /// assert_eq!(count, 100);
+ /// ```
+ fn count(self) -> usize {
+ fn one<T>(_: T) -> usize {
+ 1
+ }
+
+ self.map(one).sum()
+ }
+
+ /// Applies `map_op` to each item of this iterator, producing a new
+ /// iterator with the results.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let mut par_iter = (0..5).into_par_iter().map(|x| x * 2);
+ ///
+ /// let doubles: Vec<_> = par_iter.collect();
+ ///
+ /// assert_eq!(&doubles[..], &[0, 2, 4, 6, 8]);
+ /// ```
+ fn map<F, R>(self, map_op: F) -> Map<Self, F>
+ where
+ F: Fn(Self::Item) -> R + Sync + Send,
+ R: Send,
+ {
+ Map::new(self, map_op)
+ }
+
+ /// Applies `map_op` to the given `init` value with each item of this
+ /// iterator, producing a new iterator with the results.
+ ///
+ /// The `init` value will be cloned only as needed to be paired with
+ /// the group of items in each rayon job. It does not require the type
+ /// to be `Sync`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::mpsc::channel;
+ /// use rayon::prelude::*;
+ ///
+ /// let (sender, receiver) = channel();
+ ///
+ /// let a: Vec<_> = (0..5)
+ /// .into_par_iter() // iterating over i32
+ /// .map_with(sender, |s, x| {
+ /// s.send(x).unwrap(); // sending i32 values through the channel
+ /// x // returning i32
+ /// })
+ /// .collect(); // collecting the returned values into a vector
+ ///
+ /// let mut b: Vec<_> = receiver.iter() // iterating over the values in the channel
+ /// .collect(); // and collecting them
+ /// b.sort();
+ ///
+ /// assert_eq!(a, b);
+ /// ```
+ fn map_with<F, T, R>(self, init: T, map_op: F) -> MapWith<Self, T, F>
+ where
+ F: Fn(&mut T, Self::Item) -> R + Sync + Send,
+ T: Send + Clone,
+ R: Send,
+ {
+ MapWith::new(self, init, map_op)
+ }
+
+ /// Applies `map_op` to a value returned by `init` with each item of this
+ /// iterator, producing a new iterator with the results.
+ ///
+ /// The `init` function will be called only as needed for a value to be
+ /// paired with the group of items in each rayon job. There is no
+ /// constraint on that returned type at all!
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rand::Rng;
+ /// use rayon::prelude::*;
+ ///
+ /// let a: Vec<_> = (1i32..1_000_000)
+ /// .into_par_iter()
+ /// .map_init(
+ /// || rand::thread_rng(), // get the thread-local RNG
+ /// |rng, x| if rng.gen() { // randomly negate items
+ /// -x
+ /// } else {
+ /// x
+ /// },
+ /// ).collect();
+ ///
+ /// // There's a remote chance that this will fail...
+ /// assert!(a.iter().any(|&x| x < 0));
+ /// assert!(a.iter().any(|&x| x > 0));
+ /// ```
+ fn map_init<F, INIT, T, R>(self, init: INIT, map_op: F) -> MapInit<Self, INIT, F>
+ where
+ F: Fn(&mut T, Self::Item) -> R + Sync + Send,
+ INIT: Fn() -> T + Sync + Send,
+ R: Send,
+ {
+ MapInit::new(self, init, map_op)
+ }
+
+ /// Creates an iterator which clones all of its elements. This may be
+ /// useful when you have an iterator over `&T`, but you need `T`, and
+ /// that type implements `Clone`. See also [`copied()`].
+ ///
+ /// [`copied()`]: #method.copied
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [1, 2, 3];
+ ///
+ /// let v_cloned: Vec<_> = a.par_iter().cloned().collect();
+ ///
+ /// // cloned is the same as .map(|&x| x), for integers
+ /// let v_map: Vec<_> = a.par_iter().map(|&x| x).collect();
+ ///
+ /// assert_eq!(v_cloned, vec![1, 2, 3]);
+ /// assert_eq!(v_map, vec![1, 2, 3]);
+ /// ```
+ fn cloned<'a, T>(self) -> Cloned<Self>
+ where
+ T: 'a + Clone + Send,
+ Self: ParallelIterator<Item = &'a T>,
+ {
+ Cloned::new(self)
+ }
+
+ /// Creates an iterator which copies all of its elements. This may be
+ /// useful when you have an iterator over `&T`, but you need `T`, and
+ /// that type implements `Copy`. See also [`cloned()`].
+ ///
+ /// [`cloned()`]: #method.cloned
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [1, 2, 3];
+ ///
+ /// let v_copied: Vec<_> = a.par_iter().copied().collect();
+ ///
+ /// // copied is the same as .map(|&x| x), for integers
+ /// let v_map: Vec<_> = a.par_iter().map(|&x| x).collect();
+ ///
+ /// assert_eq!(v_copied, vec![1, 2, 3]);
+ /// assert_eq!(v_map, vec![1, 2, 3]);
+ /// ```
+ fn copied<'a, T>(self) -> Copied<Self>
+ where
+ T: 'a + Copy + Send,
+ Self: ParallelIterator<Item = &'a T>,
+ {
+ Copied::new(self)
+ }
+
+ /// Applies `inspect_op` to a reference to each item of this iterator,
+ /// producing a new iterator passing through the original items. This is
+ /// often useful for debugging to see what's happening in iterator stages.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [1, 4, 2, 3];
+ ///
+ /// // this iterator sequence is complex.
+ /// let sum = a.par_iter()
+ /// .cloned()
+ /// .filter(|&x| x % 2 == 0)
+ /// .reduce(|| 0, |sum, i| sum + i);
+ ///
+ /// println!("{}", sum);
+ ///
+ /// // let's add some inspect() calls to investigate what's happening
+ /// let sum = a.par_iter()
+ /// .cloned()
+ /// .inspect(|x| println!("about to filter: {}", x))
+ /// .filter(|&x| x % 2 == 0)
+ /// .inspect(|x| println!("made it through filter: {}", x))
+ /// .reduce(|| 0, |sum, i| sum + i);
+ ///
+ /// println!("{}", sum);
+ /// ```
+ fn inspect<OP>(self, inspect_op: OP) -> Inspect<Self, OP>
+ where
+ OP: Fn(&Self::Item) + Sync + Send,
+ {
+ Inspect::new(self, inspect_op)
+ }
+
+ /// Mutates each item of this iterator before yielding it.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let par_iter = (0..5).into_par_iter().update(|x| {*x *= 2;});
+ ///
+ /// let doubles: Vec<_> = par_iter.collect();
+ ///
+ /// assert_eq!(&doubles[..], &[0, 2, 4, 6, 8]);
+ /// ```
+ fn update<F>(self, update_op: F) -> Update<Self, F>
+ where
+ F: Fn(&mut Self::Item) + Sync + Send,
+ {
+ Update::new(self, update_op)
+ }
+
+ /// Applies `filter_op` to each item of this iterator, producing a new
+ /// iterator with only the items that gave `true` results.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let mut par_iter = (0..10).into_par_iter().filter(|x| x % 2 == 0);
+ ///
+ /// let even_numbers: Vec<_> = par_iter.collect();
+ ///
+ /// assert_eq!(&even_numbers[..], &[0, 2, 4, 6, 8]);
+ /// ```
+ fn filter<P>(self, filter_op: P) -> Filter<Self, P>
+ where
+ P: Fn(&Self::Item) -> bool + Sync + Send,
+ {
+ Filter::new(self, filter_op)
+ }
+
+ /// Applies `filter_op` to each item of this iterator to get an `Option`,
+ /// producing a new iterator with only the items from `Some` results.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let mut par_iter = (0..10).into_par_iter()
+ /// .filter_map(|x| {
+ /// if x % 2 == 0 { Some(x * 3) }
+ /// else { None }
+ /// });
+ ///
+ /// let even_numbers: Vec<_> = par_iter.collect();
+ ///
+ /// assert_eq!(&even_numbers[..], &[0, 6, 12, 18, 24]);
+ /// ```
+ fn filter_map<P, R>(self, filter_op: P) -> FilterMap<Self, P>
+ where
+ P: Fn(Self::Item) -> Option<R> + Sync + Send,
+ R: Send,
+ {
+ FilterMap::new(self, filter_op)
+ }
+
+ /// Applies `map_op` to each item of this iterator to get nested parallel iterators,
+ /// producing a new parallel iterator that flattens these back into one.
+ ///
+ /// See also [`flat_map_iter`](#method.flat_map_iter).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [[1, 2], [3, 4], [5, 6], [7, 8]];
+ ///
+ /// let par_iter = a.par_iter().cloned().flat_map(|a| a.to_vec());
+ ///
+ /// let vec: Vec<_> = par_iter.collect();
+ ///
+ /// assert_eq!(&vec[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
+ /// ```
+ fn flat_map<F, PI>(self, map_op: F) -> FlatMap<Self, F>
+ where
+ F: Fn(Self::Item) -> PI + Sync + Send,
+ PI: IntoParallelIterator,
+ {
+ FlatMap::new(self, map_op)
+ }
+
+ /// Applies `map_op` to each item of this iterator to get nested serial iterators,
+ /// producing a new parallel iterator that flattens these back into one.
+ ///
+ /// # `flat_map_iter` versus `flat_map`
+ ///
+ /// These two methods are similar but behave slightly differently. With [`flat_map`],
+ /// each of the nested iterators must be a parallel iterator, and they will be further
+ /// split up with nested parallelism. With `flat_map_iter`, each nested iterator is a
+ /// sequential `Iterator`, and we only parallelize _between_ them, while the items
+ /// produced by each nested iterator are processed sequentially.
+ ///
+ /// When choosing between these methods, consider whether nested parallelism suits the
+ /// potential iterators at hand. If there's little computation involved, or its length
+ /// is much less than the outer parallel iterator, then it may perform better to avoid
+ /// the overhead of parallelism, just flattening sequentially with `flat_map_iter`.
+ /// If there is a lot of computation, potentially outweighing the outer parallel
+ /// iterator, then the nested parallelism of `flat_map` may be worthwhile.
+ ///
+ /// [`flat_map`]: #method.flat_map
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// use std::cell::RefCell;
+ ///
+ /// let a = [[1, 2], [3, 4], [5, 6], [7, 8]];
+ ///
+ /// let par_iter = a.par_iter().flat_map_iter(|a| {
+ /// // The serial iterator doesn't have to be thread-safe, just its items.
+ /// let cell_iter = RefCell::new(a.iter().cloned());
+ /// std::iter::from_fn(move || cell_iter.borrow_mut().next())
+ /// });
+ ///
+ /// let vec: Vec<_> = par_iter.collect();
+ ///
+ /// assert_eq!(&vec[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
+ /// ```
+ fn flat_map_iter<F, SI>(self, map_op: F) -> FlatMapIter<Self, F>
+ where
+ F: Fn(Self::Item) -> SI + Sync + Send,
+ SI: IntoIterator,
+ SI::Item: Send,
+ {
+ FlatMapIter::new(self, map_op)
+ }
+
+ /// An adaptor that flattens parallel-iterable `Item`s into one large iterator.
+ ///
+ /// See also [`flatten_iter`](#method.flatten_iter).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let x: Vec<Vec<_>> = vec![vec![1, 2], vec![3, 4]];
+ /// let y: Vec<_> = x.into_par_iter().flatten().collect();
+ ///
+ /// assert_eq!(y, vec![1, 2, 3, 4]);
+ /// ```
+ fn flatten(self) -> Flatten<Self>
+ where
+ Self::Item: IntoParallelIterator,
+ {
+ Flatten::new(self)
+ }
+
+ /// An adaptor that flattens serial-iterable `Item`s into one large iterator.
+ ///
+ /// See also [`flatten`](#method.flatten) and the analogous comparison of
+ /// [`flat_map_iter` versus `flat_map`](#flat_map_iter-versus-flat_map).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let x: Vec<Vec<_>> = vec![vec![1, 2], vec![3, 4]];
+ /// let iters: Vec<_> = x.into_iter().map(Vec::into_iter).collect();
+ /// let y: Vec<_> = iters.into_par_iter().flatten_iter().collect();
+ ///
+ /// assert_eq!(y, vec![1, 2, 3, 4]);
+ /// ```
+ fn flatten_iter(self) -> FlattenIter<Self>
+ where
+ Self::Item: IntoIterator,
+ <Self::Item as IntoIterator>::Item: Send,
+ {
+ FlattenIter::new(self)
+ }
+
+ /// Reduces the items in the iterator into one item using `op`.
+ /// The argument `identity` should be a closure that can produce
+ /// "identity" value which may be inserted into the sequence as
+ /// needed to create opportunities for parallel execution. So, for
+ /// example, if you are doing a summation, then `identity()` ought
+ /// to produce something that represents the zero for your type
+ /// (but consider just calling `sum()` in that case).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// // Iterate over a sequence of pairs `(x0, y0), ..., (xN, yN)`
+ /// // and use reduce to compute one pair `(x0 + ... + xN, y0 + ... + yN)`
+ /// // where the first/second elements are summed separately.
+ /// use rayon::prelude::*;
+ /// let sums = [(0, 1), (5, 6), (16, 2), (8, 9)]
+ /// .par_iter() // iterating over &(i32, i32)
+ /// .cloned() // iterating over (i32, i32)
+ /// .reduce(|| (0, 0), // the "identity" is 0 in both columns
+ /// |a, b| (a.0 + b.0, a.1 + b.1));
+ /// assert_eq!(sums, (0 + 5 + 16 + 8, 1 + 6 + 2 + 9));
+ /// ```
+ ///
+ /// **Note:** unlike a sequential `fold` operation, the order in
+ /// which `op` will be applied to reduce the result is not fully
+ /// specified. So `op` should be [associative] or else the results
+ /// will be non-deterministic. And of course `identity()` should
+ /// produce a true identity.
+ ///
+ /// [associative]: https://en.wikipedia.org/wiki/Associative_property
+ fn reduce<OP, ID>(self, identity: ID, op: OP) -> Self::Item
+ where
+ OP: Fn(Self::Item, Self::Item) -> Self::Item + Sync + Send,
+ ID: Fn() -> Self::Item + Sync + Send,
+ {
+ reduce::reduce(self, identity, op)
+ }
+
+ /// Reduces the items in the iterator into one item using `op`.
+ /// If the iterator is empty, `None` is returned; otherwise,
+ /// `Some` is returned.
+ ///
+ /// This version of `reduce` is simple but somewhat less
+ /// efficient. If possible, it is better to call `reduce()`, which
+ /// requires an identity element.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// let sums = [(0, 1), (5, 6), (16, 2), (8, 9)]
+ /// .par_iter() // iterating over &(i32, i32)
+ /// .cloned() // iterating over (i32, i32)
+ /// .reduce_with(|a, b| (a.0 + b.0, a.1 + b.1))
+ /// .unwrap();
+ /// assert_eq!(sums, (0 + 5 + 16 + 8, 1 + 6 + 2 + 9));
+ /// ```
+ ///
+ /// **Note:** unlike a sequential `fold` operation, the order in
+ /// which `op` will be applied to reduce the result is not fully
+ /// specified. So `op` should be [associative] or else the results
+ /// will be non-deterministic.
+ ///
+ /// [associative]: https://en.wikipedia.org/wiki/Associative_property
+ fn reduce_with<OP>(self, op: OP) -> Option<Self::Item>
+ where
+ OP: Fn(Self::Item, Self::Item) -> Self::Item + Sync + Send,
+ {
+ fn opt_fold<T>(op: impl Fn(T, T) -> T) -> impl Fn(Option<T>, T) -> Option<T> {
+ move |opt_a, b| match opt_a {
+ Some(a) => Some(op(a, b)),
+ None => Some(b),
+ }
+ }
+
+ fn opt_reduce<T>(op: impl Fn(T, T) -> T) -> impl Fn(Option<T>, Option<T>) -> Option<T> {
+ move |opt_a, opt_b| match (opt_a, opt_b) {
+ (Some(a), Some(b)) => Some(op(a, b)),
+ (Some(v), None) | (None, Some(v)) => Some(v),
+ (None, None) => None,
+ }
+ }
+
+ self.fold(<_>::default, opt_fold(&op))
+ .reduce(<_>::default, opt_reduce(&op))
+ }
+
+ /// Reduces the items in the iterator into one item using a fallible `op`.
+ /// The `identity` argument is used the same way as in [`reduce()`].
+ ///
+ /// [`reduce()`]: #method.reduce
+ ///
+ /// If a `Result::Err` or `Option::None` item is found, or if `op` reduces
+ /// to one, we will attempt to stop processing the rest of the items in the
+ /// iterator as soon as possible, and we will return that terminating value.
+ /// Otherwise, we will return the final reduced `Result::Ok(T)` or
+ /// `Option::Some(T)`. If there are multiple errors in parallel, it is not
+ /// specified which will be returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// // Compute the sum of squares, being careful about overflow.
+ /// fn sum_squares<I: IntoParallelIterator<Item = i32>>(iter: I) -> Option<i32> {
+ /// iter.into_par_iter()
+ /// .map(|i| i.checked_mul(i)) // square each item,
+ /// .try_reduce(|| 0, i32::checked_add) // and add them up!
+ /// }
+ /// assert_eq!(sum_squares(0..5), Some(0 + 1 + 4 + 9 + 16));
+ ///
+ /// // The sum might overflow
+ /// assert_eq!(sum_squares(0..10_000), None);
+ ///
+ /// // Or the squares might overflow before it even reaches `try_reduce`
+ /// assert_eq!(sum_squares(1_000_000..1_000_001), None);
+ /// ```
+ fn try_reduce<T, OP, ID>(self, identity: ID, op: OP) -> Self::Item
+ where
+ OP: Fn(T, T) -> Self::Item + Sync + Send,
+ ID: Fn() -> T + Sync + Send,
+ Self::Item: Try<Output = T>,
+ {
+ try_reduce::try_reduce(self, identity, op)
+ }
+
+ /// Reduces the items in the iterator into one item using a fallible `op`.
+ ///
+ /// Like [`reduce_with()`], if the iterator is empty, `None` is returned;
+ /// otherwise, `Some` is returned. Beyond that, it behaves like
+ /// [`try_reduce()`] for handling `Err`/`None`.
+ ///
+ /// [`reduce_with()`]: #method.reduce_with
+ /// [`try_reduce()`]: #method.try_reduce
+ ///
+ /// For instance, with `Option` items, the return value may be:
+ /// - `None`, the iterator was empty
+ /// - `Some(None)`, we stopped after encountering `None`.
+ /// - `Some(Some(x))`, the entire iterator reduced to `x`.
+ ///
+ /// With `Result` items, the nesting is more obvious:
+ /// - `None`, the iterator was empty
+ /// - `Some(Err(e))`, we stopped after encountering an error `e`.
+ /// - `Some(Ok(x))`, the entire iterator reduced to `x`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let files = ["/dev/null", "/does/not/exist"];
+ ///
+ /// // Find the biggest file
+ /// files.into_par_iter()
+ /// .map(|path| std::fs::metadata(path).map(|m| (path, m.len())))
+ /// .try_reduce_with(|a, b| {
+ /// Ok(if a.1 >= b.1 { a } else { b })
+ /// })
+ /// .expect("Some value, since the iterator is not empty")
+ /// .expect_err("not found");
+ /// ```
+ fn try_reduce_with<T, OP>(self, op: OP) -> Option<Self::Item>
+ where
+ OP: Fn(T, T) -> Self::Item + Sync + Send,
+ Self::Item: Try<Output = T>,
+ {
+ try_reduce_with::try_reduce_with(self, op)
+ }
+
+ /// Parallel fold is similar to sequential fold except that the
+ /// sequence of items may be subdivided before it is
+ /// folded. Consider a list of numbers like `22 3 77 89 46`. If
+ /// you used sequential fold to add them (`fold(0, |a,b| a+b)`,
+ /// you would wind up first adding 0 + 22, then 22 + 3, then 25 +
+ /// 77, and so forth. The **parallel fold** works similarly except
+ /// that it first breaks up your list into sublists, and hence
+ /// instead of yielding up a single sum at the end, it yields up
+ /// multiple sums. The number of results is nondeterministic, as
+ /// is the point where the breaks occur.
+ ///
+ /// So if we did the same parallel fold (`fold(0, |a,b| a+b)`) on
+ /// our example list, we might wind up with a sequence of two numbers,
+ /// like so:
+ ///
+ /// ```notrust
+ /// 22 3 77 89 46
+ /// | |
+ /// 102 135
+ /// ```
+ ///
+ /// Or perhaps these three numbers:
+ ///
+ /// ```notrust
+ /// 22 3 77 89 46
+ /// | | |
+ /// 102 89 46
+ /// ```
+ ///
+ /// In general, Rayon will attempt to find good breaking points
+ /// that keep all of your cores busy.
+ ///
+ /// ### Fold versus reduce
+ ///
+ /// The `fold()` and `reduce()` methods each take an identity element
+ /// and a combining function, but they operate rather differently.
+ ///
+ /// `reduce()` requires that the identity function has the same
+ /// type as the things you are iterating over, and it fully
+ /// reduces the list of items into a single item. So, for example,
+ /// imagine we are iterating over a list of bytes `bytes: [128_u8,
+ /// 64_u8, 64_u8]`. If we used `bytes.reduce(|| 0_u8, |a: u8, b:
+ /// u8| a + b)`, we would get an overflow. This is because `0`,
+ /// `a`, and `b` here are all bytes, just like the numbers in the
+ /// list (I wrote the types explicitly above, but those are the
+ /// only types you can use). To avoid the overflow, we would need
+ /// to do something like `bytes.map(|b| b as u32).reduce(|| 0, |a,
+ /// b| a + b)`, in which case our result would be `256`.
+ ///
+ /// In contrast, with `fold()`, the identity function does not
+ /// have to have the same type as the things you are iterating
+ /// over, and you potentially get back many results. So, if we
+ /// continue with the `bytes` example from the previous paragraph,
+ /// we could do `bytes.fold(|| 0_u32, |a, b| a + (b as u32))` to
+ /// convert our bytes into `u32`. And of course we might not get
+ /// back a single sum.
+ ///
+ /// There is a more subtle distinction as well, though it's
+ /// actually implied by the above points. When you use `reduce()`,
+ /// your reduction function is sometimes called with values that
+ /// were never part of your original parallel iterator (for
+ /// example, both the left and right might be a partial sum). With
+ /// `fold()`, in contrast, the left value in the fold function is
+ /// always the accumulator, and the right value is always from
+ /// your original sequence.
+ ///
+ /// ### Fold vs Map/Reduce
+ ///
+ /// Fold makes sense if you have some operation where it is
+ /// cheaper to create groups of elements at a time. For example,
+ /// imagine collecting characters into a string. If you were going
+ /// to use map/reduce, you might try this:
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let s =
+ /// ['a', 'b', 'c', 'd', 'e']
+ /// .par_iter()
+ /// .map(|c: &char| format!("{}", c))
+ /// .reduce(|| String::new(),
+ /// |mut a: String, b: String| { a.push_str(&b); a });
+ ///
+ /// assert_eq!(s, "abcde");
+ /// ```
+ ///
+ /// Because reduce produces the same type of element as its input,
+ /// you have to first map each character into a string, and then
+ /// you can reduce them. This means we create one string per
+ /// element in our iterator -- not so great. Using `fold`, we can
+ /// do this instead:
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let s =
+ /// ['a', 'b', 'c', 'd', 'e']
+ /// .par_iter()
+ /// .fold(|| String::new(),
+ /// |mut s: String, c: &char| { s.push(*c); s })
+ /// .reduce(|| String::new(),
+ /// |mut a: String, b: String| { a.push_str(&b); a });
+ ///
+ /// assert_eq!(s, "abcde");
+ /// ```
+ ///
+ /// Now `fold` will process groups of our characters at a time,
+ /// and we only make one string per group. We should wind up with
+ /// some small-ish number of strings roughly proportional to the
+ /// number of CPUs you have (it will ultimately depend on how busy
+ /// your processors are). Note that we still need to do a reduce
+ /// afterwards to combine those groups of strings into a single
+ /// string.
+ ///
+ /// You could use a similar trick to save partial results (e.g., a
+ /// cache) or something similar.
+ ///
+ /// ### Combining fold with other operations
+ ///
+ /// You can combine `fold` with `reduce` if you want to produce a
+ /// single value. This is then roughly equivalent to a map/reduce
+ /// combination in effect:
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let bytes = 0..22_u8;
+ /// let sum = bytes.into_par_iter()
+ /// .fold(|| 0_u32, |a: u32, b: u8| a + (b as u32))
+ /// .sum::<u32>();
+ ///
+ /// assert_eq!(sum, (0..22).sum()); // compare to sequential
+ /// ```
+ fn fold<T, ID, F>(self, identity: ID, fold_op: F) -> Fold<Self, ID, F>
+ where
+ F: Fn(T, Self::Item) -> T + Sync + Send,
+ ID: Fn() -> T + Sync + Send,
+ T: Send,
+ {
+ Fold::new(self, identity, fold_op)
+ }
+
+ /// Applies `fold_op` to the given `init` value with each item of this
+ /// iterator, finally producing the value for further use.
+ ///
+ /// This works essentially like `fold(|| init.clone(), fold_op)`, except
+ /// it doesn't require the `init` type to be `Sync`, nor any other form
+ /// of added synchronization.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let bytes = 0..22_u8;
+ /// let sum = bytes.into_par_iter()
+ /// .fold_with(0_u32, |a: u32, b: u8| a + (b as u32))
+ /// .sum::<u32>();
+ ///
+ /// assert_eq!(sum, (0..22).sum()); // compare to sequential
+ /// ```
+ fn fold_with<F, T>(self, init: T, fold_op: F) -> FoldWith<Self, T, F>
+ where
+ F: Fn(T, Self::Item) -> T + Sync + Send,
+ T: Send + Clone,
+ {
+ FoldWith::new(self, init, fold_op)
+ }
+
+ /// Performs a fallible parallel fold.
+ ///
+ /// This is a variation of [`fold()`] for operations which can fail with
+ /// `Option::None` or `Result::Err`. The first such failure stops
+ /// processing the local set of items, without affecting other folds in the
+ /// iterator's subdivisions.
+ ///
+ /// Often, `try_fold()` will be followed by [`try_reduce()`]
+ /// for a final reduction and global short-circuiting effect.
+ ///
+ /// [`fold()`]: #method.fold
+ /// [`try_reduce()`]: #method.try_reduce
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let bytes = 0..22_u8;
+ /// let sum = bytes.into_par_iter()
+ /// .try_fold(|| 0_u32, |a: u32, b: u8| a.checked_add(b as u32))
+ /// .try_reduce(|| 0, u32::checked_add);
+ ///
+ /// assert_eq!(sum, Some((0..22).sum())); // compare to sequential
+ /// ```
+ fn try_fold<T, R, ID, F>(self, identity: ID, fold_op: F) -> TryFold<Self, R, ID, F>
+ where
+ F: Fn(T, Self::Item) -> R + Sync + Send,
+ ID: Fn() -> T + Sync + Send,
+ R: Try<Output = T> + Send,
+ {
+ TryFold::new(self, identity, fold_op)
+ }
+
+ /// Performs a fallible parallel fold with a cloneable `init` value.
+ ///
+ /// This combines the `init` semantics of [`fold_with()`] and the failure
+ /// semantics of [`try_fold()`].
+ ///
+ /// [`fold_with()`]: #method.fold_with
+ /// [`try_fold()`]: #method.try_fold
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let bytes = 0..22_u8;
+ /// let sum = bytes.into_par_iter()
+ /// .try_fold_with(0_u32, |a: u32, b: u8| a.checked_add(b as u32))
+ /// .try_reduce(|| 0, u32::checked_add);
+ ///
+ /// assert_eq!(sum, Some((0..22).sum())); // compare to sequential
+ /// ```
+ fn try_fold_with<F, T, R>(self, init: T, fold_op: F) -> TryFoldWith<Self, R, F>
+ where
+ F: Fn(T, Self::Item) -> R + Sync + Send,
+ R: Try<Output = T> + Send,
+ T: Clone + Send,
+ {
+ TryFoldWith::new(self, init, fold_op)
+ }
+
+ /// Sums up the items in the iterator.
+ ///
+ /// Note that the order in items will be reduced is not specified,
+ /// so if the `+` operator is not truly [associative] \(as is the
+ /// case for floating point numbers), then the results are not
+ /// fully deterministic.
+ ///
+ /// [associative]: https://en.wikipedia.org/wiki/Associative_property
+ ///
+ /// Basically equivalent to `self.reduce(|| 0, |a, b| a + b)`,
+ /// except that the type of `0` and the `+` operation may vary
+ /// depending on the type of value being produced.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [1, 5, 7];
+ ///
+ /// let sum: i32 = a.par_iter().sum();
+ ///
+ /// assert_eq!(sum, 13);
+ /// ```
+ fn sum<S>(self) -> S
+ where
+ S: Send + Sum<Self::Item> + Sum<S>,
+ {
+ sum::sum(self)
+ }
+
+ /// Multiplies all the items in the iterator.
+ ///
+ /// Note that the order in items will be reduced is not specified,
+ /// so if the `*` operator is not truly [associative] \(as is the
+ /// case for floating point numbers), then the results are not
+ /// fully deterministic.
+ ///
+ /// [associative]: https://en.wikipedia.org/wiki/Associative_property
+ ///
+ /// Basically equivalent to `self.reduce(|| 1, |a, b| a * b)`,
+ /// except that the type of `1` and the `*` operation may vary
+ /// depending on the type of value being produced.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// fn factorial(n: u32) -> u32 {
+ /// (1..n+1).into_par_iter().product()
+ /// }
+ ///
+ /// assert_eq!(factorial(0), 1);
+ /// assert_eq!(factorial(1), 1);
+ /// assert_eq!(factorial(5), 120);
+ /// ```
+ fn product<P>(self) -> P
+ where
+ P: Send + Product<Self::Item> + Product<P>,
+ {
+ product::product(self)
+ }
+
+ /// Computes the minimum of all the items in the iterator. If the
+ /// iterator is empty, `None` is returned; otherwise, `Some(min)`
+ /// is returned.
+ ///
+ /// Note that the order in which the items will be reduced is not
+ /// specified, so if the `Ord` impl is not truly associative, then
+ /// the results are not deterministic.
+ ///
+ /// Basically equivalent to `self.reduce_with(|a, b| cmp::min(a, b))`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [45, 74, 32];
+ ///
+ /// assert_eq!(a.par_iter().min(), Some(&32));
+ ///
+ /// let b: [i32; 0] = [];
+ ///
+ /// assert_eq!(b.par_iter().min(), None);
+ /// ```
+ fn min(self) -> Option<Self::Item>
+ where
+ Self::Item: Ord,
+ {
+ self.reduce_with(cmp::min)
+ }
+
+ /// Computes the minimum of all the items in the iterator with respect to
+ /// the given comparison function. If the iterator is empty, `None` is
+ /// returned; otherwise, `Some(min)` is returned.
+ ///
+ /// Note that the order in which the items will be reduced is not
+ /// specified, so if the comparison function is not associative, then
+ /// the results are not deterministic.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [-3_i32, 77, 53, 240, -1];
+ ///
+ /// assert_eq!(a.par_iter().min_by(|x, y| x.cmp(y)), Some(&-3));
+ /// ```
+ fn min_by<F>(self, f: F) -> Option<Self::Item>
+ where
+ F: Sync + Send + Fn(&Self::Item, &Self::Item) -> Ordering,
+ {
+ fn min<T>(f: impl Fn(&T, &T) -> Ordering) -> impl Fn(T, T) -> T {
+ move |a, b| match f(&a, &b) {
+ Ordering::Greater => b,
+ _ => a,
+ }
+ }
+
+ self.reduce_with(min(f))
+ }
+
+ /// Computes the item that yields the minimum value for the given
+ /// function. If the iterator is empty, `None` is returned;
+ /// otherwise, `Some(item)` is returned.
+ ///
+ /// Note that the order in which the items will be reduced is not
+ /// specified, so if the `Ord` impl is not truly associative, then
+ /// the results are not deterministic.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [-3_i32, 34, 2, 5, -10, -3, -23];
+ ///
+ /// assert_eq!(a.par_iter().min_by_key(|x| x.abs()), Some(&2));
+ /// ```
+ fn min_by_key<K, F>(self, f: F) -> Option<Self::Item>
+ where
+ K: Ord + Send,
+ F: Sync + Send + Fn(&Self::Item) -> K,
+ {
+ fn key<T, K>(f: impl Fn(&T) -> K) -> impl Fn(T) -> (K, T) {
+ move |x| (f(&x), x)
+ }
+
+ fn min_key<T, K: Ord>(a: (K, T), b: (K, T)) -> (K, T) {
+ match (a.0).cmp(&b.0) {
+ Ordering::Greater => b,
+ _ => a,
+ }
+ }
+
+ let (_, x) = self.map(key(f)).reduce_with(min_key)?;
+ Some(x)
+ }
+
+ /// Computes the maximum of all the items in the iterator. If the
+ /// iterator is empty, `None` is returned; otherwise, `Some(max)`
+ /// is returned.
+ ///
+ /// Note that the order in which the items will be reduced is not
+ /// specified, so if the `Ord` impl is not truly associative, then
+ /// the results are not deterministic.
+ ///
+ /// Basically equivalent to `self.reduce_with(|a, b| cmp::max(a, b))`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [45, 74, 32];
+ ///
+ /// assert_eq!(a.par_iter().max(), Some(&74));
+ ///
+ /// let b: [i32; 0] = [];
+ ///
+ /// assert_eq!(b.par_iter().max(), None);
+ /// ```
+ fn max(self) -> Option<Self::Item>
+ where
+ Self::Item: Ord,
+ {
+ self.reduce_with(cmp::max)
+ }
+
+ /// Computes the maximum of all the items in the iterator with respect to
+ /// the given comparison function. If the iterator is empty, `None` is
+ /// returned; otherwise, `Some(min)` is returned.
+ ///
+ /// Note that the order in which the items will be reduced is not
+ /// specified, so if the comparison function is not associative, then
+ /// the results are not deterministic.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [-3_i32, 77, 53, 240, -1];
+ ///
+ /// assert_eq!(a.par_iter().max_by(|x, y| x.abs().cmp(&y.abs())), Some(&240));
+ /// ```
+ fn max_by<F>(self, f: F) -> Option<Self::Item>
+ where
+ F: Sync + Send + Fn(&Self::Item, &Self::Item) -> Ordering,
+ {
+ fn max<T>(f: impl Fn(&T, &T) -> Ordering) -> impl Fn(T, T) -> T {
+ move |a, b| match f(&a, &b) {
+ Ordering::Greater => a,
+ _ => b,
+ }
+ }
+
+ self.reduce_with(max(f))
+ }
+
+ /// Computes the item that yields the maximum value for the given
+ /// function. If the iterator is empty, `None` is returned;
+ /// otherwise, `Some(item)` is returned.
+ ///
+ /// Note that the order in which the items will be reduced is not
+ /// specified, so if the `Ord` impl is not truly associative, then
+ /// the results are not deterministic.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [-3_i32, 34, 2, 5, -10, -3, -23];
+ ///
+ /// assert_eq!(a.par_iter().max_by_key(|x| x.abs()), Some(&34));
+ /// ```
+ fn max_by_key<K, F>(self, f: F) -> Option<Self::Item>
+ where
+ K: Ord + Send,
+ F: Sync + Send + Fn(&Self::Item) -> K,
+ {
+ fn key<T, K>(f: impl Fn(&T) -> K) -> impl Fn(T) -> (K, T) {
+ move |x| (f(&x), x)
+ }
+
+ fn max_key<T, K: Ord>(a: (K, T), b: (K, T)) -> (K, T) {
+ match (a.0).cmp(&b.0) {
+ Ordering::Greater => a,
+ _ => b,
+ }
+ }
+
+ let (_, x) = self.map(key(f)).reduce_with(max_key)?;
+ Some(x)
+ }
+
+ /// Takes two iterators and creates a new iterator over both.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [0, 1, 2];
+ /// let b = [9, 8, 7];
+ ///
+ /// let par_iter = a.par_iter().chain(b.par_iter());
+ ///
+ /// let chained: Vec<_> = par_iter.cloned().collect();
+ ///
+ /// assert_eq!(&chained[..], &[0, 1, 2, 9, 8, 7]);
+ /// ```
+ fn chain<C>(self, chain: C) -> Chain<Self, C::Iter>
+ where
+ C: IntoParallelIterator<Item = Self::Item>,
+ {
+ Chain::new(self, chain.into_par_iter())
+ }
+
+ /// Searches for **some** item in the parallel iterator that
+ /// matches the given predicate and returns it. This operation
+ /// is similar to [`find` on sequential iterators][find] but
+ /// the item returned may not be the **first** one in the parallel
+ /// sequence which matches, since we search the entire sequence in parallel.
+ ///
+ /// Once a match is found, we will attempt to stop processing
+ /// the rest of the items in the iterator as soon as possible
+ /// (just as `find` stops iterating once a match is found).
+ ///
+ /// [find]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.find
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [1, 2, 3, 3];
+ ///
+ /// assert_eq!(a.par_iter().find_any(|&&x| x == 3), Some(&3));
+ ///
+ /// assert_eq!(a.par_iter().find_any(|&&x| x == 100), None);
+ /// ```
+ fn find_any<P>(self, predicate: P) -> Option<Self::Item>
+ where
+ P: Fn(&Self::Item) -> bool + Sync + Send,
+ {
+ find::find(self, predicate)
+ }
+
+ /// Searches for the sequentially **first** item in the parallel iterator
+ /// that matches the given predicate and returns it.
+ ///
+ /// Once a match is found, all attempts to the right of the match
+ /// will be stopped, while attempts to the left must continue in case
+ /// an earlier match is found.
+ ///
+ /// Note that not all parallel iterators have a useful order, much like
+ /// sequential `HashMap` iteration, so "first" may be nebulous. If you
+ /// just want the first match that discovered anywhere in the iterator,
+ /// `find_any` is a better choice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [1, 2, 3, 3];
+ ///
+ /// assert_eq!(a.par_iter().find_first(|&&x| x == 3), Some(&3));
+ ///
+ /// assert_eq!(a.par_iter().find_first(|&&x| x == 100), None);
+ /// ```
+ fn find_first<P>(self, predicate: P) -> Option<Self::Item>
+ where
+ P: Fn(&Self::Item) -> bool + Sync + Send,
+ {
+ find_first_last::find_first(self, predicate)
+ }
+
+ /// Searches for the sequentially **last** item in the parallel iterator
+ /// that matches the given predicate and returns it.
+ ///
+ /// Once a match is found, all attempts to the left of the match
+ /// will be stopped, while attempts to the right must continue in case
+ /// a later match is found.
+ ///
+ /// Note that not all parallel iterators have a useful order, much like
+ /// sequential `HashMap` iteration, so "last" may be nebulous. When the
+ /// order doesn't actually matter to you, `find_any` is a better choice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [1, 2, 3, 3];
+ ///
+ /// assert_eq!(a.par_iter().find_last(|&&x| x == 3), Some(&3));
+ ///
+ /// assert_eq!(a.par_iter().find_last(|&&x| x == 100), None);
+ /// ```
+ fn find_last<P>(self, predicate: P) -> Option<Self::Item>
+ where
+ P: Fn(&Self::Item) -> bool + Sync + Send,
+ {
+ find_first_last::find_last(self, predicate)
+ }
+
+ /// Applies the given predicate to the items in the parallel iterator
+ /// and returns **any** non-None result of the map operation.
+ ///
+ /// Once a non-None value is produced from the map operation, we will
+ /// attempt to stop processing the rest of the items in the iterator
+ /// as soon as possible.
+ ///
+ /// Note that this method only returns **some** item in the parallel
+ /// iterator that is not None from the map predicate. The item returned
+ /// may not be the **first** non-None value produced in the parallel
+ /// sequence, since the entire sequence is mapped over in parallel.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let c = ["lol", "NaN", "5", "5"];
+ ///
+ /// let found_number = c.par_iter().find_map_any(|s| s.parse().ok());
+ ///
+ /// assert_eq!(found_number, Some(5));
+ /// ```
+ fn find_map_any<P, R>(self, predicate: P) -> Option<R>
+ where
+ P: Fn(Self::Item) -> Option<R> + Sync + Send,
+ R: Send,
+ {
+ fn yes<T>(_: &T) -> bool {
+ true
+ }
+ self.filter_map(predicate).find_any(yes)
+ }
+
+ /// Applies the given predicate to the items in the parallel iterator and
+ /// returns the sequentially **first** non-None result of the map operation.
+ ///
+ /// Once a non-None value is produced from the map operation, all attempts
+ /// to the right of the match will be stopped, while attempts to the left
+ /// must continue in case an earlier match is found.
+ ///
+ /// Note that not all parallel iterators have a useful order, much like
+ /// sequential `HashMap` iteration, so "first" may be nebulous. If you
+ /// just want the first non-None value discovered anywhere in the iterator,
+ /// `find_map_any` is a better choice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let c = ["lol", "NaN", "2", "5"];
+ ///
+ /// let first_number = c.par_iter().find_map_first(|s| s.parse().ok());
+ ///
+ /// assert_eq!(first_number, Some(2));
+ /// ```
+ fn find_map_first<P, R>(self, predicate: P) -> Option<R>
+ where
+ P: Fn(Self::Item) -> Option<R> + Sync + Send,
+ R: Send,
+ {
+ fn yes<T>(_: &T) -> bool {
+ true
+ }
+ self.filter_map(predicate).find_first(yes)
+ }
+
+ /// Applies the given predicate to the items in the parallel iterator and
+ /// returns the sequentially **last** non-None result of the map operation.
+ ///
+ /// Once a non-None value is produced from the map operation, all attempts
+ /// to the left of the match will be stopped, while attempts to the right
+ /// must continue in case a later match is found.
+ ///
+ /// Note that not all parallel iterators have a useful order, much like
+ /// sequential `HashMap` iteration, so "first" may be nebulous. If you
+ /// just want the first non-None value discovered anywhere in the iterator,
+ /// `find_map_any` is a better choice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let c = ["lol", "NaN", "2", "5"];
+ ///
+ /// let last_number = c.par_iter().find_map_last(|s| s.parse().ok());
+ ///
+ /// assert_eq!(last_number, Some(5));
+ /// ```
+ fn find_map_last<P, R>(self, predicate: P) -> Option<R>
+ where
+ P: Fn(Self::Item) -> Option<R> + Sync + Send,
+ R: Send,
+ {
+ fn yes<T>(_: &T) -> bool {
+ true
+ }
+ self.filter_map(predicate).find_last(yes)
+ }
+
+ #[doc(hidden)]
+ #[deprecated(note = "parallel `find` does not search in order -- use `find_any`, \\
+ `find_first`, or `find_last`")]
+ fn find<P>(self, predicate: P) -> Option<Self::Item>
+ where
+ P: Fn(&Self::Item) -> bool + Sync + Send,
+ {
+ self.find_any(predicate)
+ }
+
+ /// Searches for **some** item in the parallel iterator that
+ /// matches the given predicate, and if so returns true. Once
+ /// a match is found, we'll attempt to stop process the rest
+ /// of the items. Proving that there's no match, returning false,
+ /// does require visiting every item.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [0, 12, 3, 4, 0, 23, 0];
+ ///
+ /// let is_valid = a.par_iter().any(|&x| x > 10);
+ ///
+ /// assert!(is_valid);
+ /// ```
+ fn any<P>(self, predicate: P) -> bool
+ where
+ P: Fn(Self::Item) -> bool + Sync + Send,
+ {
+ self.map(predicate).find_any(bool::clone).is_some()
+ }
+
+ /// Tests that every item in the parallel iterator matches the given
+ /// predicate, and if so returns true. If a counter-example is found,
+ /// we'll attempt to stop processing more items, then return false.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [0, 12, 3, 4, 0, 23, 0];
+ ///
+ /// let is_valid = a.par_iter().all(|&x| x > 10);
+ ///
+ /// assert!(!is_valid);
+ /// ```
+ fn all<P>(self, predicate: P) -> bool
+ where
+ P: Fn(Self::Item) -> bool + Sync + Send,
+ {
+ #[inline]
+ fn is_false(x: &bool) -> bool {
+ !x
+ }
+
+ self.map(predicate).find_any(is_false).is_none()
+ }
+
+ /// Creates an iterator over the `Some` items of this iterator, halting
+ /// as soon as any `None` is found.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// use std::sync::atomic::{AtomicUsize, Ordering};
+ ///
+ /// let counter = AtomicUsize::new(0);
+ /// let value = (0_i32..2048)
+ /// .into_par_iter()
+ /// .map(|x| {
+ /// counter.fetch_add(1, Ordering::SeqCst);
+ /// if x < 1024 { Some(x) } else { None }
+ /// })
+ /// .while_some()
+ /// .max();
+ ///
+ /// assert!(value < Some(1024));
+ /// assert!(counter.load(Ordering::SeqCst) < 2048); // should not have visited every single one
+ /// ```
+ fn while_some<T>(self) -> WhileSome<Self>
+ where
+ Self: ParallelIterator<Item = Option<T>>,
+ T: Send,
+ {
+ WhileSome::new(self)
+ }
+
+ /// Wraps an iterator with a fuse in case of panics, to halt all threads
+ /// as soon as possible.
+ ///
+ /// Panics within parallel iterators are always propagated to the caller,
+ /// but they don't always halt the rest of the iterator right away, due to
+ /// the internal semantics of [`join`]. This adaptor makes a greater effort
+ /// to stop processing other items sooner, with the cost of additional
+ /// synchronization overhead, which may also inhibit some optimizations.
+ ///
+ /// [`join`]: ../fn.join.html#panics
+ ///
+ /// # Examples
+ ///
+ /// If this code didn't use `panic_fuse()`, it would continue processing
+ /// many more items in other threads (with long sleep delays) before the
+ /// panic is finally propagated.
+ ///
+ /// ```should_panic
+ /// use rayon::prelude::*;
+ /// use std::{thread, time};
+ ///
+ /// (0..1_000_000)
+ /// .into_par_iter()
+ /// .panic_fuse()
+ /// .for_each(|i| {
+ /// // simulate some work
+ /// thread::sleep(time::Duration::from_secs(1));
+ /// assert!(i > 0); // oops!
+ /// });
+ /// ```
+ fn panic_fuse(self) -> PanicFuse<Self> {
+ PanicFuse::new(self)
+ }
+
+ /// Creates a fresh collection containing all the elements produced
+ /// by this parallel iterator.
+ ///
+ /// You may prefer [`collect_into_vec()`] implemented on
+ /// [`IndexedParallelIterator`], if your underlying iterator also implements
+ /// it. [`collect_into_vec()`] allocates efficiently with precise knowledge
+ /// of how many elements the iterator contains, and even allows you to reuse
+ /// an existing vector's backing store rather than allocating a fresh vector.
+ ///
+ /// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+ /// [`collect_into_vec()`]:
+ /// trait.IndexedParallelIterator.html#method.collect_into_vec
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let sync_vec: Vec<_> = (0..100).into_iter().collect();
+ ///
+ /// let async_vec: Vec<_> = (0..100).into_par_iter().collect();
+ ///
+ /// assert_eq!(sync_vec, async_vec);
+ /// ```
+ ///
+ /// You can collect a pair of collections like [`unzip`](#method.unzip)
+ /// for paired items:
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [(0, 1), (1, 2), (2, 3), (3, 4)];
+ /// let (first, second): (Vec<_>, Vec<_>) = a.into_par_iter().collect();
+ ///
+ /// assert_eq!(first, [0, 1, 2, 3]);
+ /// assert_eq!(second, [1, 2, 3, 4]);
+ /// ```
+ ///
+ /// Or like [`partition_map`](#method.partition_map) for `Either` items:
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// use rayon::iter::Either;
+ ///
+ /// let (left, right): (Vec<_>, Vec<_>) = (0..8).into_par_iter().map(|x| {
+ /// if x % 2 == 0 {
+ /// Either::Left(x * 4)
+ /// } else {
+ /// Either::Right(x * 3)
+ /// }
+ /// }).collect();
+ ///
+ /// assert_eq!(left, [0, 8, 16, 24]);
+ /// assert_eq!(right, [3, 9, 15, 21]);
+ /// ```
+ ///
+ /// You can even collect an arbitrarily-nested combination of pairs and `Either`:
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// use rayon::iter::Either;
+ ///
+ /// let (first, (left, right)): (Vec<_>, (Vec<_>, Vec<_>))
+ /// = (0..8).into_par_iter().map(|x| {
+ /// if x % 2 == 0 {
+ /// (x, Either::Left(x * 4))
+ /// } else {
+ /// (-x, Either::Right(x * 3))
+ /// }
+ /// }).collect();
+ ///
+ /// assert_eq!(first, [0, -1, 2, -3, 4, -5, 6, -7]);
+ /// assert_eq!(left, [0, 8, 16, 24]);
+ /// assert_eq!(right, [3, 9, 15, 21]);
+ /// ```
+ ///
+ /// All of that can _also_ be combined with short-circuiting collection of
+ /// `Result` or `Option` types:
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// use rayon::iter::Either;
+ ///
+ /// let result: Result<(Vec<_>, (Vec<_>, Vec<_>)), _>
+ /// = (0..8).into_par_iter().map(|x| {
+ /// if x > 5 {
+ /// Err(x)
+ /// } else if x % 2 == 0 {
+ /// Ok((x, Either::Left(x * 4)))
+ /// } else {
+ /// Ok((-x, Either::Right(x * 3)))
+ /// }
+ /// }).collect();
+ ///
+ /// let error = result.unwrap_err();
+ /// assert!(error == 6 || error == 7);
+ /// ```
+ fn collect<C>(self) -> C
+ where
+ C: FromParallelIterator<Self::Item>,
+ {
+ C::from_par_iter(self)
+ }
+
+ /// Unzips the items of a parallel iterator into a pair of arbitrary
+ /// `ParallelExtend` containers.
+ ///
+ /// You may prefer to use `unzip_into_vecs()`, which allocates more
+ /// efficiently with precise knowledge of how many elements the
+ /// iterator contains, and even allows you to reuse existing
+ /// vectors' backing stores rather than allocating fresh vectors.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [(0, 1), (1, 2), (2, 3), (3, 4)];
+ ///
+ /// let (left, right): (Vec<_>, Vec<_>) = a.par_iter().cloned().unzip();
+ ///
+ /// assert_eq!(left, [0, 1, 2, 3]);
+ /// assert_eq!(right, [1, 2, 3, 4]);
+ /// ```
+ ///
+ /// Nested pairs can be unzipped too.
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let (values, (squares, cubes)): (Vec<_>, (Vec<_>, Vec<_>)) = (0..4).into_par_iter()
+ /// .map(|i| (i, (i * i, i * i * i)))
+ /// .unzip();
+ ///
+ /// assert_eq!(values, [0, 1, 2, 3]);
+ /// assert_eq!(squares, [0, 1, 4, 9]);
+ /// assert_eq!(cubes, [0, 1, 8, 27]);
+ /// ```
+ fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB)
+ where
+ Self: ParallelIterator<Item = (A, B)>,
+ FromA: Default + Send + ParallelExtend<A>,
+ FromB: Default + Send + ParallelExtend<B>,
+ A: Send,
+ B: Send,
+ {
+ unzip::unzip(self)
+ }
+
+ /// Partitions the items of a parallel iterator into a pair of arbitrary
+ /// `ParallelExtend` containers. Items for which the `predicate` returns
+ /// true go into the first container, and the rest go into the second.
+ ///
+ /// Note: unlike the standard `Iterator::partition`, this allows distinct
+ /// collection types for the left and right items. This is more flexible,
+ /// but may require new type annotations when converting sequential code
+ /// that used type inference assuming the two were the same.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let (left, right): (Vec<_>, Vec<_>) = (0..8).into_par_iter().partition(|x| x % 2 == 0);
+ ///
+ /// assert_eq!(left, [0, 2, 4, 6]);
+ /// assert_eq!(right, [1, 3, 5, 7]);
+ /// ```
+ fn partition<A, B, P>(self, predicate: P) -> (A, B)
+ where
+ A: Default + Send + ParallelExtend<Self::Item>,
+ B: Default + Send + ParallelExtend<Self::Item>,
+ P: Fn(&Self::Item) -> bool + Sync + Send,
+ {
+ unzip::partition(self, predicate)
+ }
+
+ /// Partitions and maps the items of a parallel iterator into a pair of
+ /// arbitrary `ParallelExtend` containers. `Either::Left` items go into
+ /// the first container, and `Either::Right` items go into the second.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// use rayon::iter::Either;
+ ///
+ /// let (left, right): (Vec<_>, Vec<_>) = (0..8).into_par_iter()
+ /// .partition_map(|x| {
+ /// if x % 2 == 0 {
+ /// Either::Left(x * 4)
+ /// } else {
+ /// Either::Right(x * 3)
+ /// }
+ /// });
+ ///
+ /// assert_eq!(left, [0, 8, 16, 24]);
+ /// assert_eq!(right, [3, 9, 15, 21]);
+ /// ```
+ ///
+ /// Nested `Either` enums can be split as well.
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// use rayon::iter::Either::*;
+ ///
+ /// let ((fizzbuzz, fizz), (buzz, other)): ((Vec<_>, Vec<_>), (Vec<_>, Vec<_>)) = (1..20)
+ /// .into_par_iter()
+ /// .partition_map(|x| match (x % 3, x % 5) {
+ /// (0, 0) => Left(Left(x)),
+ /// (0, _) => Left(Right(x)),
+ /// (_, 0) => Right(Left(x)),
+ /// (_, _) => Right(Right(x)),
+ /// });
+ ///
+ /// assert_eq!(fizzbuzz, [15]);
+ /// assert_eq!(fizz, [3, 6, 9, 12, 18]);
+ /// assert_eq!(buzz, [5, 10]);
+ /// assert_eq!(other, [1, 2, 4, 7, 8, 11, 13, 14, 16, 17, 19]);
+ /// ```
+ fn partition_map<A, B, P, L, R>(self, predicate: P) -> (A, B)
+ where
+ A: Default + Send + ParallelExtend<L>,
+ B: Default + Send + ParallelExtend<R>,
+ P: Fn(Self::Item) -> Either<L, R> + Sync + Send,
+ L: Send,
+ R: Send,
+ {
+ unzip::partition_map(self, predicate)
+ }
+
+ /// Intersperses clones of an element between items of this iterator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let x = vec![1, 2, 3];
+ /// let r: Vec<_> = x.into_par_iter().intersperse(-1).collect();
+ ///
+ /// assert_eq!(r, vec![1, -1, 2, -1, 3]);
+ /// ```
+ fn intersperse(self, element: Self::Item) -> Intersperse<Self>
+ where
+ Self::Item: Clone,
+ {
+ Intersperse::new(self, element)
+ }
+
+ /// Internal method used to define the behavior of this parallel
+ /// iterator. You should not need to call this directly.
+ ///
+ /// This method causes the iterator `self` to start producing
+ /// items and to feed them to the consumer `consumer` one by one.
+ /// It may split the consumer before doing so to create the
+ /// opportunity to produce in parallel.
+ ///
+ /// See the [README] for more details on the internals of parallel
+ /// iterators.
+ ///
+ /// [README]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>;
+
+ /// Internal method used to define the behavior of this parallel
+ /// iterator. You should not need to call this directly.
+ ///
+ /// Returns the number of items produced by this iterator, if known
+ /// statically. This can be used by consumers to trigger special fast
+ /// paths. Therefore, if `Some(_)` is returned, this iterator must only
+ /// use the (indexed) `Consumer` methods when driving a consumer, such
+ /// as `split_at()`. Calling `UnindexedConsumer::split_off_left()` or
+ /// other `UnindexedConsumer` methods -- or returning an inaccurate
+ /// value -- may result in panics.
+ ///
+ /// This method is currently used to optimize `collect` for want
+ /// of true Rust specialization; it may be removed when
+ /// specialization is stable.
+ fn opt_len(&self) -> Option<usize> {
+ None
+ }
+}
+
+impl<T: ParallelIterator> IntoParallelIterator for T {
+ type Iter = T;
+ type Item = T::Item;
+
+ fn into_par_iter(self) -> T {
+ self
+ }
+}
+
+/// An iterator that supports "random access" to its data, meaning
+/// that you can split it at arbitrary indices and draw data from
+/// those points.
+///
+/// **Note:** Not implemented for `u64`, `i64`, `u128`, or `i128` ranges
+// Waiting for `ExactSizeIterator::is_empty` to be stabilized. See rust-lang/rust#35428
+#[allow(clippy::len_without_is_empty)]
+pub trait IndexedParallelIterator: ParallelIterator {
+ /// Collects the results of the iterator into the specified
+ /// vector. The vector is always truncated before execution
+ /// begins. If possible, reusing the vector across calls can lead
+ /// to better performance since it reuses the same backing buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// // any prior data will be truncated
+ /// let mut vec = vec![-1, -2, -3];
+ ///
+ /// (0..5).into_par_iter()
+ /// .collect_into_vec(&mut vec);
+ ///
+ /// assert_eq!(vec, [0, 1, 2, 3, 4]);
+ /// ```
+ fn collect_into_vec(self, target: &mut Vec<Self::Item>) {
+ collect::collect_into_vec(self, target);
+ }
+
+ /// Unzips the results of the iterator into the specified
+ /// vectors. The vectors are always truncated before execution
+ /// begins. If possible, reusing the vectors across calls can lead
+ /// to better performance since they reuse the same backing buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// // any prior data will be truncated
+ /// let mut left = vec![42; 10];
+ /// let mut right = vec![-1; 10];
+ ///
+ /// (10..15).into_par_iter()
+ /// .enumerate()
+ /// .unzip_into_vecs(&mut left, &mut right);
+ ///
+ /// assert_eq!(left, [0, 1, 2, 3, 4]);
+ /// assert_eq!(right, [10, 11, 12, 13, 14]);
+ /// ```
+ fn unzip_into_vecs<A, B>(self, left: &mut Vec<A>, right: &mut Vec<B>)
+ where
+ Self: IndexedParallelIterator<Item = (A, B)>,
+ A: Send,
+ B: Send,
+ {
+ collect::unzip_into_vecs(self, left, right);
+ }
+
+ /// Iterates over tuples `(A, B)`, where the items `A` are from
+ /// this iterator and `B` are from the iterator given as argument.
+ /// Like the `zip` method on ordinary iterators, if the two
+ /// iterators are of unequal length, you only get the items they
+ /// have in common.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let result: Vec<_> = (1..4)
+ /// .into_par_iter()
+ /// .zip(vec!['a', 'b', 'c'])
+ /// .collect();
+ ///
+ /// assert_eq!(result, [(1, 'a'), (2, 'b'), (3, 'c')]);
+ /// ```
+ fn zip<Z>(self, zip_op: Z) -> Zip<Self, Z::Iter>
+ where
+ Z: IntoParallelIterator,
+ Z::Iter: IndexedParallelIterator,
+ {
+ Zip::new(self, zip_op.into_par_iter())
+ }
+
+ /// The same as `Zip`, but requires that both iterators have the same length.
+ ///
+ /// # Panics
+ /// Will panic if `self` and `zip_op` are not the same length.
+ ///
+ /// ```should_panic
+ /// use rayon::prelude::*;
+ ///
+ /// let one = [1u8];
+ /// let two = [2u8, 2];
+ /// let one_iter = one.par_iter();
+ /// let two_iter = two.par_iter();
+ ///
+ /// // this will panic
+ /// let zipped: Vec<(&u8, &u8)> = one_iter.zip_eq(two_iter).collect();
+ ///
+ /// // we should never get here
+ /// assert_eq!(1, zipped.len());
+ /// ```
+ #[track_caller]
+ fn zip_eq<Z>(self, zip_op: Z) -> ZipEq<Self, Z::Iter>
+ where
+ Z: IntoParallelIterator,
+ Z::Iter: IndexedParallelIterator,
+ {
+ let zip_op_iter = zip_op.into_par_iter();
+ assert_eq!(
+ self.len(),
+ zip_op_iter.len(),
+ "iterators must have the same length"
+ );
+ ZipEq::new(self, zip_op_iter)
+ }
+
+ /// Interleaves elements of this iterator and the other given
+ /// iterator. Alternately yields elements from this iterator and
+ /// the given iterator, until both are exhausted. If one iterator
+ /// is exhausted before the other, the last elements are provided
+ /// from the other.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// let (x, y) = (vec![1, 2], vec![3, 4, 5, 6]);
+ /// let r: Vec<i32> = x.into_par_iter().interleave(y).collect();
+ /// assert_eq!(r, vec![1, 3, 2, 4, 5, 6]);
+ /// ```
+ fn interleave<I>(self, other: I) -> Interleave<Self, I::Iter>
+ where
+ I: IntoParallelIterator<Item = Self::Item>,
+ I::Iter: IndexedParallelIterator<Item = Self::Item>,
+ {
+ Interleave::new(self, other.into_par_iter())
+ }
+
+ /// Interleaves elements of this iterator and the other given
+ /// iterator, until one is exhausted.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// let (x, y) = (vec![1, 2, 3, 4], vec![5, 6]);
+ /// let r: Vec<i32> = x.into_par_iter().interleave_shortest(y).collect();
+ /// assert_eq!(r, vec![1, 5, 2, 6, 3]);
+ /// ```
+ fn interleave_shortest<I>(self, other: I) -> InterleaveShortest<Self, I::Iter>
+ where
+ I: IntoParallelIterator<Item = Self::Item>,
+ I::Iter: IndexedParallelIterator<Item = Self::Item>,
+ {
+ InterleaveShortest::new(self, other.into_par_iter())
+ }
+
+ /// Splits an iterator up into fixed-size chunks.
+ ///
+ /// Returns an iterator that returns `Vec`s of the given number of elements.
+ /// If the number of elements in the iterator is not divisible by `chunk_size`,
+ /// the last chunk may be shorter than `chunk_size`.
+ ///
+ /// See also [`par_chunks()`] and [`par_chunks_mut()`] for similar behavior on
+ /// slices, without having to allocate intermediate `Vec`s for the chunks.
+ ///
+ /// [`par_chunks()`]: ../slice/trait.ParallelSlice.html#method.par_chunks
+ /// [`par_chunks_mut()`]: ../slice/trait.ParallelSliceMut.html#method.par_chunks_mut
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// let a = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ /// let r: Vec<Vec<i32>> = a.into_par_iter().chunks(3).collect();
+ /// assert_eq!(r, vec![vec![1,2,3], vec![4,5,6], vec![7,8,9], vec![10]]);
+ /// ```
+ fn chunks(self, chunk_size: usize) -> Chunks<Self> {
+ assert!(chunk_size != 0, "chunk_size must not be zero");
+ Chunks::new(self, chunk_size)
+ }
+
+ /// Splits an iterator into fixed-size chunks, performing a sequential [`fold()`] on
+ /// each chunk.
+ ///
+ /// Returns an iterator that produces a folded result for each chunk of items
+ /// produced by this iterator.
+ ///
+ /// This works essentially like:
+ ///
+ /// ```text
+ /// iter.chunks(chunk_size)
+ /// .map(|chunk|
+ /// chunk.into_iter()
+ /// .fold(identity, fold_op)
+ /// )
+ /// ```
+ ///
+ /// except there is no per-chunk allocation overhead.
+ ///
+ /// [`fold()`]: std::iter::Iterator#method.fold
+ ///
+ /// **Panics** if `chunk_size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// let nums = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ /// let chunk_sums = nums.into_par_iter().fold_chunks(2, || 0, |a, n| a + n).collect::<Vec<_>>();
+ /// assert_eq!(chunk_sums, vec![3, 7, 11, 15, 19]);
+ /// ```
+ #[track_caller]
+ fn fold_chunks<T, ID, F>(
+ self,
+ chunk_size: usize,
+ identity: ID,
+ fold_op: F,
+ ) -> FoldChunks<Self, ID, F>
+ where
+ ID: Fn() -> T + Send + Sync,
+ F: Fn(T, Self::Item) -> T + Send + Sync,
+ T: Send,
+ {
+ assert!(chunk_size != 0, "chunk_size must not be zero");
+ FoldChunks::new(self, chunk_size, identity, fold_op)
+ }
+
+ /// Splits an iterator into fixed-size chunks, performing a sequential [`fold()`] on
+ /// each chunk.
+ ///
+ /// Returns an iterator that produces a folded result for each chunk of items
+ /// produced by this iterator.
+ ///
+ /// This works essentially like `fold_chunks(chunk_size, || init.clone(), fold_op)`,
+ /// except it doesn't require the `init` type to be `Sync`, nor any other form of
+ /// added synchronization.
+ ///
+ /// [`fold()`]: std::iter::Iterator#method.fold
+ ///
+ /// **Panics** if `chunk_size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// let nums = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ /// let chunk_sums = nums.into_par_iter().fold_chunks_with(2, 0, |a, n| a + n).collect::<Vec<_>>();
+ /// assert_eq!(chunk_sums, vec![3, 7, 11, 15, 19]);
+ /// ```
+ #[track_caller]
+ fn fold_chunks_with<T, F>(
+ self,
+ chunk_size: usize,
+ init: T,
+ fold_op: F,
+ ) -> FoldChunksWith<Self, T, F>
+ where
+ T: Send + Clone,
+ F: Fn(T, Self::Item) -> T + Send + Sync,
+ {
+ assert!(chunk_size != 0, "chunk_size must not be zero");
+ FoldChunksWith::new(self, chunk_size, init, fold_op)
+ }
+
+ /// Lexicographically compares the elements of this `ParallelIterator` with those of
+ /// another.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// use std::cmp::Ordering::*;
+ ///
+ /// let x = vec![1, 2, 3];
+ /// assert_eq!(x.par_iter().cmp(&vec![1, 3, 0]), Less);
+ /// assert_eq!(x.par_iter().cmp(&vec![1, 2, 3]), Equal);
+ /// assert_eq!(x.par_iter().cmp(&vec![1, 2]), Greater);
+ /// ```
+ fn cmp<I>(self, other: I) -> Ordering
+ where
+ I: IntoParallelIterator<Item = Self::Item>,
+ I::Iter: IndexedParallelIterator,
+ Self::Item: Ord,
+ {
+ #[inline]
+ fn ordering<T: Ord>((x, y): (T, T)) -> Ordering {
+ Ord::cmp(&x, &y)
+ }
+
+ #[inline]
+ fn inequal(&ord: &Ordering) -> bool {
+ ord != Ordering::Equal
+ }
+
+ let other = other.into_par_iter();
+ let ord_len = self.len().cmp(&other.len());
+ self.zip(other)
+ .map(ordering)
+ .find_first(inequal)
+ .unwrap_or(ord_len)
+ }
+
+ /// Lexicographically compares the elements of this `ParallelIterator` with those of
+ /// another.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// use std::cmp::Ordering::*;
+ /// use std::f64::NAN;
+ ///
+ /// let x = vec![1.0, 2.0, 3.0];
+ /// assert_eq!(x.par_iter().partial_cmp(&vec![1.0, 3.0, 0.0]), Some(Less));
+ /// assert_eq!(x.par_iter().partial_cmp(&vec![1.0, 2.0, 3.0]), Some(Equal));
+ /// assert_eq!(x.par_iter().partial_cmp(&vec![1.0, 2.0]), Some(Greater));
+ /// assert_eq!(x.par_iter().partial_cmp(&vec![1.0, NAN]), None);
+ /// ```
+ fn partial_cmp<I>(self, other: I) -> Option<Ordering>
+ where
+ I: IntoParallelIterator,
+ I::Iter: IndexedParallelIterator,
+ Self::Item: PartialOrd<I::Item>,
+ {
+ #[inline]
+ fn ordering<T: PartialOrd<U>, U>((x, y): (T, U)) -> Option<Ordering> {
+ PartialOrd::partial_cmp(&x, &y)
+ }
+
+ #[inline]
+ fn inequal(&ord: &Option<Ordering>) -> bool {
+ ord != Some(Ordering::Equal)
+ }
+
+ let other = other.into_par_iter();
+ let ord_len = self.len().cmp(&other.len());
+ self.zip(other)
+ .map(ordering)
+ .find_first(inequal)
+ .unwrap_or(Some(ord_len))
+ }
+
+ /// Determines if the elements of this `ParallelIterator`
+ /// are equal to those of another
+ fn eq<I>(self, other: I) -> bool
+ where
+ I: IntoParallelIterator,
+ I::Iter: IndexedParallelIterator,
+ Self::Item: PartialEq<I::Item>,
+ {
+ #[inline]
+ fn eq<T: PartialEq<U>, U>((x, y): (T, U)) -> bool {
+ PartialEq::eq(&x, &y)
+ }
+
+ let other = other.into_par_iter();
+ self.len() == other.len() && self.zip(other).all(eq)
+ }
+
+ /// Determines if the elements of this `ParallelIterator`
+ /// are unequal to those of another
+ fn ne<I>(self, other: I) -> bool
+ where
+ I: IntoParallelIterator,
+ I::Iter: IndexedParallelIterator,
+ Self::Item: PartialEq<I::Item>,
+ {
+ !self.eq(other)
+ }
+
+ /// Determines if the elements of this `ParallelIterator`
+ /// are lexicographically less than those of another.
+ fn lt<I>(self, other: I) -> bool
+ where
+ I: IntoParallelIterator,
+ I::Iter: IndexedParallelIterator,
+ Self::Item: PartialOrd<I::Item>,
+ {
+ self.partial_cmp(other) == Some(Ordering::Less)
+ }
+
+ /// Determines if the elements of this `ParallelIterator`
+ /// are less or equal to those of another.
+ fn le<I>(self, other: I) -> bool
+ where
+ I: IntoParallelIterator,
+ I::Iter: IndexedParallelIterator,
+ Self::Item: PartialOrd<I::Item>,
+ {
+ let ord = self.partial_cmp(other);
+ ord == Some(Ordering::Equal) || ord == Some(Ordering::Less)
+ }
+
+ /// Determines if the elements of this `ParallelIterator`
+ /// are lexicographically greater than those of another.
+ fn gt<I>(self, other: I) -> bool
+ where
+ I: IntoParallelIterator,
+ I::Iter: IndexedParallelIterator,
+ Self::Item: PartialOrd<I::Item>,
+ {
+ self.partial_cmp(other) == Some(Ordering::Greater)
+ }
+
+ /// Determines if the elements of this `ParallelIterator`
+ /// are less or equal to those of another.
+ fn ge<I>(self, other: I) -> bool
+ where
+ I: IntoParallelIterator,
+ I::Iter: IndexedParallelIterator,
+ Self::Item: PartialOrd<I::Item>,
+ {
+ let ord = self.partial_cmp(other);
+ ord == Some(Ordering::Equal) || ord == Some(Ordering::Greater)
+ }
+
+ /// Yields an index along with each item.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let chars = vec!['a', 'b', 'c'];
+ /// let result: Vec<_> = chars
+ /// .into_par_iter()
+ /// .enumerate()
+ /// .collect();
+ ///
+ /// assert_eq!(result, [(0, 'a'), (1, 'b'), (2, 'c')]);
+ /// ```
+ fn enumerate(self) -> Enumerate<Self> {
+ Enumerate::new(self)
+ }
+
+ /// Creates an iterator that steps by the given amount
+ ///
+ /// # Examples
+ ///
+ /// ```
+ ///use rayon::prelude::*;
+ ///
+ /// let range = (3..10);
+ /// let result: Vec<i32> = range
+ /// .into_par_iter()
+ /// .step_by(3)
+ /// .collect();
+ ///
+ /// assert_eq!(result, [3, 6, 9])
+ /// ```
+ fn step_by(self, step: usize) -> StepBy<Self> {
+ StepBy::new(self, step)
+ }
+
+ /// Creates an iterator that skips the first `n` elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let result: Vec<_> = (0..100)
+ /// .into_par_iter()
+ /// .skip(95)
+ /// .collect();
+ ///
+ /// assert_eq!(result, [95, 96, 97, 98, 99]);
+ /// ```
+ fn skip(self, n: usize) -> Skip<Self> {
+ Skip::new(self, n)
+ }
+
+ /// Creates an iterator that yields the first `n` elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let result: Vec<_> = (0..100)
+ /// .into_par_iter()
+ /// .take(5)
+ /// .collect();
+ ///
+ /// assert_eq!(result, [0, 1, 2, 3, 4]);
+ /// ```
+ fn take(self, n: usize) -> Take<Self> {
+ Take::new(self, n)
+ }
+
+ /// Searches for **some** item in the parallel iterator that
+ /// matches the given predicate, and returns its index. Like
+ /// `ParallelIterator::find_any`, the parallel search will not
+ /// necessarily find the **first** match, and once a match is
+ /// found we'll attempt to stop processing any more.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [1, 2, 3, 3];
+ ///
+ /// let i = a.par_iter().position_any(|&x| x == 3).expect("found");
+ /// assert!(i == 2 || i == 3);
+ ///
+ /// assert_eq!(a.par_iter().position_any(|&x| x == 100), None);
+ /// ```
+ fn position_any<P>(self, predicate: P) -> Option<usize>
+ where
+ P: Fn(Self::Item) -> bool + Sync + Send,
+ {
+ #[inline]
+ fn check(&(_, p): &(usize, bool)) -> bool {
+ p
+ }
+
+ let (i, _) = self.map(predicate).enumerate().find_any(check)?;
+ Some(i)
+ }
+
+ /// Searches for the sequentially **first** item in the parallel iterator
+ /// that matches the given predicate, and returns its index.
+ ///
+ /// Like `ParallelIterator::find_first`, once a match is found,
+ /// all attempts to the right of the match will be stopped, while
+ /// attempts to the left must continue in case an earlier match
+ /// is found.
+ ///
+ /// Note that not all parallel iterators have a useful order, much like
+ /// sequential `HashMap` iteration, so "first" may be nebulous. If you
+ /// just want the first match that discovered anywhere in the iterator,
+ /// `position_any` is a better choice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [1, 2, 3, 3];
+ ///
+ /// assert_eq!(a.par_iter().position_first(|&x| x == 3), Some(2));
+ ///
+ /// assert_eq!(a.par_iter().position_first(|&x| x == 100), None);
+ /// ```
+ fn position_first<P>(self, predicate: P) -> Option<usize>
+ where
+ P: Fn(Self::Item) -> bool + Sync + Send,
+ {
+ #[inline]
+ fn check(&(_, p): &(usize, bool)) -> bool {
+ p
+ }
+
+ let (i, _) = self.map(predicate).enumerate().find_first(check)?;
+ Some(i)
+ }
+
+ /// Searches for the sequentially **last** item in the parallel iterator
+ /// that matches the given predicate, and returns its index.
+ ///
+ /// Like `ParallelIterator::find_last`, once a match is found,
+ /// all attempts to the left of the match will be stopped, while
+ /// attempts to the right must continue in case a later match
+ /// is found.
+ ///
+ /// Note that not all parallel iterators have a useful order, much like
+ /// sequential `HashMap` iteration, so "last" may be nebulous. When the
+ /// order doesn't actually matter to you, `position_any` is a better
+ /// choice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let a = [1, 2, 3, 3];
+ ///
+ /// assert_eq!(a.par_iter().position_last(|&x| x == 3), Some(3));
+ ///
+ /// assert_eq!(a.par_iter().position_last(|&x| x == 100), None);
+ /// ```
+ fn position_last<P>(self, predicate: P) -> Option<usize>
+ where
+ P: Fn(Self::Item) -> bool + Sync + Send,
+ {
+ #[inline]
+ fn check(&(_, p): &(usize, bool)) -> bool {
+ p
+ }
+
+ let (i, _) = self.map(predicate).enumerate().find_last(check)?;
+ Some(i)
+ }
+
+ #[doc(hidden)]
+ #[deprecated(
+ note = "parallel `position` does not search in order -- use `position_any`, \\
+ `position_first`, or `position_last`"
+ )]
+ fn position<P>(self, predicate: P) -> Option<usize>
+ where
+ P: Fn(Self::Item) -> bool + Sync + Send,
+ {
+ self.position_any(predicate)
+ }
+
+ /// Searches for items in the parallel iterator that match the given
+ /// predicate, and returns their indices.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let primes = vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
+ ///
+ /// // Find the positions of primes congruent to 1 modulo 6
+ /// let p1mod6: Vec<_> = primes.par_iter().positions(|&p| p % 6 == 1).collect();
+ /// assert_eq!(p1mod6, [3, 5, 7]); // primes 7, 13, and 19
+ ///
+ /// // Find the positions of primes congruent to 5 modulo 6
+ /// let p5mod6: Vec<_> = primes.par_iter().positions(|&p| p % 6 == 5).collect();
+ /// assert_eq!(p5mod6, [2, 4, 6, 8, 9]); // primes 5, 11, 17, 23, and 29
+ /// ```
+ fn positions<P>(self, predicate: P) -> Positions<Self, P>
+ where
+ P: Fn(Self::Item) -> bool + Sync + Send,
+ {
+ Positions::new(self, predicate)
+ }
+
+ /// Produces a new iterator with the elements of this iterator in
+ /// reverse order.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let result: Vec<_> = (0..5)
+ /// .into_par_iter()
+ /// .rev()
+ /// .collect();
+ ///
+ /// assert_eq!(result, [4, 3, 2, 1, 0]);
+ /// ```
+ fn rev(self) -> Rev<Self> {
+ Rev::new(self)
+ }
+
+ /// Sets the minimum length of iterators desired to process in each
+ /// rayon job. Rayon will not split any smaller than this length, but
+ /// of course an iterator could already be smaller to begin with.
+ ///
+ /// Producers like `zip` and `interleave` will use greater of the two
+ /// minimums.
+ /// Chained iterators and iterators inside `flat_map` may each use
+ /// their own minimum length.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let min = (0..1_000_000)
+ /// .into_par_iter()
+ /// .with_min_len(1234)
+ /// .fold(|| 0, |acc, _| acc + 1) // count how many are in this segment
+ /// .min().unwrap();
+ ///
+ /// assert!(min >= 1234);
+ /// ```
+ fn with_min_len(self, min: usize) -> MinLen<Self> {
+ MinLen::new(self, min)
+ }
+
+ /// Sets the maximum length of iterators desired to process in each
+ /// rayon job. Rayon will try to split at least below this length,
+ /// unless that would put it below the length from `with_min_len()`.
+ /// For example, given min=10 and max=15, a length of 16 will not be
+ /// split any further.
+ ///
+ /// Producers like `zip` and `interleave` will use lesser of the two
+ /// maximums.
+ /// Chained iterators and iterators inside `flat_map` may each use
+ /// their own maximum length.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let max = (0..1_000_000)
+ /// .into_par_iter()
+ /// .with_max_len(1234)
+ /// .fold(|| 0, |acc, _| acc + 1) // count how many are in this segment
+ /// .max().unwrap();
+ ///
+ /// assert!(max <= 1234);
+ /// ```
+ fn with_max_len(self, max: usize) -> MaxLen<Self> {
+ MaxLen::new(self, max)
+ }
+
+ /// Produces an exact count of how many items this iterator will
+ /// produce, presuming no panic occurs.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let par_iter = (0..100).into_par_iter().zip(vec![0; 10]);
+ /// assert_eq!(par_iter.len(), 10);
+ ///
+ /// let vec: Vec<_> = par_iter.collect();
+ /// assert_eq!(vec.len(), 10);
+ /// ```
+ fn len(&self) -> usize;
+
+ /// Internal method used to define the behavior of this parallel
+ /// iterator. You should not need to call this directly.
+ ///
+ /// This method causes the iterator `self` to start producing
+ /// items and to feed them to the consumer `consumer` one by one.
+ /// It may split the consumer before doing so to create the
+ /// opportunity to produce in parallel. If a split does happen, it
+ /// will inform the consumer of the index where the split should
+ /// occur (unlike `ParallelIterator::drive_unindexed()`).
+ ///
+ /// See the [README] for more details on the internals of parallel
+ /// iterators.
+ ///
+ /// [README]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
+ fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result;
+
+ /// Internal method used to define the behavior of this parallel
+ /// iterator. You should not need to call this directly.
+ ///
+ /// This method converts the iterator into a producer P and then
+ /// invokes `callback.callback()` with P. Note that the type of
+ /// this producer is not defined as part of the API, since
+ /// `callback` must be defined generically for all producers. This
+ /// allows the producer type to contain references; it also means
+ /// that parallel iterators can adjust that type without causing a
+ /// breaking change.
+ ///
+ /// See the [README] for more details on the internals of parallel
+ /// iterators.
+ ///
+ /// [README]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
+ fn with_producer<CB: ProducerCallback<Self::Item>>(self, callback: CB) -> CB::Output;
+}
+
+/// `FromParallelIterator` implements the creation of a collection
+/// from a [`ParallelIterator`]. By implementing
+/// `FromParallelIterator` for a given type, you define how it will be
+/// created from an iterator.
+///
+/// `FromParallelIterator` is used through [`ParallelIterator`]'s [`collect()`] method.
+///
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+/// [`collect()`]: trait.ParallelIterator.html#method.collect
+///
+/// # Examples
+///
+/// Implementing `FromParallelIterator` for your type:
+///
+/// ```
+/// use rayon::prelude::*;
+/// use std::mem;
+///
+/// struct BlackHole {
+/// mass: usize,
+/// }
+///
+/// impl<T: Send> FromParallelIterator<T> for BlackHole {
+/// fn from_par_iter<I>(par_iter: I) -> Self
+/// where I: IntoParallelIterator<Item = T>
+/// {
+/// let par_iter = par_iter.into_par_iter();
+/// BlackHole {
+/// mass: par_iter.count() * mem::size_of::<T>(),
+/// }
+/// }
+/// }
+///
+/// let bh: BlackHole = (0i32..1000).into_par_iter().collect();
+/// assert_eq!(bh.mass, 4000);
+/// ```
+pub trait FromParallelIterator<T>
+where
+ T: Send,
+{
+ /// Creates an instance of the collection from the parallel iterator `par_iter`.
+ ///
+ /// If your collection is not naturally parallel, the easiest (and
+ /// fastest) way to do this is often to collect `par_iter` into a
+ /// [`LinkedList`] or other intermediate data structure and then
+ /// sequentially extend your collection. However, a more 'native'
+ /// technique is to use the [`par_iter.fold`] or
+ /// [`par_iter.fold_with`] methods to create the collection.
+ /// Alternatively, if your collection is 'natively' parallel, you
+ /// can use `par_iter.for_each` to process each element in turn.
+ ///
+ /// [`LinkedList`]: https://doc.rust-lang.org/std/collections/struct.LinkedList.html
+ /// [`par_iter.fold`]: trait.ParallelIterator.html#method.fold
+ /// [`par_iter.fold_with`]: trait.ParallelIterator.html#method.fold_with
+ /// [`par_iter.for_each`]: trait.ParallelIterator.html#method.for_each
+ fn from_par_iter<I>(par_iter: I) -> Self
+ where
+ I: IntoParallelIterator<Item = T>;
+}
+
+/// `ParallelExtend` extends an existing collection with items from a [`ParallelIterator`].
+///
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+///
+/// # Examples
+///
+/// Implementing `ParallelExtend` for your type:
+///
+/// ```
+/// use rayon::prelude::*;
+/// use std::mem;
+///
+/// struct BlackHole {
+/// mass: usize,
+/// }
+///
+/// impl<T: Send> ParallelExtend<T> for BlackHole {
+/// fn par_extend<I>(&mut self, par_iter: I)
+/// where I: IntoParallelIterator<Item = T>
+/// {
+/// let par_iter = par_iter.into_par_iter();
+/// self.mass += par_iter.count() * mem::size_of::<T>();
+/// }
+/// }
+///
+/// let mut bh = BlackHole { mass: 0 };
+/// bh.par_extend(0i32..1000);
+/// assert_eq!(bh.mass, 4000);
+/// bh.par_extend(0i64..10);
+/// assert_eq!(bh.mass, 4080);
+/// ```
+pub trait ParallelExtend<T>
+where
+ T: Send,
+{
+ /// Extends an instance of the collection with the elements drawn
+ /// from the parallel iterator `par_iter`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let mut vec = vec![];
+ /// vec.par_extend(0..5);
+ /// vec.par_extend((0..5).into_par_iter().map(|i| i * i));
+ /// assert_eq!(vec, [0, 1, 2, 3, 4, 0, 1, 4, 9, 16]);
+ /// ```
+ fn par_extend<I>(&mut self, par_iter: I)
+ where
+ I: IntoParallelIterator<Item = T>;
+}
+
+/// `ParallelDrainFull` creates a parallel iterator that moves all items
+/// from a collection while retaining the original capacity.
+///
+/// Types which are indexable typically implement [`ParallelDrainRange`]
+/// instead, where you can drain fully with `par_drain(..)`.
+///
+/// [`ParallelDrainRange`]: trait.ParallelDrainRange.html
+pub trait ParallelDrainFull {
+ /// The draining parallel iterator type that will be created.
+ type Iter: ParallelIterator<Item = Self::Item>;
+
+ /// The type of item that the parallel iterator will produce.
+ /// This is usually the same as `IntoParallelIterator::Item`.
+ type Item: Send;
+
+ /// Returns a draining parallel iterator over an entire collection.
+ ///
+ /// When the iterator is dropped, all items are removed, even if the
+ /// iterator was not fully consumed. If the iterator is leaked, for example
+ /// using `std::mem::forget`, it is unspecified how many items are removed.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ /// use std::collections::{BinaryHeap, HashSet};
+ ///
+ /// let squares: HashSet<i32> = (0..10).map(|x| x * x).collect();
+ ///
+ /// let mut heap: BinaryHeap<_> = squares.iter().copied().collect();
+ /// assert_eq!(
+ /// // heaps are drained in arbitrary order
+ /// heap.par_drain()
+ /// .inspect(|x| assert!(squares.contains(x)))
+ /// .count(),
+ /// squares.len(),
+ /// );
+ /// assert!(heap.is_empty());
+ /// assert!(heap.capacity() >= squares.len());
+ /// ```
+ fn par_drain(self) -> Self::Iter;
+}
+
+/// `ParallelDrainRange` creates a parallel iterator that moves a range of items
+/// from a collection while retaining the original capacity.
+///
+/// Types which are not indexable may implement [`ParallelDrainFull`] instead.
+///
+/// [`ParallelDrainFull`]: trait.ParallelDrainFull.html
+pub trait ParallelDrainRange<Idx = usize> {
+ /// The draining parallel iterator type that will be created.
+ type Iter: ParallelIterator<Item = Self::Item>;
+
+ /// The type of item that the parallel iterator will produce.
+ /// This is usually the same as `IntoParallelIterator::Item`.
+ type Item: Send;
+
+ /// Returns a draining parallel iterator over a range of the collection.
+ ///
+ /// When the iterator is dropped, all items in the range are removed, even
+ /// if the iterator was not fully consumed. If the iterator is leaked, for
+ /// example using `std::mem::forget`, it is unspecified how many items are
+ /// removed.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use rayon::prelude::*;
+ ///
+ /// let squares: Vec<i32> = (0..10).map(|x| x * x).collect();
+ ///
+ /// println!("RangeFull");
+ /// let mut vec = squares.clone();
+ /// assert!(vec.par_drain(..)
+ /// .eq(squares.par_iter().copied()));
+ /// assert!(vec.is_empty());
+ /// assert!(vec.capacity() >= squares.len());
+ ///
+ /// println!("RangeFrom");
+ /// let mut vec = squares.clone();
+ /// assert!(vec.par_drain(5..)
+ /// .eq(squares[5..].par_iter().copied()));
+ /// assert_eq!(&vec[..], &squares[..5]);
+ /// assert!(vec.capacity() >= squares.len());
+ ///
+ /// println!("RangeTo");
+ /// let mut vec = squares.clone();
+ /// assert!(vec.par_drain(..5)
+ /// .eq(squares[..5].par_iter().copied()));
+ /// assert_eq!(&vec[..], &squares[5..]);
+ /// assert!(vec.capacity() >= squares.len());
+ ///
+ /// println!("RangeToInclusive");
+ /// let mut vec = squares.clone();
+ /// assert!(vec.par_drain(..=5)
+ /// .eq(squares[..=5].par_iter().copied()));
+ /// assert_eq!(&vec[..], &squares[6..]);
+ /// assert!(vec.capacity() >= squares.len());
+ ///
+ /// println!("Range");
+ /// let mut vec = squares.clone();
+ /// assert!(vec.par_drain(3..7)
+ /// .eq(squares[3..7].par_iter().copied()));
+ /// assert_eq!(&vec[..3], &squares[..3]);
+ /// assert_eq!(&vec[3..], &squares[7..]);
+ /// assert!(vec.capacity() >= squares.len());
+ ///
+ /// println!("RangeInclusive");
+ /// let mut vec = squares.clone();
+ /// assert!(vec.par_drain(3..=7)
+ /// .eq(squares[3..=7].par_iter().copied()));
+ /// assert_eq!(&vec[..3], &squares[..3]);
+ /// assert_eq!(&vec[3..], &squares[8..]);
+ /// assert!(vec.capacity() >= squares.len());
+ /// ```
+ fn par_drain<R: RangeBounds<Idx>>(self, range: R) -> Self::Iter;
+}
+
+/// We hide the `Try` trait in a private module, as it's only meant to be a
+/// stable clone of the standard library's `Try` trait, as yet unstable.
+mod private {
+ use std::convert::Infallible;
+ use std::ops::ControlFlow::{self, Break, Continue};
+ use std::task::Poll;
+
+ /// Clone of `std::ops::Try`.
+ ///
+ /// Implementing this trait is not permitted outside of `rayon`.
+ pub trait Try {
+ private_decl! {}
+
+ type Output;
+ type Residual;
+
+ fn from_output(output: Self::Output) -> Self;
+
+ fn from_residual(residual: Self::Residual) -> Self;
+
+ fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
+ }
+
+ impl<B, C> Try for ControlFlow<B, C> {
+ private_impl! {}
+
+ type Output = C;
+ type Residual = ControlFlow<B, Infallible>;
+
+ fn from_output(output: Self::Output) -> Self {
+ Continue(output)
+ }
+
+ fn from_residual(residual: Self::Residual) -> Self {
+ match residual {
+ Break(b) => Break(b),
+ Continue(_) => unreachable!(),
+ }
+ }
+
+ fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
+ match self {
+ Continue(c) => Continue(c),
+ Break(b) => Break(Break(b)),
+ }
+ }
+ }
+
+ impl<T> Try for Option<T> {
+ private_impl! {}
+
+ type Output = T;
+ type Residual = Option<Infallible>;
+
+ fn from_output(output: Self::Output) -> Self {
+ Some(output)
+ }
+
+ fn from_residual(residual: Self::Residual) -> Self {
+ match residual {
+ None => None,
+ Some(_) => unreachable!(),
+ }
+ }
+
+ fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
+ match self {
+ Some(c) => Continue(c),
+ None => Break(None),
+ }
+ }
+ }
+
+ impl<T, E> Try for Result<T, E> {
+ private_impl! {}
+
+ type Output = T;
+ type Residual = Result<Infallible, E>;
+
+ fn from_output(output: Self::Output) -> Self {
+ Ok(output)
+ }
+
+ fn from_residual(residual: Self::Residual) -> Self {
+ match residual {
+ Err(e) => Err(e),
+ Ok(_) => unreachable!(),
+ }
+ }
+
+ fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
+ match self {
+ Ok(c) => Continue(c),
+ Err(e) => Break(Err(e)),
+ }
+ }
+ }
+
+ impl<T, E> Try for Poll<Result<T, E>> {
+ private_impl! {}
+
+ type Output = Poll<T>;
+ type Residual = Result<Infallible, E>;
+
+ fn from_output(output: Self::Output) -> Self {
+ output.map(Ok)
+ }
+
+ fn from_residual(residual: Self::Residual) -> Self {
+ match residual {
+ Err(e) => Poll::Ready(Err(e)),
+ Ok(_) => unreachable!(),
+ }
+ }
+
+ fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
+ match self {
+ Poll::Pending => Continue(Poll::Pending),
+ Poll::Ready(Ok(c)) => Continue(Poll::Ready(c)),
+ Poll::Ready(Err(e)) => Break(Err(e)),
+ }
+ }
+ }
+
+ impl<T, E> Try for Poll<Option<Result<T, E>>> {
+ private_impl! {}
+
+ type Output = Poll<Option<T>>;
+ type Residual = Result<Infallible, E>;
+
+ fn from_output(output: Self::Output) -> Self {
+ match output {
+ Poll::Ready(o) => Poll::Ready(o.map(Ok)),
+ Poll::Pending => Poll::Pending,
+ }
+ }
+
+ fn from_residual(residual: Self::Residual) -> Self {
+ match residual {
+ Err(e) => Poll::Ready(Some(Err(e))),
+ Ok(_) => unreachable!(),
+ }
+ }
+
+ fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
+ match self {
+ Poll::Pending => Continue(Poll::Pending),
+ Poll::Ready(None) => Continue(Poll::Ready(None)),
+ Poll::Ready(Some(Ok(c))) => Continue(Poll::Ready(Some(c))),
+ Poll::Ready(Some(Err(e))) => Break(Err(e)),
+ }
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/multizip.rs b/third_party/rust/rayon/src/iter/multizip.rs
new file mode 100644
index 0000000000..8e36d08a29
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/multizip.rs
@@ -0,0 +1,338 @@
+use super::plumbing::*;
+use super::*;
+
+/// `MultiZip` is an iterator that zips up a tuple of parallel iterators to
+/// produce tuples of their items.
+///
+/// It is created by calling `into_par_iter()` on a tuple of types that
+/// implement `IntoParallelIterator`, or `par_iter()`/`par_iter_mut()` with
+/// types that are iterable by reference.
+///
+/// The implementation currently support tuples up to length 12.
+///
+/// # Examples
+///
+/// ```
+/// use rayon::prelude::*;
+///
+/// // This will iterate `r` by mutable reference, like `par_iter_mut()`, while
+/// // ranges are all iterated by value like `into_par_iter()`.
+/// // Note that the zipped iterator is only as long as the shortest input.
+/// let mut r = vec![0; 3];
+/// (&mut r, 1..10, 10..100, 100..1000).into_par_iter()
+/// .for_each(|(r, x, y, z)| *r = x * y + z);
+///
+/// assert_eq!(&r, &[1 * 10 + 100, 2 * 11 + 101, 3 * 12 + 102]);
+/// ```
+///
+/// For a group that should all be iterated by reference, you can use a tuple reference.
+///
+/// ```
+/// use rayon::prelude::*;
+///
+/// let xs: Vec<_> = (1..10).collect();
+/// let ys: Vec<_> = (10..100).collect();
+/// let zs: Vec<_> = (100..1000).collect();
+///
+/// // Reference each input separately with `IntoParallelIterator`:
+/// let r1: Vec<_> = (&xs, &ys, &zs).into_par_iter()
+/// .map(|(x, y, z)| x * y + z)
+/// .collect();
+///
+/// // Reference them all together with `IntoParallelRefIterator`:
+/// let r2: Vec<_> = (xs, ys, zs).par_iter()
+/// .map(|(x, y, z)| x * y + z)
+/// .collect();
+///
+/// assert_eq!(r1, r2);
+/// ```
+///
+/// Mutable references to a tuple will work similarly.
+///
+/// ```
+/// use rayon::prelude::*;
+///
+/// let mut xs: Vec<_> = (1..4).collect();
+/// let mut ys: Vec<_> = (-4..-1).collect();
+/// let mut zs = vec![0; 3];
+///
+/// // Mutably reference each input separately with `IntoParallelIterator`:
+/// (&mut xs, &mut ys, &mut zs).into_par_iter().for_each(|(x, y, z)| {
+/// *z += *x + *y;
+/// std::mem::swap(x, y);
+/// });
+///
+/// assert_eq!(xs, (vec![-4, -3, -2]));
+/// assert_eq!(ys, (vec![1, 2, 3]));
+/// assert_eq!(zs, (vec![-3, -1, 1]));
+///
+/// // Mutably reference them all together with `IntoParallelRefMutIterator`:
+/// let mut tuple = (xs, ys, zs);
+/// tuple.par_iter_mut().for_each(|(x, y, z)| {
+/// *z += *x + *y;
+/// std::mem::swap(x, y);
+/// });
+///
+/// assert_eq!(tuple, (vec![1, 2, 3], vec![-4, -3, -2], vec![-6, -2, 2]));
+/// ```
+#[derive(Debug, Clone)]
+pub struct MultiZip<T> {
+ tuple: T,
+}
+
+// These macros greedily consume 4 or 2 items first to achieve log2 nesting depth.
+// For example, 5 => 4,1 => (2,2),1.
+//
+// The tuples go up to 12, so we might want to greedily consume 8 too, but
+// the depth works out the same if we let that expand on the right:
+// 9 => 4,5 => (2,2),(4,1) => (2,2),((2,2),1)
+// 12 => 4,8 => (2,2),(4,4) => (2,2),((2,2),(2,2))
+//
+// But if we ever increase to 13, we would want to split 8,5 rather than 4,9.
+
+macro_rules! reduce {
+ ($a:expr, $b:expr, $c:expr, $d:expr, $( $x:expr ),+ => $fn:path) => {
+ reduce!(reduce!($a, $b, $c, $d => $fn),
+ reduce!($( $x ),+ => $fn)
+ => $fn)
+ };
+ ($a:expr, $b:expr, $( $x:expr ),+ => $fn:path) => {
+ reduce!(reduce!($a, $b => $fn),
+ reduce!($( $x ),+ => $fn)
+ => $fn)
+ };
+ ($a:expr, $b:expr => $fn:path) => { $fn($a, $b) };
+ ($a:expr => $fn:path) => { $a };
+}
+
+macro_rules! nest {
+ ($A:tt, $B:tt, $C:tt, $D:tt, $( $X:tt ),+) => {
+ (nest!($A, $B, $C, $D), nest!($( $X ),+))
+ };
+ ($A:tt, $B:tt, $( $X:tt ),+) => {
+ (($A, $B), nest!($( $X ),+))
+ };
+ ($A:tt, $B:tt) => { ($A, $B) };
+ ($A:tt) => { $A };
+}
+
+macro_rules! flatten {
+ ($( $T:ident ),+) => {{
+ #[allow(non_snake_case)]
+ fn flatten<$( $T ),+>(nest!($( $T ),+) : nest!($( $T ),+)) -> ($( $T, )+) {
+ ($( $T, )+)
+ }
+ flatten
+ }};
+}
+
+macro_rules! multizip_impls {
+ ($(
+ $Tuple:ident {
+ $(($idx:tt) -> $T:ident)+
+ }
+ )+) => {
+ $(
+ impl<$( $T, )+> IntoParallelIterator for ($( $T, )+)
+ where
+ $(
+ $T: IntoParallelIterator,
+ $T::Iter: IndexedParallelIterator,
+ )+
+ {
+ type Item = ($( $T::Item, )+);
+ type Iter = MultiZip<($( $T::Iter, )+)>;
+
+ fn into_par_iter(self) -> Self::Iter {
+ MultiZip {
+ tuple: ( $( self.$idx.into_par_iter(), )+ ),
+ }
+ }
+ }
+
+ impl<'a, $( $T, )+> IntoParallelIterator for &'a ($( $T, )+)
+ where
+ $(
+ $T: IntoParallelRefIterator<'a>,
+ $T::Iter: IndexedParallelIterator,
+ )+
+ {
+ type Item = ($( $T::Item, )+);
+ type Iter = MultiZip<($( $T::Iter, )+)>;
+
+ fn into_par_iter(self) -> Self::Iter {
+ MultiZip {
+ tuple: ( $( self.$idx.par_iter(), )+ ),
+ }
+ }
+ }
+
+ impl<'a, $( $T, )+> IntoParallelIterator for &'a mut ($( $T, )+)
+ where
+ $(
+ $T: IntoParallelRefMutIterator<'a>,
+ $T::Iter: IndexedParallelIterator,
+ )+
+ {
+ type Item = ($( $T::Item, )+);
+ type Iter = MultiZip<($( $T::Iter, )+)>;
+
+ fn into_par_iter(self) -> Self::Iter {
+ MultiZip {
+ tuple: ( $( self.$idx.par_iter_mut(), )+ ),
+ }
+ }
+ }
+
+ impl<$( $T, )+> ParallelIterator for MultiZip<($( $T, )+)>
+ where
+ $( $T: IndexedParallelIterator, )+
+ {
+ type Item = ($( $T::Item, )+);
+
+ fn drive_unindexed<CONSUMER>(self, consumer: CONSUMER) -> CONSUMER::Result
+ where
+ CONSUMER: UnindexedConsumer<Self::Item>,
+ {
+ self.drive(consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+ }
+
+ impl<$( $T, )+> IndexedParallelIterator for MultiZip<($( $T, )+)>
+ where
+ $( $T: IndexedParallelIterator, )+
+ {
+ fn drive<CONSUMER>(self, consumer: CONSUMER) -> CONSUMER::Result
+ where
+ CONSUMER: Consumer<Self::Item>,
+ {
+ reduce!($( self.tuple.$idx ),+ => IndexedParallelIterator::zip)
+ .map(flatten!($( $T ),+))
+ .drive(consumer)
+ }
+
+ fn len(&self) -> usize {
+ reduce!($( self.tuple.$idx.len() ),+ => Ord::min)
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ reduce!($( self.tuple.$idx ),+ => IndexedParallelIterator::zip)
+ .map(flatten!($( $T ),+))
+ .with_producer(callback)
+ }
+ }
+ )+
+ }
+}
+
+multizip_impls! {
+ Tuple1 {
+ (0) -> A
+ }
+ Tuple2 {
+ (0) -> A
+ (1) -> B
+ }
+ Tuple3 {
+ (0) -> A
+ (1) -> B
+ (2) -> C
+ }
+ Tuple4 {
+ (0) -> A
+ (1) -> B
+ (2) -> C
+ (3) -> D
+ }
+ Tuple5 {
+ (0) -> A
+ (1) -> B
+ (2) -> C
+ (3) -> D
+ (4) -> E
+ }
+ Tuple6 {
+ (0) -> A
+ (1) -> B
+ (2) -> C
+ (3) -> D
+ (4) -> E
+ (5) -> F
+ }
+ Tuple7 {
+ (0) -> A
+ (1) -> B
+ (2) -> C
+ (3) -> D
+ (4) -> E
+ (5) -> F
+ (6) -> G
+ }
+ Tuple8 {
+ (0) -> A
+ (1) -> B
+ (2) -> C
+ (3) -> D
+ (4) -> E
+ (5) -> F
+ (6) -> G
+ (7) -> H
+ }
+ Tuple9 {
+ (0) -> A
+ (1) -> B
+ (2) -> C
+ (3) -> D
+ (4) -> E
+ (5) -> F
+ (6) -> G
+ (7) -> H
+ (8) -> I
+ }
+ Tuple10 {
+ (0) -> A
+ (1) -> B
+ (2) -> C
+ (3) -> D
+ (4) -> E
+ (5) -> F
+ (6) -> G
+ (7) -> H
+ (8) -> I
+ (9) -> J
+ }
+ Tuple11 {
+ (0) -> A
+ (1) -> B
+ (2) -> C
+ (3) -> D
+ (4) -> E
+ (5) -> F
+ (6) -> G
+ (7) -> H
+ (8) -> I
+ (9) -> J
+ (10) -> K
+ }
+ Tuple12 {
+ (0) -> A
+ (1) -> B
+ (2) -> C
+ (3) -> D
+ (4) -> E
+ (5) -> F
+ (6) -> G
+ (7) -> H
+ (8) -> I
+ (9) -> J
+ (10) -> K
+ (11) -> L
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/noop.rs b/third_party/rust/rayon/src/iter/noop.rs
new file mode 100644
index 0000000000..1e55ecb20e
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/noop.rs
@@ -0,0 +1,59 @@
+use super::plumbing::*;
+
+pub(super) struct NoopConsumer;
+
+impl<T> Consumer<T> for NoopConsumer {
+ type Folder = NoopConsumer;
+ type Reducer = NoopReducer;
+ type Result = ();
+
+ fn split_at(self, _index: usize) -> (Self, Self, NoopReducer) {
+ (NoopConsumer, NoopConsumer, NoopReducer)
+ }
+
+ fn into_folder(self) -> Self {
+ self
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl<T> Folder<T> for NoopConsumer {
+ type Result = ();
+
+ fn consume(self, _item: T) -> Self {
+ self
+ }
+
+ fn consume_iter<I>(self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ iter.into_iter().for_each(drop);
+ self
+ }
+
+ fn complete(self) {}
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl<T> UnindexedConsumer<T> for NoopConsumer {
+ fn split_off_left(&self) -> Self {
+ NoopConsumer
+ }
+
+ fn to_reducer(&self) -> NoopReducer {
+ NoopReducer
+ }
+}
+
+pub(super) struct NoopReducer;
+
+impl Reducer<()> for NoopReducer {
+ fn reduce(self, _left: (), _right: ()) {}
+}
diff --git a/third_party/rust/rayon/src/iter/once.rs b/third_party/rust/rayon/src/iter/once.rs
new file mode 100644
index 0000000000..5140b6b9f8
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/once.rs
@@ -0,0 +1,68 @@
+use crate::iter::plumbing::*;
+use crate::iter::*;
+
+/// Creates a parallel iterator that produces an element exactly once.
+///
+/// This admits no parallelism on its own, but it could be chained to existing
+/// parallel iterators to extend their contents, or otherwise used for any code
+/// that deals with generic parallel iterators.
+///
+/// # Examples
+///
+/// ```
+/// use rayon::prelude::*;
+/// use rayon::iter::once;
+///
+/// let pi = (0..1234).into_par_iter()
+/// .chain(once(-1))
+/// .chain(1234..10_000);
+///
+/// assert_eq!(pi.clone().count(), 10_001);
+/// assert_eq!(pi.clone().filter(|&x| x < 0).count(), 1);
+/// assert_eq!(pi.position_any(|x| x < 0), Some(1234));
+/// ```
+pub fn once<T: Send>(item: T) -> Once<T> {
+ Once { item }
+}
+
+/// Iterator adaptor for [the `once()` function](fn.once.html).
+#[derive(Clone, Debug)]
+pub struct Once<T: Send> {
+ item: T,
+}
+
+impl<T: Send> ParallelIterator for Once<T> {
+ type Item = T;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ self.drive(consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(1)
+ }
+}
+
+impl<T: Send> IndexedParallelIterator for Once<T> {
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ consumer.into_folder().consume(self.item).complete()
+ }
+
+ fn len(&self) -> usize {
+ 1
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ // Let `OptionProducer` handle it.
+ Some(self.item).into_par_iter().with_producer(callback)
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/panic_fuse.rs b/third_party/rust/rayon/src/iter/panic_fuse.rs
new file mode 100644
index 0000000000..7487230e57
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/panic_fuse.rs
@@ -0,0 +1,342 @@
+use super::plumbing::*;
+use super::*;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::thread;
+
+/// `PanicFuse` is an adaptor that wraps an iterator with a fuse in case
+/// of panics, to halt all threads as soon as possible.
+///
+/// This struct is created by the [`panic_fuse()`] method on [`ParallelIterator`]
+///
+/// [`panic_fuse()`]: trait.ParallelIterator.html#method.panic_fuse
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct PanicFuse<I: ParallelIterator> {
+ base: I,
+}
+
+/// Helper that sets a bool to `true` if dropped while unwinding.
+#[derive(Clone)]
+struct Fuse<'a>(&'a AtomicBool);
+
+impl<'a> Drop for Fuse<'a> {
+ #[inline]
+ fn drop(&mut self) {
+ if thread::panicking() {
+ self.0.store(true, Ordering::Relaxed);
+ }
+ }
+}
+
+impl<'a> Fuse<'a> {
+ #[inline]
+ fn panicked(&self) -> bool {
+ self.0.load(Ordering::Relaxed)
+ }
+}
+
+impl<I> PanicFuse<I>
+where
+ I: ParallelIterator,
+{
+ /// Creates a new `PanicFuse` iterator.
+ pub(super) fn new(base: I) -> PanicFuse<I> {
+ PanicFuse { base }
+ }
+}
+
+impl<I> ParallelIterator for PanicFuse<I>
+where
+ I: ParallelIterator,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let panicked = AtomicBool::new(false);
+ let consumer1 = PanicFuseConsumer {
+ base: consumer,
+ fuse: Fuse(&panicked),
+ };
+ self.base.drive_unindexed(consumer1)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ self.base.opt_len()
+ }
+}
+
+impl<I> IndexedParallelIterator for PanicFuse<I>
+where
+ I: IndexedParallelIterator,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ let panicked = AtomicBool::new(false);
+ let consumer1 = PanicFuseConsumer {
+ base: consumer,
+ fuse: Fuse(&panicked),
+ };
+ self.base.drive(consumer1)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback { callback });
+
+ struct Callback<CB> {
+ callback: CB,
+ }
+
+ impl<T, CB> ProducerCallback<T> for Callback<CB>
+ where
+ CB: ProducerCallback<T>,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let panicked = AtomicBool::new(false);
+ let producer = PanicFuseProducer {
+ base,
+ fuse: Fuse(&panicked),
+ };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Producer implementation
+
+struct PanicFuseProducer<'a, P> {
+ base: P,
+ fuse: Fuse<'a>,
+}
+
+impl<'a, P> Producer for PanicFuseProducer<'a, P>
+where
+ P: Producer,
+{
+ type Item = P::Item;
+ type IntoIter = PanicFuseIter<'a, P::IntoIter>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ PanicFuseIter {
+ base: self.base.into_iter(),
+ fuse: self.fuse,
+ }
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(index);
+ (
+ PanicFuseProducer {
+ base: left,
+ fuse: self.fuse.clone(),
+ },
+ PanicFuseProducer {
+ base: right,
+ fuse: self.fuse,
+ },
+ )
+ }
+
+ fn fold_with<G>(self, folder: G) -> G
+ where
+ G: Folder<Self::Item>,
+ {
+ let folder1 = PanicFuseFolder {
+ base: folder,
+ fuse: self.fuse,
+ };
+ self.base.fold_with(folder1).base
+ }
+}
+
+struct PanicFuseIter<'a, I> {
+ base: I,
+ fuse: Fuse<'a>,
+}
+
+impl<'a, I> Iterator for PanicFuseIter<'a, I>
+where
+ I: Iterator,
+{
+ type Item = I::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.fuse.panicked() {
+ None
+ } else {
+ self.base.next()
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.base.size_hint()
+ }
+}
+
+impl<'a, I> DoubleEndedIterator for PanicFuseIter<'a, I>
+where
+ I: DoubleEndedIterator,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ if self.fuse.panicked() {
+ None
+ } else {
+ self.base.next_back()
+ }
+ }
+}
+
+impl<'a, I> ExactSizeIterator for PanicFuseIter<'a, I>
+where
+ I: ExactSizeIterator,
+{
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct PanicFuseConsumer<'a, C> {
+ base: C,
+ fuse: Fuse<'a>,
+}
+
+impl<'a, T, C> Consumer<T> for PanicFuseConsumer<'a, C>
+where
+ C: Consumer<T>,
+{
+ type Folder = PanicFuseFolder<'a, C::Folder>;
+ type Reducer = PanicFuseReducer<'a, C::Reducer>;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ PanicFuseConsumer {
+ base: left,
+ fuse: self.fuse.clone(),
+ },
+ PanicFuseConsumer {
+ base: right,
+ fuse: self.fuse.clone(),
+ },
+ PanicFuseReducer {
+ base: reducer,
+ _fuse: self.fuse,
+ },
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ PanicFuseFolder {
+ base: self.base.into_folder(),
+ fuse: self.fuse,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.fuse.panicked() || self.base.full()
+ }
+}
+
+impl<'a, T, C> UnindexedConsumer<T> for PanicFuseConsumer<'a, C>
+where
+ C: UnindexedConsumer<T>,
+{
+ fn split_off_left(&self) -> Self {
+ PanicFuseConsumer {
+ base: self.base.split_off_left(),
+ fuse: self.fuse.clone(),
+ }
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ PanicFuseReducer {
+ base: self.base.to_reducer(),
+ _fuse: self.fuse.clone(),
+ }
+ }
+}
+
+struct PanicFuseFolder<'a, C> {
+ base: C,
+ fuse: Fuse<'a>,
+}
+
+impl<'a, T, C> Folder<T> for PanicFuseFolder<'a, C>
+where
+ C: Folder<T>,
+{
+ type Result = C::Result;
+
+ fn consume(mut self, item: T) -> Self {
+ self.base = self.base.consume(item);
+ self
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ fn cool<'a, T>(fuse: &'a Fuse<'_>) -> impl Fn(&T) -> bool + 'a {
+ move |_| !fuse.panicked()
+ }
+
+ self.base = {
+ let fuse = &self.fuse;
+ let iter = iter.into_iter().take_while(cool(fuse));
+ self.base.consume_iter(iter)
+ };
+ self
+ }
+
+ fn complete(self) -> C::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.fuse.panicked() || self.base.full()
+ }
+}
+
+struct PanicFuseReducer<'a, C> {
+ base: C,
+ _fuse: Fuse<'a>,
+}
+
+impl<'a, T, C> Reducer<T> for PanicFuseReducer<'a, C>
+where
+ C: Reducer<T>,
+{
+ fn reduce(self, left: T, right: T) -> T {
+ self.base.reduce(left, right)
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/par_bridge.rs b/third_party/rust/rayon/src/iter/par_bridge.rs
new file mode 100644
index 0000000000..8398274b35
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/par_bridge.rs
@@ -0,0 +1,162 @@
+use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+use std::sync::Mutex;
+
+use crate::iter::plumbing::{bridge_unindexed, Folder, UnindexedConsumer, UnindexedProducer};
+use crate::iter::ParallelIterator;
+use crate::{current_num_threads, current_thread_index};
+
+/// Conversion trait to convert an `Iterator` to a `ParallelIterator`.
+///
+/// This creates a "bridge" from a sequential iterator to a parallel one, by distributing its items
+/// across the Rayon thread pool. This has the advantage of being able to parallelize just about
+/// anything, but the resulting `ParallelIterator` can be less efficient than if you started with
+/// `par_iter` instead. However, it can still be useful for iterators that are difficult to
+/// parallelize by other means, like channels or file or network I/O.
+///
+/// The resulting iterator is not guaranteed to keep the order of the original iterator.
+///
+/// # Examples
+///
+/// To use this trait, take an existing `Iterator` and call `par_bridge` on it. After that, you can
+/// use any of the `ParallelIterator` methods:
+///
+/// ```
+/// use rayon::iter::ParallelBridge;
+/// use rayon::prelude::ParallelIterator;
+/// use std::sync::mpsc::channel;
+///
+/// let rx = {
+/// let (tx, rx) = channel();
+///
+/// tx.send("one!");
+/// tx.send("two!");
+/// tx.send("three!");
+///
+/// rx
+/// };
+///
+/// let mut output: Vec<&'static str> = rx.into_iter().par_bridge().collect();
+/// output.sort_unstable();
+///
+/// assert_eq!(&*output, &["one!", "three!", "two!"]);
+/// ```
+pub trait ParallelBridge: Sized {
+ /// Creates a bridge from this type to a `ParallelIterator`.
+ fn par_bridge(self) -> IterBridge<Self>;
+}
+
+impl<T: Iterator + Send> ParallelBridge for T
+where
+ T::Item: Send,
+{
+ fn par_bridge(self) -> IterBridge<Self> {
+ IterBridge { iter: self }
+ }
+}
+
+/// `IterBridge` is a parallel iterator that wraps a sequential iterator.
+///
+/// This type is created when using the `par_bridge` method on `ParallelBridge`. See the
+/// [`ParallelBridge`] documentation for details.
+///
+/// [`ParallelBridge`]: trait.ParallelBridge.html
+#[derive(Debug, Clone)]
+pub struct IterBridge<Iter> {
+ iter: Iter,
+}
+
+impl<Iter: Iterator + Send> ParallelIterator for IterBridge<Iter>
+where
+ Iter::Item: Send,
+{
+ type Item = Iter::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let num_threads = current_num_threads();
+ let threads_started: Vec<_> = (0..num_threads).map(|_| AtomicBool::new(false)).collect();
+
+ bridge_unindexed(
+ &IterParallelProducer {
+ split_count: AtomicUsize::new(num_threads),
+ iter: Mutex::new(self.iter.fuse()),
+ threads_started: &threads_started,
+ },
+ consumer,
+ )
+ }
+}
+
+struct IterParallelProducer<'a, Iter> {
+ split_count: AtomicUsize,
+ iter: Mutex<std::iter::Fuse<Iter>>,
+ threads_started: &'a [AtomicBool],
+}
+
+impl<Iter: Iterator + Send> UnindexedProducer for &IterParallelProducer<'_, Iter> {
+ type Item = Iter::Item;
+
+ fn split(self) -> (Self, Option<Self>) {
+ let mut count = self.split_count.load(Ordering::SeqCst);
+
+ loop {
+ // Check if the iterator is exhausted
+ if let Some(new_count) = count.checked_sub(1) {
+ match self.split_count.compare_exchange_weak(
+ count,
+ new_count,
+ Ordering::SeqCst,
+ Ordering::SeqCst,
+ ) {
+ Ok(_) => return (self, Some(self)),
+ Err(last_count) => count = last_count,
+ }
+ } else {
+ return (self, None);
+ }
+ }
+ }
+
+ fn fold_with<F>(self, mut folder: F) -> F
+ where
+ F: Folder<Self::Item>,
+ {
+ // Guard against work-stealing-induced recursion, in case `Iter::next()`
+ // calls rayon internally, so we don't deadlock our mutex. We might also
+ // be recursing via `folder` methods, which doesn't present a mutex hazard,
+ // but it's lower overhead for us to just check this once, rather than
+ // updating additional shared state on every mutex lock/unlock.
+ // (If this isn't a rayon thread, then there's no work-stealing anyway...)
+ if let Some(i) = current_thread_index() {
+ // Note: If the number of threads in the pool ever grows dynamically, then
+ // we'll end up sharing flags and may falsely detect recursion -- that's
+ // still fine for overall correctness, just not optimal for parallelism.
+ let thread_started = &self.threads_started[i % self.threads_started.len()];
+ if thread_started.swap(true, Ordering::Relaxed) {
+ // We can't make progress with a nested mutex, so just return and let
+ // the outermost loop continue with the rest of the iterator items.
+ return folder;
+ }
+ }
+
+ loop {
+ if let Ok(mut iter) = self.iter.lock() {
+ if let Some(it) = iter.next() {
+ drop(iter);
+ folder = folder.consume(it);
+ if folder.full() {
+ return folder;
+ }
+ } else {
+ return folder;
+ }
+ } else {
+ // any panics from other threads will have been caught by the pool,
+ // and will be re-thrown when joined - just exit
+ return folder;
+ }
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/plumbing/README.md b/third_party/rust/rayon/src/iter/plumbing/README.md
new file mode 100644
index 0000000000..dbee36ba00
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/plumbing/README.md
@@ -0,0 +1,315 @@
+# Parallel Iterators
+
+These are some notes on the design of the parallel iterator traits.
+This file does not describe how to **use** parallel iterators.
+
+## The challenge
+
+Parallel iterators are more complicated than sequential iterators.
+The reason is that they have to be able to split themselves up and
+operate in parallel across the two halves.
+
+The current design for parallel iterators has two distinct modes in
+which they can be used; as we will see, not all iterators support both
+modes (which is why there are two):
+
+- **Pull mode** (the `Producer` and `UnindexedProducer` traits): in this mode,
+ the iterator is asked to produce the next item using a call to `next`. This
+ is basically like a normal iterator, but with a twist: you can split the
+ iterator in half to produce disjoint items in separate threads.
+ - in the `Producer` trait, splitting is done with `split_at`, which accepts
+ an index where the split should be performed. Only indexed iterators can
+ work in this mode, as they know exactly how much data they will produce,
+ and how to locate the requested index.
+ - in the `UnindexedProducer` trait, splitting is done with `split`, which
+ simply requests that the producer divide itself *approximately* in half.
+ This is useful when the exact length and/or layout is unknown, as with
+ `String` characters, or when the length might exceed `usize`, as with
+ `Range<u64>` on 32-bit platforms.
+ - In theory, any `Producer` could act unindexed, but we don't currently
+ use that possibility. When you know the exact length, a `split` can
+ simply be implemented as `split_at(length/2)`.
+- **Push mode** (the `Consumer` and `UnindexedConsumer` traits): in
+ this mode, the iterator instead is *given* each item in turn, which
+ is then processed. This is the opposite of a normal iterator. It's
+ more like a `for_each` call: each time a new item is produced, the
+ `consume` method is called with that item. (The traits themselves are
+ a bit more complex, as they support state that can be threaded
+ through and ultimately reduced.) Unlike producers, there are two
+ variants of consumers. The difference is how the split is performed:
+ - in the `Consumer` trait, splitting is done with `split_at`, which
+ accepts an index where the split should be performed. All
+ iterators can work in this mode. The resulting halves thus have an
+ idea about how much data they expect to consume.
+ - in the `UnindexedConsumer` trait, splitting is done with
+ `split_off_left`. There is no index: the resulting halves must be
+ prepared to process any amount of data, and they don't know where that
+ data falls in the overall stream.
+ - Not all consumers can operate in this mode. It works for
+ `for_each` and `reduce`, for example, but it does not work for
+ `collect_into_vec`, since in that case the position of each item is
+ important for knowing where it ends up in the target collection.
+
+## How iterator execution proceeds
+
+We'll walk through this example iterator chain to start. This chain
+demonstrates more-or-less the full complexity of what can happen.
+
+```rust
+vec1.par_iter()
+ .zip(vec2.par_iter())
+ .flat_map(some_function)
+ .for_each(some_other_function)
+```
+
+To handle an iterator chain, we start by creating consumers. This
+works from the end. So in this case, the call to `for_each` is the
+final step, so it will create a `ForEachConsumer` that, given an item,
+just calls `some_other_function` with that item. (`ForEachConsumer` is
+a very simple consumer because it doesn't need to thread any state
+between items at all.)
+
+Now, the `for_each` call will pass this consumer to the base iterator,
+which is the `flat_map`. It will do this by calling the `drive_unindexed`
+method on the `ParallelIterator` trait. `drive_unindexed` basically
+says "produce items for this iterator and feed them to this consumer";
+it only works for unindexed consumers.
+
+(As an aside, it is interesting that only some consumers can work in
+unindexed mode, but all producers can *drive* an unindexed consumer.
+In contrast, only some producers can drive an *indexed* consumer, but
+all consumers can be supplied indexes. Isn't variance neat.)
+
+As it happens, `FlatMap` only works with unindexed consumers anyway.
+This is because flat-map basically has no idea how many items it will
+produce. If you ask flat-map to produce the 22nd item, it can't do it,
+at least not without some intermediate state. It doesn't know whether
+processing the first item will create 1 item, 3 items, or 100;
+therefore, to produce an arbitrary item, it would basically just have
+to start at the beginning and execute sequentially, which is not what
+we want. But for unindexed consumers, this doesn't matter, since they
+don't need to know how much data they will get.
+
+Therefore, `FlatMap` can wrap the `ForEachConsumer` with a
+`FlatMapConsumer` that feeds to it. This `FlatMapConsumer` will be
+given one item. It will then invoke `some_function` to get a parallel
+iterator out. It will then ask this new parallel iterator to drive the
+`ForEachConsumer`. The `drive_unindexed` method on `flat_map` can then
+pass the `FlatMapConsumer` up the chain to the previous item, which is
+`zip`. At this point, something interesting happens.
+
+## Switching from push to pull mode
+
+If you think about `zip`, it can't really be implemented as a
+consumer, at least not without an intermediate thread and some
+channels or something (or maybe coroutines). The problem is that it
+has to walk two iterators *in lockstep*. Basically, it can't call two
+`drive` methods simultaneously, it can only call one at a time. So at
+this point, the `zip` iterator needs to switch from *push mode* into
+*pull mode*.
+
+You'll note that `Zip` is only usable if its inputs implement
+`IndexedParallelIterator`, meaning that they can produce data starting
+at random points in the stream. This need to switch to push mode is
+exactly why. If we want to split a zip iterator at position 22, we
+need to be able to start zipping items from index 22 right away,
+without having to start from index 0.
+
+Anyway, so at this point, the `drive_unindexed` method for `Zip` stops
+creating consumers. Instead, it creates a *producer*, a `ZipProducer`,
+to be exact, and calls the `bridge` function in the `internals`
+module. Creating a `ZipProducer` will in turn create producers for
+the two iterators being zipped. This is possible because they both
+implement `IndexedParallelIterator`.
+
+The `bridge` function will then connect the consumer, which is
+handling the `flat_map` and `for_each`, with the producer, which is
+handling the `zip` and its predecessors. It will split down until the
+chunks seem reasonably small, then pull items from the producer and
+feed them to the consumer.
+
+## The base case
+
+The other time that `bridge` gets used is when we bottom out in an
+indexed producer, such as a slice or range. There is also a
+`bridge_unindexed` equivalent for - you guessed it - unindexed producers,
+such as string characters.
+
+<a name="producer-callback">
+
+## What on earth is `ProducerCallback`?
+
+We saw that when you call a parallel action method like
+`par_iter.reduce()`, that will create a "reducing" consumer and then
+invoke `par_iter.drive_unindexed()` (or `par_iter.drive()`) as
+appropriate. This may create yet more consumers as we proceed up the
+parallel iterator chain. But at some point we're going to get to the
+start of the chain, or to a parallel iterator (like `zip()`) that has
+to coordinate multiple inputs. At that point, we need to start
+converting parallel iterators into producers.
+
+The way we do this is by invoking the method `with_producer()`, defined on
+`IndexedParallelIterator`. This is a callback scheme. In an ideal world,
+it would work like this:
+
+```rust
+base_iter.with_producer(|base_producer| {
+ // here, `base_producer` is the producer for `base_iter`
+});
+```
+
+In that case, we could implement a combinator like `map()` by getting
+the producer for the base iterator, wrapping it to make our own
+`MapProducer`, and then passing that to the callback. Something like
+this:
+
+```rust
+struct MapProducer<'f, P, F: 'f> {
+ base: P,
+ map_op: &'f F,
+}
+
+impl<I, F> IndexedParallelIterator for Map<I, F>
+ where I: IndexedParallelIterator,
+ F: MapOp<I::Item>,
+{
+ fn with_producer<CB>(self, callback: CB) -> CB::Output {
+ let map_op = &self.map_op;
+ self.base_iter.with_producer(|base_producer| {
+ // Here `producer` is the producer for `self.base_iter`.
+ // Wrap that to make a `MapProducer`
+ let map_producer = MapProducer {
+ base: base_producer,
+ map_op: map_op
+ };
+
+ // invoke the callback with the wrapped version
+ callback(map_producer)
+ });
+ }
+});
+```
+
+This example demonstrates some of the power of the callback scheme.
+It winds up being a very flexible setup. For one thing, it means we
+can take ownership of `par_iter`; we can then in turn give ownership
+away of its bits and pieces into the producer (this is very useful if
+the iterator owns an `&mut` slice, for example), or create shared
+references and put *those* in the producer. In the case of map, for
+example, the parallel iterator owns the `map_op`, and we borrow
+references to it which we then put into the `MapProducer` (this means
+the `MapProducer` can easily split itself and share those references).
+The `with_producer` method can also create resources that are needed
+during the parallel execution, since the producer does not have to be
+returned.
+
+Unfortunately there is a catch. We can't actually use closures the way
+I showed you. To see why, think about the type that `map_producer`
+would have to have. If we were going to write the `with_producer`
+method using a closure, it would have to look something like this:
+
+```rust
+pub trait IndexedParallelIterator: ParallelIterator {
+ type Producer;
+ fn with_producer<CB, R>(self, callback: CB) -> R
+ where CB: FnOnce(Self::Producer) -> R;
+ ...
+}
+```
+
+Note that we had to add this associated type `Producer` so that
+we could specify the argument of the callback to be `Self::Producer`.
+Now, imagine trying to write that `MapProducer` impl using this style:
+
+```rust
+impl<I, F> IndexedParallelIterator for Map<I, F>
+ where I: IndexedParallelIterator,
+ F: MapOp<I::Item>,
+{
+ type MapProducer = MapProducer<'f, P::Producer, F>;
+ // ^^ wait, what is this `'f`?
+
+ fn with_producer<CB, R>(self, callback: CB) -> R
+ where CB: FnOnce(Self::Producer) -> R
+ {
+ let map_op = &self.map_op;
+ // ^^^^^^ `'f` is (conceptually) the lifetime of this reference,
+ // so it will be different for each call to `with_producer`!
+ }
+}
+```
+
+This may look familiar to you: it's the same problem that we have
+trying to define an `Iterable` trait. Basically, the producer type
+needs to include a lifetime (here, `'f`) that refers to the body of
+`with_producer` and hence is not in scope at the impl level.
+
+If we had [associated type constructors][1598], we could solve this
+problem that way. But there is another solution. We can use a
+dedicated callback trait like `ProducerCallback`, instead of `FnOnce`:
+
+[1598]: https://github.com/rust-lang/rfcs/pull/1598
+
+```rust
+pub trait ProducerCallback<T> {
+ type Output;
+ fn callback<P>(self, producer: P) -> Self::Output
+ where P: Producer<Item=T>;
+}
+```
+
+Using this trait, the signature of `with_producer()` looks like this:
+
+```rust
+fn with_producer<CB: ProducerCallback<Self::Item>>(self, callback: CB) -> CB::Output;
+```
+
+Notice that this signature **never has to name the producer type** --
+there is no associated type `Producer` anymore. This is because the
+`callback()` method is generically over **all** producers `P`.
+
+The problem is that now the `||` sugar doesn't work anymore. So we
+have to manually create the callback struct, which is a mite tedious.
+So our `MapProducer` code looks like this:
+
+```rust
+impl<I, F> IndexedParallelIterator for Map<I, F>
+ where I: IndexedParallelIterator,
+ F: MapOp<I::Item>,
+{
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where CB: ProducerCallback<Self::Item>
+ {
+ return self.base.with_producer(Callback { callback: callback, map_op: self.map_op });
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // Manual version of the closure sugar: create an instance
+ // of a struct that implements `ProducerCallback`.
+
+ // The struct declaration. Each field is something that need to capture from the
+ // creating scope.
+ struct Callback<CB, F> {
+ callback: CB,
+ map_op: F,
+ }
+
+ // Implement the `ProducerCallback` trait. This is pure boilerplate.
+ impl<T, F, CB> ProducerCallback<T> for Callback<CB, F>
+ where F: MapOp<T>,
+ CB: ProducerCallback<F::Output>
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where P: Producer<Item=T>
+ {
+ // The body of the closure is here:
+ let producer = MapProducer { base: base,
+ map_op: &self.map_op };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+```
+
+OK, a bit tedious, but it works!
diff --git a/third_party/rust/rayon/src/iter/plumbing/mod.rs b/third_party/rust/rayon/src/iter/plumbing/mod.rs
new file mode 100644
index 0000000000..71d4fb4c3d
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/plumbing/mod.rs
@@ -0,0 +1,484 @@
+//! Traits and functions used to implement parallel iteration. These are
+//! low-level details -- users of parallel iterators should not need to
+//! interact with them directly. See [the `plumbing` README][r] for a general overview.
+//!
+//! [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
+
+use crate::join_context;
+
+use super::IndexedParallelIterator;
+
+use std::cmp;
+use std::usize;
+
+/// The `ProducerCallback` trait is a kind of generic closure,
+/// [analogous to `FnOnce`][FnOnce]. See [the corresponding section in
+/// the plumbing README][r] for more details.
+///
+/// [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md#producer-callback
+/// [FnOnce]: https://doc.rust-lang.org/std/ops/trait.FnOnce.html
+pub trait ProducerCallback<T> {
+ /// The type of value returned by this callback. Analogous to
+ /// [`Output` from the `FnOnce` trait][Output].
+ ///
+ /// [Output]: https://doc.rust-lang.org/std/ops/trait.FnOnce.html#associatedtype.Output
+ type Output;
+
+ /// Invokes the callback with the given producer as argument. The
+ /// key point of this trait is that this method is generic over
+ /// `P`, and hence implementors must be defined for any producer.
+ fn callback<P>(self, producer: P) -> Self::Output
+ where
+ P: Producer<Item = T>;
+}
+
+/// A `Producer` is effectively a "splittable `IntoIterator`". That
+/// is, a producer is a value which can be converted into an iterator
+/// at any time: at that point, it simply produces items on demand,
+/// like any iterator. But what makes a `Producer` special is that,
+/// *before* we convert to an iterator, we can also **split** it at a
+/// particular point using the `split_at` method. This will yield up
+/// two producers, one producing the items before that point, and one
+/// producing the items after that point (these two producers can then
+/// independently be split further, or be converted into iterators).
+/// In Rayon, this splitting is used to divide between threads.
+/// See [the `plumbing` README][r] for further details.
+///
+/// Note that each producer will always produce a fixed number of
+/// items N. However, this number N is not queryable through the API;
+/// the consumer is expected to track it.
+///
+/// NB. You might expect `Producer` to extend the `IntoIterator`
+/// trait. However, [rust-lang/rust#20671][20671] prevents us from
+/// declaring the DoubleEndedIterator and ExactSizeIterator
+/// constraints on a required IntoIterator trait, so we inline
+/// IntoIterator here until that issue is fixed.
+///
+/// [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
+/// [20671]: https://github.com/rust-lang/rust/issues/20671
+pub trait Producer: Send + Sized {
+ /// The type of item that will be produced by this producer once
+ /// it is converted into an iterator.
+ type Item;
+
+ /// The type of iterator we will become.
+ type IntoIter: Iterator<Item = Self::Item> + DoubleEndedIterator + ExactSizeIterator;
+
+ /// Convert `self` into an iterator; at this point, no more parallel splits
+ /// are possible.
+ fn into_iter(self) -> Self::IntoIter;
+
+ /// The minimum number of items that we will process
+ /// sequentially. Defaults to 1, which means that we will split
+ /// all the way down to a single item. This can be raised higher
+ /// using the [`with_min_len`] method, which will force us to
+ /// create sequential tasks at a larger granularity. Note that
+ /// Rayon automatically normally attempts to adjust the size of
+ /// parallel splits to reduce overhead, so this should not be
+ /// needed.
+ ///
+ /// [`with_min_len`]: ../trait.IndexedParallelIterator.html#method.with_min_len
+ fn min_len(&self) -> usize {
+ 1
+ }
+
+ /// The maximum number of items that we will process
+ /// sequentially. Defaults to MAX, which means that we can choose
+ /// not to split at all. This can be lowered using the
+ /// [`with_max_len`] method, which will force us to create more
+ /// parallel tasks. Note that Rayon automatically normally
+ /// attempts to adjust the size of parallel splits to reduce
+ /// overhead, so this should not be needed.
+ ///
+ /// [`with_max_len`]: ../trait.IndexedParallelIterator.html#method.with_max_len
+ fn max_len(&self) -> usize {
+ usize::MAX
+ }
+
+ /// Split into two producers; one produces items `0..index`, the
+ /// other `index..N`. Index must be less than or equal to `N`.
+ fn split_at(self, index: usize) -> (Self, Self);
+
+ /// Iterate the producer, feeding each element to `folder`, and
+ /// stop when the folder is full (or all elements have been consumed).
+ ///
+ /// The provided implementation is sufficient for most iterables.
+ fn fold_with<F>(self, folder: F) -> F
+ where
+ F: Folder<Self::Item>,
+ {
+ folder.consume_iter(self.into_iter())
+ }
+}
+
+/// A consumer is effectively a [generalized "fold" operation][fold],
+/// and in fact each consumer will eventually be converted into a
+/// [`Folder`]. What makes a consumer special is that, like a
+/// [`Producer`], it can be **split** into multiple consumers using
+/// the `split_at` method. When a consumer is split, it produces two
+/// consumers, as well as a **reducer**. The two consumers can be fed
+/// items independently, and when they are done the reducer is used to
+/// combine their two results into one. See [the `plumbing`
+/// README][r] for further details.
+///
+/// [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
+/// [fold]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold
+/// [`Folder`]: trait.Folder.html
+/// [`Producer`]: trait.Producer.html
+pub trait Consumer<Item>: Send + Sized {
+ /// The type of folder that this consumer can be converted into.
+ type Folder: Folder<Item, Result = Self::Result>;
+
+ /// The type of reducer that is produced if this consumer is split.
+ type Reducer: Reducer<Self::Result>;
+
+ /// The type of result that this consumer will ultimately produce.
+ type Result: Send;
+
+ /// Divide the consumer into two consumers, one processing items
+ /// `0..index` and one processing items from `index..`. Also
+ /// produces a reducer that can be used to reduce the results at
+ /// the end.
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer);
+
+ /// Convert the consumer into a folder that can consume items
+ /// sequentially, eventually producing a final result.
+ fn into_folder(self) -> Self::Folder;
+
+ /// Hint whether this `Consumer` would like to stop processing
+ /// further items, e.g. if a search has been completed.
+ fn full(&self) -> bool;
+}
+
+/// The `Folder` trait encapsulates [the standard fold
+/// operation][fold]. It can be fed many items using the `consume`
+/// method. At the end, once all items have been consumed, it can then
+/// be converted (using `complete`) into a final value.
+///
+/// [fold]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold
+pub trait Folder<Item>: Sized {
+ /// The type of result that will ultimately be produced by the folder.
+ type Result;
+
+ /// Consume next item and return new sequential state.
+ fn consume(self, item: Item) -> Self;
+
+ /// Consume items from the iterator until full, and return new sequential state.
+ ///
+ /// This method is **optional**. The default simply iterates over
+ /// `iter`, invoking `consume` and checking after each iteration
+ /// whether `full` returns false.
+ ///
+ /// The main reason to override it is if you can provide a more
+ /// specialized, efficient implementation.
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = Item>,
+ {
+ for item in iter {
+ self = self.consume(item);
+ if self.full() {
+ break;
+ }
+ }
+ self
+ }
+
+ /// Finish consuming items, produce final result.
+ fn complete(self) -> Self::Result;
+
+ /// Hint whether this `Folder` would like to stop processing
+ /// further items, e.g. if a search has been completed.
+ fn full(&self) -> bool;
+}
+
+/// The reducer is the final step of a `Consumer` -- after a consumer
+/// has been split into two parts, and each of those parts has been
+/// fully processed, we are left with two results. The reducer is then
+/// used to combine those two results into one. See [the `plumbing`
+/// README][r] for further details.
+///
+/// [r]: https://github.com/rayon-rs/rayon/blob/master/src/iter/plumbing/README.md
+pub trait Reducer<Result> {
+ /// Reduce two final results into one; this is executed after a
+ /// split.
+ fn reduce(self, left: Result, right: Result) -> Result;
+}
+
+/// A stateless consumer can be freely copied. These consumers can be
+/// used like regular consumers, but they also support a
+/// `split_off_left` method that does not take an index to split, but
+/// simply splits at some arbitrary point (`for_each`, for example,
+/// produces an unindexed consumer).
+pub trait UnindexedConsumer<I>: Consumer<I> {
+ /// Splits off a "left" consumer and returns it. The `self`
+ /// consumer should then be used to consume the "right" portion of
+ /// the data. (The ordering matters for methods like find_first --
+ /// values produced by the returned value are given precedence
+ /// over values produced by `self`.) Once the left and right
+ /// halves have been fully consumed, you should reduce the results
+ /// with the result of `to_reducer`.
+ fn split_off_left(&self) -> Self;
+
+ /// Creates a reducer that can be used to combine the results from
+ /// a split consumer.
+ fn to_reducer(&self) -> Self::Reducer;
+}
+
+/// A variant on `Producer` which does not know its exact length or
+/// cannot represent it in a `usize`. These producers act like
+/// ordinary producers except that they cannot be told to split at a
+/// particular point. Instead, you just ask them to split 'somewhere'.
+///
+/// (In principle, `Producer` could extend this trait; however, it
+/// does not because to do so would require producers to carry their
+/// own length with them.)
+pub trait UnindexedProducer: Send + Sized {
+ /// The type of item returned by this producer.
+ type Item;
+
+ /// Split midway into a new producer if possible, otherwise return `None`.
+ fn split(self) -> (Self, Option<Self>);
+
+ /// Iterate the producer, feeding each element to `folder`, and
+ /// stop when the folder is full (or all elements have been consumed).
+ fn fold_with<F>(self, folder: F) -> F
+ where
+ F: Folder<Self::Item>;
+}
+
+/// A splitter controls the policy for splitting into smaller work items.
+///
+/// Thief-splitting is an adaptive policy that starts by splitting into
+/// enough jobs for every worker thread, and then resets itself whenever a
+/// job is actually stolen into a different thread.
+#[derive(Clone, Copy)]
+struct Splitter {
+ /// The `splits` tell us approximately how many remaining times we'd
+ /// like to split this job. We always just divide it by two though, so
+ /// the effective number of pieces will be `next_power_of_two()`.
+ splits: usize,
+}
+
+impl Splitter {
+ #[inline]
+ fn new() -> Splitter {
+ Splitter {
+ splits: crate::current_num_threads(),
+ }
+ }
+
+ #[inline]
+ fn try_split(&mut self, stolen: bool) -> bool {
+ let Splitter { splits } = *self;
+
+ if stolen {
+ // This job was stolen! Reset the number of desired splits to the
+ // thread count, if that's more than we had remaining anyway.
+ self.splits = cmp::max(crate::current_num_threads(), self.splits / 2);
+ true
+ } else if splits > 0 {
+ // We have splits remaining, make it so.
+ self.splits /= 2;
+ true
+ } else {
+ // Not stolen, and no more splits -- we're done!
+ false
+ }
+ }
+}
+
+/// The length splitter is built on thief-splitting, but additionally takes
+/// into account the remaining length of the iterator.
+#[derive(Clone, Copy)]
+struct LengthSplitter {
+ inner: Splitter,
+
+ /// The smallest we're willing to divide into. Usually this is just 1,
+ /// but you can choose a larger working size with `with_min_len()`.
+ min: usize,
+}
+
+impl LengthSplitter {
+ /// Creates a new splitter based on lengths.
+ ///
+ /// The `min` is a hard lower bound. We'll never split below that, but
+ /// of course an iterator might start out smaller already.
+ ///
+ /// The `max` is an upper bound on the working size, used to determine
+ /// the minimum number of times we need to split to get under that limit.
+ /// The adaptive algorithm may very well split even further, but never
+ /// smaller than the `min`.
+ #[inline]
+ fn new(min: usize, max: usize, len: usize) -> LengthSplitter {
+ let mut splitter = LengthSplitter {
+ inner: Splitter::new(),
+ min: cmp::max(min, 1),
+ };
+
+ // Divide the given length by the max working length to get the minimum
+ // number of splits we need to get under that max. This rounds down,
+ // but the splitter actually gives `next_power_of_two()` pieces anyway.
+ // e.g. len 12345 / max 100 = 123 min_splits -> 128 pieces.
+ let min_splits = len / cmp::max(max, 1);
+
+ // Only update the value if it's not splitting enough already.
+ if min_splits > splitter.inner.splits {
+ splitter.inner.splits = min_splits;
+ }
+
+ splitter
+ }
+
+ #[inline]
+ fn try_split(&mut self, len: usize, stolen: bool) -> bool {
+ // If splitting wouldn't make us too small, try the inner splitter.
+ len / 2 >= self.min && self.inner.try_split(stolen)
+ }
+}
+
+/// This helper function is used to "connect" a parallel iterator to a
+/// consumer. It will convert the `par_iter` into a producer P and
+/// then pull items from P and feed them to `consumer`, splitting and
+/// creating parallel threads as needed.
+///
+/// This is useful when you are implementing your own parallel
+/// iterators: it is often used as the definition of the
+/// [`drive_unindexed`] or [`drive`] methods.
+///
+/// [`drive_unindexed`]: ../trait.ParallelIterator.html#tymethod.drive_unindexed
+/// [`drive`]: ../trait.IndexedParallelIterator.html#tymethod.drive
+pub fn bridge<I, C>(par_iter: I, consumer: C) -> C::Result
+where
+ I: IndexedParallelIterator,
+ C: Consumer<I::Item>,
+{
+ let len = par_iter.len();
+ return par_iter.with_producer(Callback { len, consumer });
+
+ struct Callback<C> {
+ len: usize,
+ consumer: C,
+ }
+
+ impl<C, I> ProducerCallback<I> for Callback<C>
+ where
+ C: Consumer<I>,
+ {
+ type Output = C::Result;
+ fn callback<P>(self, producer: P) -> C::Result
+ where
+ P: Producer<Item = I>,
+ {
+ bridge_producer_consumer(self.len, producer, self.consumer)
+ }
+ }
+}
+
+/// This helper function is used to "connect" a producer and a
+/// consumer. You may prefer to call [`bridge`], which wraps this
+/// function. This function will draw items from `producer` and feed
+/// them to `consumer`, splitting and creating parallel tasks when
+/// needed.
+///
+/// This is useful when you are implementing your own parallel
+/// iterators: it is often used as the definition of the
+/// [`drive_unindexed`] or [`drive`] methods.
+///
+/// [`bridge`]: fn.bridge.html
+/// [`drive_unindexed`]: ../trait.ParallelIterator.html#tymethod.drive_unindexed
+/// [`drive`]: ../trait.IndexedParallelIterator.html#tymethod.drive
+pub fn bridge_producer_consumer<P, C>(len: usize, producer: P, consumer: C) -> C::Result
+where
+ P: Producer,
+ C: Consumer<P::Item>,
+{
+ let splitter = LengthSplitter::new(producer.min_len(), producer.max_len(), len);
+ return helper(len, false, splitter, producer, consumer);
+
+ fn helper<P, C>(
+ len: usize,
+ migrated: bool,
+ mut splitter: LengthSplitter,
+ producer: P,
+ consumer: C,
+ ) -> C::Result
+ where
+ P: Producer,
+ C: Consumer<P::Item>,
+ {
+ if consumer.full() {
+ consumer.into_folder().complete()
+ } else if splitter.try_split(len, migrated) {
+ let mid = len / 2;
+ let (left_producer, right_producer) = producer.split_at(mid);
+ let (left_consumer, right_consumer, reducer) = consumer.split_at(mid);
+ let (left_result, right_result) = join_context(
+ |context| {
+ helper(
+ mid,
+ context.migrated(),
+ splitter,
+ left_producer,
+ left_consumer,
+ )
+ },
+ |context| {
+ helper(
+ len - mid,
+ context.migrated(),
+ splitter,
+ right_producer,
+ right_consumer,
+ )
+ },
+ );
+ reducer.reduce(left_result, right_result)
+ } else {
+ producer.fold_with(consumer.into_folder()).complete()
+ }
+ }
+}
+
+/// A variant of [`bridge_producer_consumer`] where the producer is an unindexed producer.
+///
+/// [`bridge_producer_consumer`]: fn.bridge_producer_consumer.html
+pub fn bridge_unindexed<P, C>(producer: P, consumer: C) -> C::Result
+where
+ P: UnindexedProducer,
+ C: UnindexedConsumer<P::Item>,
+{
+ let splitter = Splitter::new();
+ bridge_unindexed_producer_consumer(false, splitter, producer, consumer)
+}
+
+fn bridge_unindexed_producer_consumer<P, C>(
+ migrated: bool,
+ mut splitter: Splitter,
+ producer: P,
+ consumer: C,
+) -> C::Result
+where
+ P: UnindexedProducer,
+ C: UnindexedConsumer<P::Item>,
+{
+ if consumer.full() {
+ consumer.into_folder().complete()
+ } else if splitter.try_split(migrated) {
+ match producer.split() {
+ (left_producer, Some(right_producer)) => {
+ let (reducer, left_consumer, right_consumer) =
+ (consumer.to_reducer(), consumer.split_off_left(), consumer);
+ let bridge = bridge_unindexed_producer_consumer;
+ let (left_result, right_result) = join_context(
+ |context| bridge(context.migrated(), splitter, left_producer, left_consumer),
+ |context| bridge(context.migrated(), splitter, right_producer, right_consumer),
+ );
+ reducer.reduce(left_result, right_result)
+ }
+ (producer, None) => producer.fold_with(consumer.into_folder()).complete(),
+ }
+ } else {
+ producer.fold_with(consumer.into_folder()).complete()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/positions.rs b/third_party/rust/rayon/src/iter/positions.rs
new file mode 100644
index 0000000000..f584bb28e2
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/positions.rs
@@ -0,0 +1,137 @@
+use super::plumbing::*;
+use super::*;
+
+use std::fmt::{self, Debug};
+
+/// `Positions` takes a predicate `predicate` and filters out elements that match,
+/// yielding their indices.
+///
+/// This struct is created by the [`positions()`] method on [`IndexedParallelIterator`]
+///
+/// [`positions()`]: trait.IndexedParallelIterator.html#method.positions
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct Positions<I: IndexedParallelIterator, P> {
+ base: I,
+ predicate: P,
+}
+
+impl<I: IndexedParallelIterator + Debug, P> Debug for Positions<I, P> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Positions")
+ .field("base", &self.base)
+ .finish()
+ }
+}
+
+impl<I, P> Positions<I, P>
+where
+ I: IndexedParallelIterator,
+{
+ /// Create a new `Positions` iterator.
+ pub(super) fn new(base: I, predicate: P) -> Self {
+ Positions { base, predicate }
+ }
+}
+
+impl<I, P> ParallelIterator for Positions<I, P>
+where
+ I: IndexedParallelIterator,
+ P: Fn(I::Item) -> bool + Sync + Send,
+{
+ type Item = usize;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = PositionsConsumer::new(consumer, &self.predicate, 0);
+ self.base.drive(consumer1)
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct PositionsConsumer<'p, C, P> {
+ base: C,
+ predicate: &'p P,
+ offset: usize,
+}
+
+impl<'p, C, P> PositionsConsumer<'p, C, P> {
+ fn new(base: C, predicate: &'p P, offset: usize) -> Self {
+ PositionsConsumer {
+ base,
+ predicate,
+ offset,
+ }
+ }
+}
+
+impl<'p, T, C, P> Consumer<T> for PositionsConsumer<'p, C, P>
+where
+ C: Consumer<usize>,
+ P: Fn(T) -> bool + Sync,
+{
+ type Folder = PositionsFolder<'p, C::Folder, P>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, C::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ PositionsConsumer::new(left, self.predicate, self.offset),
+ PositionsConsumer::new(right, self.predicate, self.offset + index),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ PositionsFolder {
+ base: self.base.into_folder(),
+ predicate: self.predicate,
+ offset: self.offset,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+struct PositionsFolder<'p, F, P> {
+ base: F,
+ predicate: &'p P,
+ offset: usize,
+}
+
+impl<F, P, T> Folder<T> for PositionsFolder<'_, F, P>
+where
+ F: Folder<usize>,
+ P: Fn(T) -> bool,
+{
+ type Result = F::Result;
+
+ fn consume(mut self, item: T) -> Self {
+ let index = self.offset;
+ self.offset += 1;
+ if (self.predicate)(item) {
+ self.base = self.base.consume(index);
+ }
+ self
+ }
+
+ // This cannot easily specialize `consume_iter` to be better than
+ // the default, because that requires checking `self.base.full()`
+ // during a call to `self.base.consume_iter()`. (#632)
+
+ fn complete(self) -> Self::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/product.rs b/third_party/rust/rayon/src/iter/product.rs
new file mode 100644
index 0000000000..a3d0727f93
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/product.rs
@@ -0,0 +1,114 @@
+use super::plumbing::*;
+use super::ParallelIterator;
+
+use std::iter::{self, Product};
+use std::marker::PhantomData;
+
+pub(super) fn product<PI, P>(pi: PI) -> P
+where
+ PI: ParallelIterator,
+ P: Send + Product<PI::Item> + Product,
+{
+ pi.drive_unindexed(ProductConsumer::new())
+}
+
+fn mul<T: Product>(left: T, right: T) -> T {
+ iter::once(left).chain(iter::once(right)).product()
+}
+
+struct ProductConsumer<P: Send> {
+ _marker: PhantomData<*const P>,
+}
+
+unsafe impl<P: Send> Send for ProductConsumer<P> {}
+
+impl<P: Send> ProductConsumer<P> {
+ fn new() -> ProductConsumer<P> {
+ ProductConsumer {
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl<P, T> Consumer<T> for ProductConsumer<P>
+where
+ P: Send + Product<T> + Product,
+{
+ type Folder = ProductFolder<P>;
+ type Reducer = Self;
+ type Result = P;
+
+ fn split_at(self, _index: usize) -> (Self, Self, Self) {
+ (
+ ProductConsumer::new(),
+ ProductConsumer::new(),
+ ProductConsumer::new(),
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ ProductFolder {
+ product: iter::empty::<T>().product(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl<P, T> UnindexedConsumer<T> for ProductConsumer<P>
+where
+ P: Send + Product<T> + Product,
+{
+ fn split_off_left(&self) -> Self {
+ ProductConsumer::new()
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ ProductConsumer::new()
+ }
+}
+
+impl<P> Reducer<P> for ProductConsumer<P>
+where
+ P: Send + Product,
+{
+ fn reduce(self, left: P, right: P) -> P {
+ mul(left, right)
+ }
+}
+
+struct ProductFolder<P> {
+ product: P,
+}
+
+impl<P, T> Folder<T> for ProductFolder<P>
+where
+ P: Product<T> + Product,
+{
+ type Result = P;
+
+ fn consume(self, item: T) -> Self {
+ ProductFolder {
+ product: mul(self.product, iter::once(item).product()),
+ }
+ }
+
+ fn consume_iter<I>(self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ ProductFolder {
+ product: mul(self.product, iter.into_iter().product()),
+ }
+ }
+
+ fn complete(self) -> P {
+ self.product
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/reduce.rs b/third_party/rust/rayon/src/iter/reduce.rs
new file mode 100644
index 0000000000..321b5dd864
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/reduce.rs
@@ -0,0 +1,116 @@
+use super::plumbing::*;
+use super::ParallelIterator;
+
+pub(super) fn reduce<PI, R, ID, T>(pi: PI, identity: ID, reduce_op: R) -> T
+where
+ PI: ParallelIterator<Item = T>,
+ R: Fn(T, T) -> T + Sync,
+ ID: Fn() -> T + Sync,
+ T: Send,
+{
+ let consumer = ReduceConsumer {
+ identity: &identity,
+ reduce_op: &reduce_op,
+ };
+ pi.drive_unindexed(consumer)
+}
+
+struct ReduceConsumer<'r, R, ID> {
+ identity: &'r ID,
+ reduce_op: &'r R,
+}
+
+impl<'r, R, ID> Copy for ReduceConsumer<'r, R, ID> {}
+
+impl<'r, R, ID> Clone for ReduceConsumer<'r, R, ID> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<'r, R, ID, T> Consumer<T> for ReduceConsumer<'r, R, ID>
+where
+ R: Fn(T, T) -> T + Sync,
+ ID: Fn() -> T + Sync,
+ T: Send,
+{
+ type Folder = ReduceFolder<'r, R, T>;
+ type Reducer = Self;
+ type Result = T;
+
+ fn split_at(self, _index: usize) -> (Self, Self, Self) {
+ (self, self, self)
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ ReduceFolder {
+ reduce_op: self.reduce_op,
+ item: (self.identity)(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl<'r, R, ID, T> UnindexedConsumer<T> for ReduceConsumer<'r, R, ID>
+where
+ R: Fn(T, T) -> T + Sync,
+ ID: Fn() -> T + Sync,
+ T: Send,
+{
+ fn split_off_left(&self) -> Self {
+ *self
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ *self
+ }
+}
+
+impl<'r, R, ID, T> Reducer<T> for ReduceConsumer<'r, R, ID>
+where
+ R: Fn(T, T) -> T + Sync,
+{
+ fn reduce(self, left: T, right: T) -> T {
+ (self.reduce_op)(left, right)
+ }
+}
+
+struct ReduceFolder<'r, R, T> {
+ reduce_op: &'r R,
+ item: T,
+}
+
+impl<'r, R, T> Folder<T> for ReduceFolder<'r, R, T>
+where
+ R: Fn(T, T) -> T,
+{
+ type Result = T;
+
+ fn consume(self, item: T) -> Self {
+ ReduceFolder {
+ reduce_op: self.reduce_op,
+ item: (self.reduce_op)(self.item, item),
+ }
+ }
+
+ fn consume_iter<I>(self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ ReduceFolder {
+ reduce_op: self.reduce_op,
+ item: iter.into_iter().fold(self.item, self.reduce_op),
+ }
+ }
+
+ fn complete(self) -> T {
+ self.item
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/repeat.rs b/third_party/rust/rayon/src/iter/repeat.rs
new file mode 100644
index 0000000000..f84a6fe779
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/repeat.rs
@@ -0,0 +1,241 @@
+use super::plumbing::*;
+use super::*;
+use std::iter;
+use std::usize;
+
+/// Iterator adaptor for [the `repeat()` function](fn.repeat.html).
+#[derive(Debug, Clone)]
+pub struct Repeat<T: Clone + Send> {
+ element: T,
+}
+
+/// Creates a parallel iterator that endlessly repeats `elt` (by
+/// cloning it). Note that this iterator has "infinite" length, so
+/// typically you would want to use `zip` or `take` or some other
+/// means to shorten it, or consider using
+/// [the `repeatn()` function](fn.repeatn.html) instead.
+///
+/// # Examples
+///
+/// ```
+/// use rayon::prelude::*;
+/// use rayon::iter::repeat;
+/// let x: Vec<(i32, i32)> = repeat(22).zip(0..3).collect();
+/// assert_eq!(x, vec![(22, 0), (22, 1), (22, 2)]);
+/// ```
+pub fn repeat<T: Clone + Send>(elt: T) -> Repeat<T> {
+ Repeat { element: elt }
+}
+
+impl<T> Repeat<T>
+where
+ T: Clone + Send,
+{
+ /// Takes only `n` repeats of the element, similar to the general
+ /// [`take()`](trait.IndexedParallelIterator.html#method.take).
+ ///
+ /// The resulting `RepeatN` is an `IndexedParallelIterator`, allowing
+ /// more functionality than `Repeat` alone.
+ pub fn take(self, n: usize) -> RepeatN<T> {
+ repeatn(self.element, n)
+ }
+
+ /// Iterates tuples, repeating the element with items from another
+ /// iterator, similar to the general
+ /// [`zip()`](trait.IndexedParallelIterator.html#method.zip).
+ pub fn zip<Z>(self, zip_op: Z) -> Zip<RepeatN<T>, Z::Iter>
+ where
+ Z: IntoParallelIterator,
+ Z::Iter: IndexedParallelIterator,
+ {
+ let z = zip_op.into_par_iter();
+ let n = z.len();
+ self.take(n).zip(z)
+ }
+}
+
+impl<T> ParallelIterator for Repeat<T>
+where
+ T: Clone + Send,
+{
+ type Item = T;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let producer = RepeatProducer {
+ element: self.element,
+ };
+ bridge_unindexed(producer, consumer)
+ }
+}
+
+/// Unindexed producer for `Repeat`.
+struct RepeatProducer<T: Clone + Send> {
+ element: T,
+}
+
+impl<T: Clone + Send> UnindexedProducer for RepeatProducer<T> {
+ type Item = T;
+
+ fn split(self) -> (Self, Option<Self>) {
+ (
+ RepeatProducer {
+ element: self.element.clone(),
+ },
+ Some(RepeatProducer {
+ element: self.element,
+ }),
+ )
+ }
+
+ fn fold_with<F>(self, folder: F) -> F
+ where
+ F: Folder<T>,
+ {
+ folder.consume_iter(iter::repeat(self.element))
+ }
+}
+
+/// Iterator adaptor for [the `repeatn()` function](fn.repeatn.html).
+#[derive(Debug, Clone)]
+pub struct RepeatN<T: Clone + Send> {
+ element: T,
+ count: usize,
+}
+
+/// Creates a parallel iterator that produces `n` repeats of `elt`
+/// (by cloning it).
+///
+/// # Examples
+///
+/// ```
+/// use rayon::prelude::*;
+/// use rayon::iter::repeatn;
+/// let x: Vec<(i32, i32)> = repeatn(22, 3).zip(0..3).collect();
+/// assert_eq!(x, vec![(22, 0), (22, 1), (22, 2)]);
+/// ```
+pub fn repeatn<T: Clone + Send>(elt: T, n: usize) -> RepeatN<T> {
+ RepeatN {
+ element: elt,
+ count: n,
+ }
+}
+
+impl<T> ParallelIterator for RepeatN<T>
+where
+ T: Clone + Send,
+{
+ type Item = T;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.count)
+ }
+}
+
+impl<T> IndexedParallelIterator for RepeatN<T>
+where
+ T: Clone + Send,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ callback.callback(RepeatNProducer {
+ element: self.element,
+ count: self.count,
+ })
+ }
+
+ fn len(&self) -> usize {
+ self.count
+ }
+}
+
+/// Producer for `RepeatN`.
+struct RepeatNProducer<T: Clone + Send> {
+ element: T,
+ count: usize,
+}
+
+impl<T: Clone + Send> Producer for RepeatNProducer<T> {
+ type Item = T;
+ type IntoIter = Iter<T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Iter {
+ element: self.element,
+ count: self.count,
+ }
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ (
+ RepeatNProducer {
+ element: self.element.clone(),
+ count: index,
+ },
+ RepeatNProducer {
+ element: self.element,
+ count: self.count - index,
+ },
+ )
+ }
+}
+
+/// Iterator for `RepeatN`.
+///
+/// This is conceptually like `std::iter::Take<std::iter::Repeat<T>>`, but
+/// we need `DoubleEndedIterator` and unconditional `ExactSizeIterator`.
+struct Iter<T: Clone> {
+ element: T,
+ count: usize,
+}
+
+impl<T: Clone> Iterator for Iter<T> {
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ if self.count > 0 {
+ self.count -= 1;
+ Some(self.element.clone())
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.count, Some(self.count))
+ }
+}
+
+impl<T: Clone> DoubleEndedIterator for Iter<T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<T> {
+ self.next()
+ }
+}
+
+impl<T: Clone> ExactSizeIterator for Iter<T> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.count
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/rev.rs b/third_party/rust/rayon/src/iter/rev.rs
new file mode 100644
index 0000000000..a4c3b7c2e1
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/rev.rs
@@ -0,0 +1,123 @@
+use super::plumbing::*;
+use super::*;
+use std::iter;
+
+/// `Rev` is an iterator that produces elements in reverse order. This struct
+/// is created by the [`rev()`] method on [`IndexedParallelIterator`]
+///
+/// [`rev()`]: trait.IndexedParallelIterator.html#method.rev
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct Rev<I: IndexedParallelIterator> {
+ base: I,
+}
+
+impl<I> Rev<I>
+where
+ I: IndexedParallelIterator,
+{
+ /// Creates a new `Rev` iterator.
+ pub(super) fn new(base: I) -> Self {
+ Rev { base }
+ }
+}
+
+impl<I> ParallelIterator for Rev<I>
+where
+ I: IndexedParallelIterator,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I> IndexedParallelIterator for Rev<I>
+where
+ I: IndexedParallelIterator,
+{
+ fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
+ bridge(self, consumer)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ let len = self.base.len();
+ return self.base.with_producer(Callback { callback, len });
+
+ struct Callback<CB> {
+ callback: CB,
+ len: usize,
+ }
+
+ impl<T, CB> ProducerCallback<T> for Callback<CB>
+ where
+ CB: ProducerCallback<T>,
+ {
+ type Output = CB::Output;
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let producer = RevProducer {
+ base,
+ len: self.len,
+ };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+struct RevProducer<P> {
+ base: P,
+ len: usize,
+}
+
+impl<P> Producer for RevProducer<P>
+where
+ P: Producer,
+{
+ type Item = P::Item;
+ type IntoIter = iter::Rev<P::IntoIter>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.base.into_iter().rev()
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(self.len - index);
+ (
+ RevProducer {
+ base: right,
+ len: index,
+ },
+ RevProducer {
+ base: left,
+ len: self.len - index,
+ },
+ )
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/skip.rs b/third_party/rust/rayon/src/iter/skip.rs
new file mode 100644
index 0000000000..2d0f9477e2
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/skip.rs
@@ -0,0 +1,95 @@
+use super::noop::NoopConsumer;
+use super::plumbing::*;
+use super::*;
+use std::cmp::min;
+
+/// `Skip` is an iterator that skips over the first `n` elements.
+/// This struct is created by the [`skip()`] method on [`IndexedParallelIterator`]
+///
+/// [`skip()`]: trait.IndexedParallelIterator.html#method.skip
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct Skip<I> {
+ base: I,
+ n: usize,
+}
+
+impl<I> Skip<I>
+where
+ I: IndexedParallelIterator,
+{
+ /// Creates a new `Skip` iterator.
+ pub(super) fn new(base: I, n: usize) -> Self {
+ let n = min(base.len(), n);
+ Skip { base, n }
+ }
+}
+
+impl<I> ParallelIterator for Skip<I>
+where
+ I: IndexedParallelIterator,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I> IndexedParallelIterator for Skip<I>
+where
+ I: IndexedParallelIterator,
+{
+ fn len(&self) -> usize {
+ self.base.len() - self.n
+ }
+
+ fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
+ bridge(self, consumer)
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback {
+ callback,
+ n: self.n,
+ });
+
+ struct Callback<CB> {
+ callback: CB,
+ n: usize,
+ }
+
+ impl<T, CB> ProducerCallback<T> for Callback<CB>
+ where
+ CB: ProducerCallback<T>,
+ {
+ type Output = CB::Output;
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ crate::in_place_scope(|scope| {
+ let Self { callback, n } = self;
+ let (before_skip, after_skip) = base.split_at(n);
+
+ // Run the skipped part separately for side effects.
+ // We'll still get any panics propagated back by the scope.
+ scope.spawn(move |_| bridge_producer_consumer(n, before_skip, NoopConsumer));
+
+ callback.callback(after_skip)
+ })
+ }
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/splitter.rs b/third_party/rust/rayon/src/iter/splitter.rs
new file mode 100644
index 0000000000..40935ac2b0
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/splitter.rs
@@ -0,0 +1,174 @@
+use super::plumbing::*;
+use super::*;
+
+use std::fmt::{self, Debug};
+
+/// The `split` function takes arbitrary data and a closure that knows how to
+/// split it, and turns this into a `ParallelIterator`.
+///
+/// # Examples
+///
+/// As a simple example, Rayon can recursively split ranges of indices
+///
+/// ```
+/// use rayon::iter;
+/// use rayon::prelude::*;
+/// use std::ops::Range;
+///
+///
+/// // We define a range of indices as follows
+/// type Range1D = Range<usize>;
+///
+/// // Splitting it in two can be done like this
+/// fn split_range1(r: Range1D) -> (Range1D, Option<Range1D>) {
+/// // We are mathematically unable to split the range if there is only
+/// // one point inside of it, but we could stop splitting before that.
+/// if r.end - r.start <= 1 { return (r, None); }
+///
+/// // Here, our range is considered large enough to be splittable
+/// let midpoint = r.start + (r.end - r.start) / 2;
+/// (r.start..midpoint, Some(midpoint..r.end))
+/// }
+///
+/// // By using iter::split, Rayon will split the range until it has enough work
+/// // to feed the CPU cores, then give us the resulting sub-ranges
+/// iter::split(0..4096, split_range1).for_each(|sub_range| {
+/// // As our initial range had a power-of-two size, the final sub-ranges
+/// // should have power-of-two sizes too
+/// assert!((sub_range.end - sub_range.start).is_power_of_two());
+/// });
+/// ```
+///
+/// This recursive splitting can be extended to two or three dimensions,
+/// to reproduce a classic "block-wise" parallelization scheme of graphics and
+/// numerical simulations:
+///
+/// ```
+/// # use rayon::iter;
+/// # use rayon::prelude::*;
+/// # use std::ops::Range;
+/// # type Range1D = Range<usize>;
+/// # fn split_range1(r: Range1D) -> (Range1D, Option<Range1D>) {
+/// # if r.end - r.start <= 1 { return (r, None); }
+/// # let midpoint = r.start + (r.end - r.start) / 2;
+/// # (r.start..midpoint, Some(midpoint..r.end))
+/// # }
+/// #
+/// // A two-dimensional range of indices can be built out of two 1D ones
+/// struct Range2D {
+/// // Range of horizontal indices
+/// pub rx: Range1D,
+///
+/// // Range of vertical indices
+/// pub ry: Range1D,
+/// }
+///
+/// // We want to recursively split them by the largest dimension until we have
+/// // enough sub-ranges to feed our mighty multi-core CPU. This function
+/// // carries out one such split.
+/// fn split_range2(r2: Range2D) -> (Range2D, Option<Range2D>) {
+/// // Decide on which axis (horizontal/vertical) the range should be split
+/// let width = r2.rx.end - r2.rx.start;
+/// let height = r2.ry.end - r2.ry.start;
+/// if width >= height {
+/// // This is a wide range, split it on the horizontal axis
+/// let (split_rx, ry) = (split_range1(r2.rx), r2.ry);
+/// let out1 = Range2D {
+/// rx: split_rx.0,
+/// ry: ry.clone(),
+/// };
+/// let out2 = split_rx.1.map(|rx| Range2D { rx, ry });
+/// (out1, out2)
+/// } else {
+/// // This is a tall range, split it on the vertical axis
+/// let (rx, split_ry) = (r2.rx, split_range1(r2.ry));
+/// let out1 = Range2D {
+/// rx: rx.clone(),
+/// ry: split_ry.0,
+/// };
+/// let out2 = split_ry.1.map(|ry| Range2D { rx, ry, });
+/// (out1, out2)
+/// }
+/// }
+///
+/// // Again, rayon can handle the recursive splitting for us
+/// let range = Range2D { rx: 0..800, ry: 0..600 };
+/// iter::split(range, split_range2).for_each(|sub_range| {
+/// // If the sub-ranges were indeed split by the largest dimension, then
+/// // if no dimension was twice larger than the other initially, this
+/// // property will remain true in the final sub-ranges.
+/// let width = sub_range.rx.end - sub_range.rx.start;
+/// let height = sub_range.ry.end - sub_range.ry.start;
+/// assert!((width / 2 <= height) && (height / 2 <= width));
+/// });
+/// ```
+///
+pub fn split<D, S>(data: D, splitter: S) -> Split<D, S>
+where
+ D: Send,
+ S: Fn(D) -> (D, Option<D>) + Sync,
+{
+ Split { data, splitter }
+}
+
+/// `Split` is a parallel iterator using arbitrary data and a splitting function.
+/// This struct is created by the [`split()`] function.
+///
+/// [`split()`]: fn.split.html
+#[derive(Clone)]
+pub struct Split<D, S> {
+ data: D,
+ splitter: S,
+}
+
+impl<D: Debug, S> Debug for Split<D, S> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Split").field("data", &self.data).finish()
+ }
+}
+
+impl<D, S> ParallelIterator for Split<D, S>
+where
+ D: Send,
+ S: Fn(D) -> (D, Option<D>) + Sync + Send,
+{
+ type Item = D;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let producer = SplitProducer {
+ data: self.data,
+ splitter: &self.splitter,
+ };
+ bridge_unindexed(producer, consumer)
+ }
+}
+
+struct SplitProducer<'a, D, S> {
+ data: D,
+ splitter: &'a S,
+}
+
+impl<'a, D, S> UnindexedProducer for SplitProducer<'a, D, S>
+where
+ D: Send,
+ S: Fn(D) -> (D, Option<D>) + Sync,
+{
+ type Item = D;
+
+ fn split(mut self) -> (Self, Option<Self>) {
+ let splitter = self.splitter;
+ let (left, right) = splitter(self.data);
+ self.data = left;
+ (self, right.map(|data| SplitProducer { data, splitter }))
+ }
+
+ fn fold_with<F>(self, folder: F) -> F
+ where
+ F: Folder<Self::Item>,
+ {
+ folder.consume(self.data)
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/step_by.rs b/third_party/rust/rayon/src/iter/step_by.rs
new file mode 100644
index 0000000000..94b8334e86
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/step_by.rs
@@ -0,0 +1,143 @@
+use std::cmp::min;
+
+use super::plumbing::*;
+use super::*;
+use crate::math::div_round_up;
+use std::iter;
+use std::usize;
+
+/// `StepBy` is an iterator that skips `n` elements between each yield, where `n` is the given step.
+/// This struct is created by the [`step_by()`] method on [`IndexedParallelIterator`]
+///
+/// [`step_by()`]: trait.IndexedParallelIterator.html#method.step_by
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct StepBy<I: IndexedParallelIterator> {
+ base: I,
+ step: usize,
+}
+
+impl<I> StepBy<I>
+where
+ I: IndexedParallelIterator,
+{
+ /// Creates a new `StepBy` iterator.
+ pub(super) fn new(base: I, step: usize) -> Self {
+ StepBy { base, step }
+ }
+}
+
+impl<I> ParallelIterator for StepBy<I>
+where
+ I: IndexedParallelIterator,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I> IndexedParallelIterator for StepBy<I>
+where
+ I: IndexedParallelIterator,
+{
+ fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
+ bridge(self, consumer)
+ }
+
+ fn len(&self) -> usize {
+ div_round_up(self.base.len(), self.step)
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ let len = self.base.len();
+ return self.base.with_producer(Callback {
+ callback,
+ step: self.step,
+ len,
+ });
+
+ struct Callback<CB> {
+ callback: CB,
+ step: usize,
+ len: usize,
+ }
+
+ impl<T, CB> ProducerCallback<T> for Callback<CB>
+ where
+ CB: ProducerCallback<T>,
+ {
+ type Output = CB::Output;
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let producer = StepByProducer {
+ base,
+ step: self.step,
+ len: self.len,
+ };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Producer implementation
+
+struct StepByProducer<P> {
+ base: P,
+ step: usize,
+ len: usize,
+}
+
+impl<P> Producer for StepByProducer<P>
+where
+ P: Producer,
+{
+ type Item = P::Item;
+ type IntoIter = iter::StepBy<P::IntoIter>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.base.into_iter().step_by(self.step)
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let elem_index = min(index * self.step, self.len);
+
+ let (left, right) = self.base.split_at(elem_index);
+ (
+ StepByProducer {
+ base: left,
+ step: self.step,
+ len: elem_index,
+ },
+ StepByProducer {
+ base: right,
+ step: self.step,
+ len: self.len - elem_index,
+ },
+ )
+ }
+
+ fn min_len(&self) -> usize {
+ div_round_up(self.base.min_len(), self.step)
+ }
+
+ fn max_len(&self) -> usize {
+ self.base.max_len() / self.step
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/sum.rs b/third_party/rust/rayon/src/iter/sum.rs
new file mode 100644
index 0000000000..a73e0bf3d7
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/sum.rs
@@ -0,0 +1,110 @@
+use super::plumbing::*;
+use super::ParallelIterator;
+
+use std::iter::{self, Sum};
+use std::marker::PhantomData;
+
+pub(super) fn sum<PI, S>(pi: PI) -> S
+where
+ PI: ParallelIterator,
+ S: Send + Sum<PI::Item> + Sum,
+{
+ pi.drive_unindexed(SumConsumer::new())
+}
+
+fn add<T: Sum>(left: T, right: T) -> T {
+ iter::once(left).chain(iter::once(right)).sum()
+}
+
+struct SumConsumer<S: Send> {
+ _marker: PhantomData<*const S>,
+}
+
+unsafe impl<S: Send> Send for SumConsumer<S> {}
+
+impl<S: Send> SumConsumer<S> {
+ fn new() -> SumConsumer<S> {
+ SumConsumer {
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl<S, T> Consumer<T> for SumConsumer<S>
+where
+ S: Send + Sum<T> + Sum,
+{
+ type Folder = SumFolder<S>;
+ type Reducer = Self;
+ type Result = S;
+
+ fn split_at(self, _index: usize) -> (Self, Self, Self) {
+ (SumConsumer::new(), SumConsumer::new(), SumConsumer::new())
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ SumFolder {
+ sum: iter::empty::<T>().sum(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
+
+impl<S, T> UnindexedConsumer<T> for SumConsumer<S>
+where
+ S: Send + Sum<T> + Sum,
+{
+ fn split_off_left(&self) -> Self {
+ SumConsumer::new()
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ SumConsumer::new()
+ }
+}
+
+impl<S> Reducer<S> for SumConsumer<S>
+where
+ S: Send + Sum,
+{
+ fn reduce(self, left: S, right: S) -> S {
+ add(left, right)
+ }
+}
+
+struct SumFolder<S> {
+ sum: S,
+}
+
+impl<S, T> Folder<T> for SumFolder<S>
+where
+ S: Sum<T> + Sum,
+{
+ type Result = S;
+
+ fn consume(self, item: T) -> Self {
+ SumFolder {
+ sum: add(self.sum, iter::once(item).sum()),
+ }
+ }
+
+ fn consume_iter<I>(self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ SumFolder {
+ sum: add(self.sum, iter.into_iter().sum()),
+ }
+ }
+
+ fn complete(self) -> S {
+ self.sum
+ }
+
+ fn full(&self) -> bool {
+ false
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/take.rs b/third_party/rust/rayon/src/iter/take.rs
new file mode 100644
index 0000000000..52d15d805c
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/take.rs
@@ -0,0 +1,86 @@
+use super::plumbing::*;
+use super::*;
+use std::cmp::min;
+
+/// `Take` is an iterator that iterates over the first `n` elements.
+/// This struct is created by the [`take()`] method on [`IndexedParallelIterator`]
+///
+/// [`take()`]: trait.IndexedParallelIterator.html#method.take
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct Take<I> {
+ base: I,
+ n: usize,
+}
+
+impl<I> Take<I>
+where
+ I: IndexedParallelIterator,
+{
+ /// Creates a new `Take` iterator.
+ pub(super) fn new(base: I, n: usize) -> Self {
+ let n = min(base.len(), n);
+ Take { base, n }
+ }
+}
+
+impl<I> ParallelIterator for Take<I>
+where
+ I: IndexedParallelIterator,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<I> IndexedParallelIterator for Take<I>
+where
+ I: IndexedParallelIterator,
+{
+ fn len(&self) -> usize {
+ self.n
+ }
+
+ fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result {
+ bridge(self, consumer)
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback {
+ callback,
+ n: self.n,
+ });
+
+ struct Callback<CB> {
+ callback: CB,
+ n: usize,
+ }
+
+ impl<T, CB> ProducerCallback<T> for Callback<CB>
+ where
+ CB: ProducerCallback<T>,
+ {
+ type Output = CB::Output;
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let (producer, _) = base.split_at(self.n);
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/test.rs b/third_party/rust/rayon/src/iter/test.rs
new file mode 100644
index 0000000000..94323d79df
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/test.rs
@@ -0,0 +1,2185 @@
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+use super::*;
+use crate::prelude::*;
+use rayon_core::*;
+
+use rand::distributions::Standard;
+use rand::{Rng, SeedableRng};
+use rand_xorshift::XorShiftRng;
+use std::collections::LinkedList;
+use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
+use std::collections::{BinaryHeap, VecDeque};
+use std::f64;
+use std::fmt::Debug;
+use std::sync::mpsc;
+use std::usize;
+
+fn is_indexed<T: IndexedParallelIterator>(_: T) {}
+
+fn seeded_rng() -> XorShiftRng {
+ let mut seed = <XorShiftRng as SeedableRng>::Seed::default();
+ (0..).zip(seed.as_mut()).for_each(|(i, x)| *x = i);
+ XorShiftRng::from_seed(seed)
+}
+
+#[test]
+fn execute() {
+ let a: Vec<i32> = (0..1024).collect();
+ let mut b = vec![];
+ a.par_iter().map(|&i| i + 1).collect_into_vec(&mut b);
+ let c: Vec<i32> = (0..1024).map(|i| i + 1).collect();
+ assert_eq!(b, c);
+}
+
+#[test]
+fn execute_cloned() {
+ let a: Vec<i32> = (0..1024).collect();
+ let mut b: Vec<i32> = vec![];
+ a.par_iter().cloned().collect_into_vec(&mut b);
+ let c: Vec<i32> = (0..1024).collect();
+ assert_eq!(b, c);
+}
+
+#[test]
+fn execute_range() {
+ let a = 0i32..1024;
+ let mut b = vec![];
+ a.into_par_iter().map(|i| i + 1).collect_into_vec(&mut b);
+ let c: Vec<i32> = (0..1024).map(|i| i + 1).collect();
+ assert_eq!(b, c);
+}
+
+#[test]
+fn execute_unindexed_range() {
+ let a = 0i64..1024;
+ let b: LinkedList<i64> = a.into_par_iter().map(|i| i + 1).collect();
+ let c: LinkedList<i64> = (0..1024).map(|i| i + 1).collect();
+ assert_eq!(b, c);
+}
+
+#[test]
+fn execute_pseudo_indexed_range() {
+ use std::i128::MAX;
+ let range = MAX - 1024..MAX;
+
+ // Given `Some` length, collecting `Vec` will try to act indexed.
+ let a = range.clone().into_par_iter();
+ assert_eq!(a.opt_len(), Some(1024));
+
+ let b: Vec<i128> = a.map(|i| i + 1).collect();
+ let c: Vec<i128> = range.map(|i| i + 1).collect();
+ assert_eq!(b, c);
+}
+
+#[test]
+fn check_map_indexed() {
+ let a = [1, 2, 3];
+ is_indexed(a.par_iter().map(|x| x));
+}
+
+#[test]
+fn map_sum() {
+ let a: Vec<i32> = (0..1024).collect();
+ let r1: i32 = a.par_iter().map(|&i| i + 1).sum();
+ let r2 = a.iter().map(|&i| i + 1).sum();
+ assert_eq!(r1, r2);
+}
+
+#[test]
+fn map_reduce() {
+ let a: Vec<i32> = (0..1024).collect();
+ let r1 = a.par_iter().map(|&i| i + 1).reduce(|| 0, |i, j| i + j);
+ let r2 = a.iter().map(|&i| i + 1).sum();
+ assert_eq!(r1, r2);
+}
+
+#[test]
+fn map_reduce_with() {
+ let a: Vec<i32> = (0..1024).collect();
+ let r1 = a.par_iter().map(|&i| i + 1).reduce_with(|i, j| i + j);
+ let r2 = a.iter().map(|&i| i + 1).sum();
+ assert_eq!(r1, Some(r2));
+}
+
+#[test]
+fn fold_map_reduce() {
+ // Kind of a weird test, but it demonstrates various
+ // transformations that are taking place. Relies on
+ // `with_max_len(1).fold()` being equivalent to `map()`.
+ //
+ // Take each number from 0 to 32 and fold them by appending to a
+ // vector. Because of `with_max_len(1)`, this will produce 32 vectors,
+ // each with one item. We then collect all of these into an
+ // individual vector by mapping each into their own vector (so we
+ // have Vec<Vec<i32>>) and then reducing those into a single
+ // vector.
+ let r1 = (0_i32..32)
+ .into_par_iter()
+ .with_max_len(1)
+ .fold(Vec::new, |mut v, e| {
+ v.push(e);
+ v
+ })
+ .map(|v| vec![v])
+ .reduce_with(|mut v_a, v_b| {
+ v_a.extend(v_b);
+ v_a
+ });
+ assert_eq!(
+ r1,
+ Some(vec![
+ vec![0],
+ vec![1],
+ vec![2],
+ vec![3],
+ vec![4],
+ vec![5],
+ vec![6],
+ vec![7],
+ vec![8],
+ vec![9],
+ vec![10],
+ vec![11],
+ vec![12],
+ vec![13],
+ vec![14],
+ vec![15],
+ vec![16],
+ vec![17],
+ vec![18],
+ vec![19],
+ vec![20],
+ vec![21],
+ vec![22],
+ vec![23],
+ vec![24],
+ vec![25],
+ vec![26],
+ vec![27],
+ vec![28],
+ vec![29],
+ vec![30],
+ vec![31]
+ ])
+ );
+}
+
+#[test]
+fn fold_is_full() {
+ let counter = AtomicUsize::new(0);
+ let a = (0_i32..2048)
+ .into_par_iter()
+ .inspect(|_| {
+ counter.fetch_add(1, Ordering::SeqCst);
+ })
+ .fold(|| 0, |a, b| a + b)
+ .find_any(|_| true);
+ assert!(a.is_some());
+ assert!(counter.load(Ordering::SeqCst) < 2048); // should not have visited every single one
+}
+
+#[test]
+fn check_step_by() {
+ let a: Vec<i32> = (0..1024).step_by(2).collect();
+ let b: Vec<i32> = (0..1024).into_par_iter().step_by(2).collect();
+
+ assert_eq!(a, b);
+}
+
+#[test]
+fn check_step_by_unaligned() {
+ let a: Vec<i32> = (0..1029).step_by(10).collect();
+ let b: Vec<i32> = (0..1029).into_par_iter().step_by(10).collect();
+
+ assert_eq!(a, b)
+}
+
+#[test]
+fn check_step_by_rev() {
+ let a: Vec<i32> = (0..1024).step_by(2).rev().collect();
+ let b: Vec<i32> = (0..1024).into_par_iter().step_by(2).rev().collect();
+
+ assert_eq!(a, b);
+}
+
+#[test]
+fn check_enumerate() {
+ let a: Vec<usize> = (0..1024).rev().collect();
+
+ let mut b = vec![];
+ a.par_iter()
+ .enumerate()
+ .map(|(i, &x)| i + x)
+ .collect_into_vec(&mut b);
+ assert!(b.iter().all(|&x| x == a.len() - 1));
+}
+
+#[test]
+fn check_enumerate_rev() {
+ let a: Vec<usize> = (0..1024).rev().collect();
+
+ let mut b = vec![];
+ a.par_iter()
+ .enumerate()
+ .rev()
+ .map(|(i, &x)| i + x)
+ .collect_into_vec(&mut b);
+ assert!(b.iter().all(|&x| x == a.len() - 1));
+}
+
+#[test]
+fn check_indices_after_enumerate_split() {
+ let a: Vec<i32> = (0..1024).collect();
+ a.par_iter().enumerate().with_producer(WithProducer);
+
+ struct WithProducer;
+ impl<'a> ProducerCallback<(usize, &'a i32)> for WithProducer {
+ type Output = ();
+ fn callback<P>(self, producer: P)
+ where
+ P: Producer<Item = (usize, &'a i32)>,
+ {
+ let (a, b) = producer.split_at(512);
+ for ((index, value), trusted_index) in a.into_iter().zip(0..) {
+ assert_eq!(index, trusted_index);
+ assert_eq!(index, *value as usize);
+ }
+ for ((index, value), trusted_index) in b.into_iter().zip(512..) {
+ assert_eq!(index, trusted_index);
+ assert_eq!(index, *value as usize);
+ }
+ }
+ }
+}
+
+#[test]
+fn check_increment() {
+ let mut a: Vec<usize> = (0..1024).rev().collect();
+
+ a.par_iter_mut().enumerate().for_each(|(i, v)| *v += i);
+
+ assert!(a.iter().all(|&x| x == a.len() - 1));
+}
+
+#[test]
+fn check_skip() {
+ let a: Vec<usize> = (0..1024).collect();
+
+ let mut v1 = Vec::new();
+ a.par_iter().skip(16).collect_into_vec(&mut v1);
+ let v2 = a.iter().skip(16).collect::<Vec<_>>();
+ assert_eq!(v1, v2);
+
+ let mut v1 = Vec::new();
+ a.par_iter().skip(2048).collect_into_vec(&mut v1);
+ let v2 = a.iter().skip(2048).collect::<Vec<_>>();
+ assert_eq!(v1, v2);
+
+ let mut v1 = Vec::new();
+ a.par_iter().skip(0).collect_into_vec(&mut v1);
+ let v2 = a.iter().skip(0).collect::<Vec<_>>();
+ assert_eq!(v1, v2);
+
+ // Check that the skipped elements side effects are executed
+ use std::sync::atomic::{AtomicUsize, Ordering};
+ let num = AtomicUsize::new(0);
+ a.par_iter()
+ .map(|&n| num.fetch_add(n, Ordering::Relaxed))
+ .skip(512)
+ .count();
+ assert_eq!(num.load(Ordering::Relaxed), a.iter().sum::<usize>());
+}
+
+#[test]
+fn check_take() {
+ let a: Vec<usize> = (0..1024).collect();
+
+ let mut v1 = Vec::new();
+ a.par_iter().take(16).collect_into_vec(&mut v1);
+ let v2 = a.iter().take(16).collect::<Vec<_>>();
+ assert_eq!(v1, v2);
+
+ let mut v1 = Vec::new();
+ a.par_iter().take(2048).collect_into_vec(&mut v1);
+ let v2 = a.iter().take(2048).collect::<Vec<_>>();
+ assert_eq!(v1, v2);
+
+ let mut v1 = Vec::new();
+ a.par_iter().take(0).collect_into_vec(&mut v1);
+ let v2 = a.iter().take(0).collect::<Vec<_>>();
+ assert_eq!(v1, v2);
+}
+
+#[test]
+fn check_inspect() {
+ use std::sync::atomic::{AtomicUsize, Ordering};
+
+ let a = AtomicUsize::new(0);
+ let b: usize = (0_usize..1024)
+ .into_par_iter()
+ .inspect(|&i| {
+ a.fetch_add(i, Ordering::Relaxed);
+ })
+ .sum();
+
+ assert_eq!(a.load(Ordering::Relaxed), b);
+}
+
+#[test]
+fn check_move() {
+ let a = vec![vec![1, 2, 3]];
+ let ptr = a[0].as_ptr();
+
+ let mut b = vec![];
+ a.into_par_iter().collect_into_vec(&mut b);
+
+ // a simple move means the inner vec will be completely unchanged
+ assert_eq!(ptr, b[0].as_ptr());
+}
+
+#[test]
+fn check_drops() {
+ use std::sync::atomic::{AtomicUsize, Ordering};
+
+ let c = AtomicUsize::new(0);
+ let a = vec![DropCounter(&c); 10];
+
+ let mut b = vec![];
+ a.clone().into_par_iter().collect_into_vec(&mut b);
+ assert_eq!(c.load(Ordering::Relaxed), 0);
+
+ b.into_par_iter();
+ assert_eq!(c.load(Ordering::Relaxed), 10);
+
+ a.into_par_iter().with_producer(Partial);
+ assert_eq!(c.load(Ordering::Relaxed), 20);
+
+ #[derive(Clone)]
+ struct DropCounter<'a>(&'a AtomicUsize);
+ impl<'a> Drop for DropCounter<'a> {
+ fn drop(&mut self) {
+ self.0.fetch_add(1, Ordering::Relaxed);
+ }
+ }
+
+ struct Partial;
+ impl<'a> ProducerCallback<DropCounter<'a>> for Partial {
+ type Output = ();
+ fn callback<P>(self, producer: P)
+ where
+ P: Producer<Item = DropCounter<'a>>,
+ {
+ let (a, _) = producer.split_at(5);
+ a.into_iter().next();
+ }
+ }
+}
+
+#[test]
+fn check_slice_indexed() {
+ let a = vec![1, 2, 3];
+ is_indexed(a.par_iter());
+}
+
+#[test]
+fn check_slice_mut_indexed() {
+ let mut a = vec![1, 2, 3];
+ is_indexed(a.par_iter_mut());
+}
+
+#[test]
+fn check_vec_indexed() {
+ let a = vec![1, 2, 3];
+ is_indexed(a.into_par_iter());
+}
+
+#[test]
+fn check_range_indexed() {
+ is_indexed((1..5).into_par_iter());
+}
+
+#[test]
+fn check_cmp_direct() {
+ let a = (0..1024).into_par_iter();
+ let b = (0..1024).into_par_iter();
+
+ let result = a.cmp(b);
+
+ assert!(result == ::std::cmp::Ordering::Equal);
+}
+
+#[test]
+fn check_cmp_to_seq() {
+ assert_eq!(
+ (0..1024).into_par_iter().cmp(0..1024),
+ (0..1024).cmp(0..1024)
+ );
+}
+
+#[test]
+fn check_cmp_rng_to_seq() {
+ let mut rng = seeded_rng();
+ let rng = &mut rng;
+ let a: Vec<i32> = rng.sample_iter(&Standard).take(1024).collect();
+ let b: Vec<i32> = rng.sample_iter(&Standard).take(1024).collect();
+ for i in 0..a.len() {
+ let par_result = a[i..].par_iter().cmp(b[i..].par_iter());
+ let seq_result = a[i..].iter().cmp(b[i..].iter());
+
+ assert_eq!(par_result, seq_result);
+ }
+}
+
+#[test]
+fn check_cmp_lt_direct() {
+ let a = (0..1024).into_par_iter();
+ let b = (1..1024).into_par_iter();
+
+ let result = a.cmp(b);
+
+ assert!(result == ::std::cmp::Ordering::Less);
+}
+
+#[test]
+fn check_cmp_lt_to_seq() {
+ assert_eq!(
+ (0..1024).into_par_iter().cmp(1..1024),
+ (0..1024).cmp(1..1024)
+ )
+}
+
+#[test]
+fn check_cmp_gt_direct() {
+ let a = (1..1024).into_par_iter();
+ let b = (0..1024).into_par_iter();
+
+ let result = a.cmp(b);
+
+ assert!(result == ::std::cmp::Ordering::Greater);
+}
+
+#[test]
+fn check_cmp_gt_to_seq() {
+ assert_eq!(
+ (1..1024).into_par_iter().cmp(0..1024),
+ (1..1024).cmp(0..1024)
+ )
+}
+
+#[test]
+fn check_cmp_short_circuit() {
+ // We only use a single thread in order to make the short-circuit behavior deterministic.
+ let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
+
+ let a = vec![0; 1024];
+ let mut b = a.clone();
+ b[42] = 1;
+
+ pool.install(|| {
+ let expected = ::std::cmp::Ordering::Less;
+ assert_eq!(a.par_iter().cmp(&b), expected);
+
+ for len in 1..10 {
+ let counter = AtomicUsize::new(0);
+ let result = a
+ .par_iter()
+ .with_max_len(len)
+ .inspect(|_| {
+ counter.fetch_add(1, Ordering::SeqCst);
+ })
+ .cmp(&b);
+ assert_eq!(result, expected);
+ // should not have visited every single one
+ assert!(counter.into_inner() < a.len());
+ }
+ });
+}
+
+#[test]
+fn check_partial_cmp_short_circuit() {
+ // We only use a single thread to make the short-circuit behavior deterministic.
+ let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
+
+ let a = vec![0; 1024];
+ let mut b = a.clone();
+ b[42] = 1;
+
+ pool.install(|| {
+ let expected = Some(::std::cmp::Ordering::Less);
+ assert_eq!(a.par_iter().partial_cmp(&b), expected);
+
+ for len in 1..10 {
+ let counter = AtomicUsize::new(0);
+ let result = a
+ .par_iter()
+ .with_max_len(len)
+ .inspect(|_| {
+ counter.fetch_add(1, Ordering::SeqCst);
+ })
+ .partial_cmp(&b);
+ assert_eq!(result, expected);
+ // should not have visited every single one
+ assert!(counter.into_inner() < a.len());
+ }
+ });
+}
+
+#[test]
+fn check_partial_cmp_nan_short_circuit() {
+ // We only use a single thread to make the short-circuit behavior deterministic.
+ let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
+
+ let a = vec![0.0; 1024];
+ let mut b = a.clone();
+ b[42] = f64::NAN;
+
+ pool.install(|| {
+ let expected = None;
+ assert_eq!(a.par_iter().partial_cmp(&b), expected);
+
+ for len in 1..10 {
+ let counter = AtomicUsize::new(0);
+ let result = a
+ .par_iter()
+ .with_max_len(len)
+ .inspect(|_| {
+ counter.fetch_add(1, Ordering::SeqCst);
+ })
+ .partial_cmp(&b);
+ assert_eq!(result, expected);
+ // should not have visited every single one
+ assert!(counter.into_inner() < a.len());
+ }
+ });
+}
+
+#[test]
+fn check_partial_cmp_direct() {
+ let a = (0..1024).into_par_iter();
+ let b = (0..1024).into_par_iter();
+
+ let result = a.partial_cmp(b);
+
+ assert!(result == Some(::std::cmp::Ordering::Equal));
+}
+
+#[test]
+fn check_partial_cmp_to_seq() {
+ let par_result = (0..1024).into_par_iter().partial_cmp(0..1024);
+ let seq_result = (0..1024).partial_cmp(0..1024);
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_partial_cmp_rng_to_seq() {
+ let mut rng = seeded_rng();
+ let rng = &mut rng;
+ let a: Vec<i32> = rng.sample_iter(&Standard).take(1024).collect();
+ let b: Vec<i32> = rng.sample_iter(&Standard).take(1024).collect();
+ for i in 0..a.len() {
+ let par_result = a[i..].par_iter().partial_cmp(b[i..].par_iter());
+ let seq_result = a[i..].iter().partial_cmp(b[i..].iter());
+
+ assert_eq!(par_result, seq_result);
+ }
+}
+
+#[test]
+fn check_partial_cmp_lt_direct() {
+ let a = (0..1024).into_par_iter();
+ let b = (1..1024).into_par_iter();
+
+ let result = a.partial_cmp(b);
+
+ assert!(result == Some(::std::cmp::Ordering::Less));
+}
+
+#[test]
+fn check_partial_cmp_lt_to_seq() {
+ let par_result = (0..1024).into_par_iter().partial_cmp(1..1024);
+ let seq_result = (0..1024).partial_cmp(1..1024);
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_partial_cmp_gt_direct() {
+ let a = (1..1024).into_par_iter();
+ let b = (0..1024).into_par_iter();
+
+ let result = a.partial_cmp(b);
+
+ assert!(result == Some(::std::cmp::Ordering::Greater));
+}
+
+#[test]
+fn check_partial_cmp_gt_to_seq() {
+ let par_result = (1..1024).into_par_iter().partial_cmp(0..1024);
+ let seq_result = (1..1024).partial_cmp(0..1024);
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_partial_cmp_none_direct() {
+ let a = vec![f64::NAN, 0.0];
+ let b = vec![0.0, 1.0];
+
+ let result = a.par_iter().partial_cmp(b.par_iter());
+
+ assert!(result == None);
+}
+
+#[test]
+fn check_partial_cmp_none_to_seq() {
+ let a = vec![f64::NAN, 0.0];
+ let b = vec![0.0, 1.0];
+
+ let par_result = a.par_iter().partial_cmp(b.par_iter());
+ let seq_result = a.iter().partial_cmp(b.iter());
+
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_partial_cmp_late_nan_direct() {
+ let a = vec![0.0, f64::NAN];
+ let b = vec![1.0, 1.0];
+
+ let result = a.par_iter().partial_cmp(b.par_iter());
+
+ assert!(result == Some(::std::cmp::Ordering::Less));
+}
+
+#[test]
+fn check_partial_cmp_late_nane_to_seq() {
+ let a = vec![0.0, f64::NAN];
+ let b = vec![1.0, 1.0];
+
+ let par_result = a.par_iter().partial_cmp(b.par_iter());
+ let seq_result = a.iter().partial_cmp(b.iter());
+
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_cmp_lengths() {
+ // comparisons should consider length if they are otherwise equal
+ let a = vec![0; 1024];
+ let b = vec![0; 1025];
+
+ assert_eq!(a.par_iter().cmp(&b), a.iter().cmp(&b));
+ assert_eq!(a.par_iter().partial_cmp(&b), a.iter().partial_cmp(&b));
+}
+
+#[test]
+fn check_eq_direct() {
+ let a = (0..1024).into_par_iter();
+ let b = (0..1024).into_par_iter();
+
+ let result = a.eq(b);
+
+ assert!(result);
+}
+
+#[test]
+fn check_eq_to_seq() {
+ let par_result = (0..1024).into_par_iter().eq((0..1024).into_par_iter());
+ let seq_result = (0..1024).eq(0..1024);
+
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_ne_direct() {
+ let a = (0..1024).into_par_iter();
+ let b = (1..1024).into_par_iter();
+
+ let result = a.ne(b);
+
+ assert!(result);
+}
+
+#[test]
+fn check_ne_to_seq() {
+ let par_result = (0..1024).into_par_iter().ne((1..1025).into_par_iter());
+ let seq_result = (0..1024).ne(1..1025);
+
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_ne_lengths() {
+ // equality should consider length too
+ let a = vec![0; 1024];
+ let b = vec![0; 1025];
+
+ assert_eq!(a.par_iter().eq(&b), a.iter().eq(&b));
+ assert_eq!(a.par_iter().ne(&b), a.iter().ne(&b));
+}
+
+#[test]
+fn check_lt_direct() {
+ assert!((0..1024).into_par_iter().lt(1..1024));
+ assert!(!(1..1024).into_par_iter().lt(0..1024));
+}
+
+#[test]
+fn check_lt_to_seq() {
+ let par_result = (0..1024).into_par_iter().lt((1..1024).into_par_iter());
+ let seq_result = (0..1024).lt(1..1024);
+
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_le_equal_direct() {
+ assert!((0..1024).into_par_iter().le((0..1024).into_par_iter()));
+}
+
+#[test]
+fn check_le_equal_to_seq() {
+ let par_result = (0..1024).into_par_iter().le((0..1024).into_par_iter());
+ let seq_result = (0..1024).le(0..1024);
+
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_le_less_direct() {
+ assert!((0..1024).into_par_iter().le((1..1024).into_par_iter()));
+}
+
+#[test]
+fn check_le_less_to_seq() {
+ let par_result = (0..1024).into_par_iter().le((1..1024).into_par_iter());
+ let seq_result = (0..1024).le(1..1024);
+
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_gt_direct() {
+ assert!((1..1024).into_par_iter().gt((0..1024).into_par_iter()));
+}
+
+#[test]
+fn check_gt_to_seq() {
+ let par_result = (1..1024).into_par_iter().gt((0..1024).into_par_iter());
+ let seq_result = (1..1024).gt(0..1024);
+
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_ge_equal_direct() {
+ assert!((0..1024).into_par_iter().ge((0..1024).into_par_iter()));
+}
+
+#[test]
+fn check_ge_equal_to_seq() {
+ let par_result = (0..1024).into_par_iter().ge((0..1024).into_par_iter());
+ let seq_result = (0..1024).ge(0..1024);
+
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_ge_greater_direct() {
+ assert!((1..1024).into_par_iter().ge((0..1024).into_par_iter()));
+}
+
+#[test]
+fn check_ge_greater_to_seq() {
+ let par_result = (1..1024).into_par_iter().ge((0..1024).into_par_iter());
+ let seq_result = (1..1024).ge(0..1024);
+
+ assert_eq!(par_result, seq_result);
+}
+
+#[test]
+fn check_zip() {
+ let mut a: Vec<usize> = (0..1024).rev().collect();
+ let b: Vec<usize> = (0..1024).collect();
+
+ a.par_iter_mut().zip(&b[..]).for_each(|(a, &b)| *a += b);
+
+ assert!(a.iter().all(|&x| x == a.len() - 1));
+}
+
+#[test]
+fn check_zip_into_par_iter() {
+ let mut a: Vec<usize> = (0..1024).rev().collect();
+ let b: Vec<usize> = (0..1024).collect();
+
+ a.par_iter_mut()
+ .zip(&b) // here we rely on &b iterating over &usize
+ .for_each(|(a, &b)| *a += b);
+
+ assert!(a.iter().all(|&x| x == a.len() - 1));
+}
+
+#[test]
+fn check_zip_into_mut_par_iter() {
+ let a: Vec<usize> = (0..1024).rev().collect();
+ let mut b: Vec<usize> = (0..1024).collect();
+
+ a.par_iter().zip(&mut b).for_each(|(&a, b)| *b += a);
+
+ assert!(b.iter().all(|&x| x == b.len() - 1));
+}
+
+#[test]
+fn check_zip_range() {
+ let mut a: Vec<usize> = (0..1024).rev().collect();
+
+ a.par_iter_mut()
+ .zip(0usize..1024)
+ .for_each(|(a, b)| *a += b);
+
+ assert!(a.iter().all(|&x| x == a.len() - 1));
+}
+
+#[test]
+fn check_zip_eq() {
+ let mut a: Vec<usize> = (0..1024).rev().collect();
+ let b: Vec<usize> = (0..1024).collect();
+
+ a.par_iter_mut().zip_eq(&b[..]).for_each(|(a, &b)| *a += b);
+
+ assert!(a.iter().all(|&x| x == a.len() - 1));
+}
+
+#[test]
+fn check_zip_eq_into_par_iter() {
+ let mut a: Vec<usize> = (0..1024).rev().collect();
+ let b: Vec<usize> = (0..1024).collect();
+
+ a.par_iter_mut()
+ .zip_eq(&b) // here we rely on &b iterating over &usize
+ .for_each(|(a, &b)| *a += b);
+
+ assert!(a.iter().all(|&x| x == a.len() - 1));
+}
+
+#[test]
+fn check_zip_eq_into_mut_par_iter() {
+ let a: Vec<usize> = (0..1024).rev().collect();
+ let mut b: Vec<usize> = (0..1024).collect();
+
+ a.par_iter().zip_eq(&mut b).for_each(|(&a, b)| *b += a);
+
+ assert!(b.iter().all(|&x| x == b.len() - 1));
+}
+
+#[test]
+fn check_zip_eq_range() {
+ let mut a: Vec<usize> = (0..1024).rev().collect();
+
+ a.par_iter_mut()
+ .zip_eq(0usize..1024)
+ .for_each(|(a, b)| *a += b);
+
+ assert!(a.iter().all(|&x| x == a.len() - 1));
+}
+
+#[test]
+fn check_sum_filtered_ints() {
+ let a: Vec<i32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let par_sum_evens: i32 = a.par_iter().filter(|&x| (x & 1) == 0).sum();
+ let seq_sum_evens = a.iter().filter(|&x| (x & 1) == 0).sum();
+ assert_eq!(par_sum_evens, seq_sum_evens);
+}
+
+#[test]
+fn check_sum_filtermap_ints() {
+ let a: Vec<i32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let par_sum_evens: u32 = a
+ .par_iter()
+ .filter_map(|&x| if (x & 1) == 0 { Some(x as u32) } else { None })
+ .sum();
+ let seq_sum_evens = a
+ .iter()
+ .filter_map(|&x| if (x & 1) == 0 { Some(x as u32) } else { None })
+ .sum();
+ assert_eq!(par_sum_evens, seq_sum_evens);
+}
+
+#[test]
+fn check_flat_map_nested_ranges() {
+ // FIXME -- why are precise type hints required on the integers here?
+
+ let v: i32 = (0_i32..10)
+ .into_par_iter()
+ .flat_map(|i| (0_i32..10).into_par_iter().map(move |j| (i, j)))
+ .map(|(i, j)| i * j)
+ .sum();
+
+ let w = (0_i32..10)
+ .flat_map(|i| (0_i32..10).map(move |j| (i, j)))
+ .map(|(i, j)| i * j)
+ .sum();
+
+ assert_eq!(v, w);
+}
+
+#[test]
+fn check_empty_flat_map_sum() {
+ let a: Vec<i32> = (0..1024).collect();
+ let empty = &a[..0];
+
+ // empty on the inside
+ let b: i32 = a.par_iter().flat_map(|_| empty).sum();
+ assert_eq!(b, 0);
+
+ // empty on the outside
+ let c: i32 = empty.par_iter().flat_map(|_| a.par_iter()).sum();
+ assert_eq!(c, 0);
+}
+
+#[test]
+fn check_flatten_vec() {
+ let a: Vec<i32> = (0..1024).collect();
+ let b: Vec<Vec<i32>> = vec![a.clone(), a.clone(), a.clone(), a.clone()];
+ let c: Vec<i32> = b.par_iter().flatten().cloned().collect();
+ let mut d = a.clone();
+ d.extend(&a);
+ d.extend(&a);
+ d.extend(&a);
+
+ assert_eq!(d, c);
+}
+
+#[test]
+fn check_flatten_vec_empty() {
+ let a: Vec<Vec<i32>> = vec![vec![]];
+ let b: Vec<i32> = a.par_iter().flatten().cloned().collect();
+
+ assert_eq!(vec![] as Vec<i32>, b);
+}
+
+#[test]
+fn check_slice_split() {
+ let v: Vec<_> = (0..1000).collect();
+ for m in 1..100 {
+ let a: Vec<_> = v.split(|x| x % m == 0).collect();
+ let b: Vec<_> = v.par_split(|x| x % m == 0).collect();
+ assert_eq!(a, b);
+ }
+
+ // same as std::slice::split() examples
+ let slice = [10, 40, 33, 20];
+ let v: Vec<_> = slice.par_split(|num| num % 3 == 0).collect();
+ assert_eq!(v, &[&slice[..2], &slice[3..]]);
+
+ let slice = [10, 40, 33];
+ let v: Vec<_> = slice.par_split(|num| num % 3 == 0).collect();
+ assert_eq!(v, &[&slice[..2], &slice[..0]]);
+
+ let slice = [10, 6, 33, 20];
+ let v: Vec<_> = slice.par_split(|num| num % 3 == 0).collect();
+ assert_eq!(v, &[&slice[..1], &slice[..0], &slice[3..]]);
+}
+
+#[test]
+fn check_slice_split_mut() {
+ let mut v1: Vec<_> = (0..1000).collect();
+ let mut v2 = v1.clone();
+ for m in 1..100 {
+ let a: Vec<_> = v1.split_mut(|x| x % m == 0).collect();
+ let b: Vec<_> = v2.par_split_mut(|x| x % m == 0).collect();
+ assert_eq!(a, b);
+ }
+
+ // same as std::slice::split_mut() example
+ let mut v = [10, 40, 30, 20, 60, 50];
+ v.par_split_mut(|num| num % 3 == 0).for_each(|group| {
+ group[0] = 1;
+ });
+ assert_eq!(v, [1, 40, 30, 1, 60, 1]);
+}
+
+#[test]
+fn check_chunks() {
+ let a: Vec<i32> = vec![1, 5, 10, 4, 100, 3, 1000, 2, 10000, 1];
+ let par_sum_product_pairs: i32 = a.par_chunks(2).map(|c| c.iter().product::<i32>()).sum();
+ let seq_sum_product_pairs = a.chunks(2).map(|c| c.iter().product::<i32>()).sum();
+ assert_eq!(par_sum_product_pairs, 12345);
+ assert_eq!(par_sum_product_pairs, seq_sum_product_pairs);
+
+ let par_sum_product_triples: i32 = a.par_chunks(3).map(|c| c.iter().product::<i32>()).sum();
+ let seq_sum_product_triples = a.chunks(3).map(|c| c.iter().product::<i32>()).sum();
+ assert_eq!(par_sum_product_triples, 5_0 + 12_00 + 20_000_000 + 1);
+ assert_eq!(par_sum_product_triples, seq_sum_product_triples);
+}
+
+#[test]
+fn check_chunks_mut() {
+ let mut a: Vec<i32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let mut b: Vec<i32> = a.clone();
+ a.par_chunks_mut(2).for_each(|c| c[0] = c.iter().sum());
+ b.chunks_mut(2).for_each(|c| c[0] = c.iter().sum());
+ assert_eq!(a, &[3, 2, 7, 4, 11, 6, 15, 8, 19, 10]);
+ assert_eq!(a, b);
+
+ let mut a: Vec<i32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let mut b: Vec<i32> = a.clone();
+ a.par_chunks_mut(3).for_each(|c| c[0] = c.iter().sum());
+ b.chunks_mut(3).for_each(|c| c[0] = c.iter().sum());
+ assert_eq!(a, &[6, 2, 3, 15, 5, 6, 24, 8, 9, 10]);
+ assert_eq!(a, b);
+}
+
+#[test]
+fn check_windows() {
+ let a: Vec<i32> = (0..1024).collect();
+ let par: Vec<_> = a.par_windows(2).collect();
+ let seq: Vec<_> = a.windows(2).collect();
+ assert_eq!(par, seq);
+
+ let par: Vec<_> = a.par_windows(100).collect();
+ let seq: Vec<_> = a.windows(100).collect();
+ assert_eq!(par, seq);
+
+ let par: Vec<_> = a.par_windows(1_000_000).collect();
+ let seq: Vec<_> = a.windows(1_000_000).collect();
+ assert_eq!(par, seq);
+
+ let par: Vec<_> = a
+ .par_windows(2)
+ .chain(a.par_windows(1_000_000))
+ .zip(a.par_windows(2))
+ .collect();
+ let seq: Vec<_> = a
+ .windows(2)
+ .chain(a.windows(1_000_000))
+ .zip(a.windows(2))
+ .collect();
+ assert_eq!(par, seq);
+}
+
+#[test]
+fn check_options() {
+ let mut a = vec![None, Some(1), None, None, Some(2), Some(4)];
+
+ assert_eq!(7, a.par_iter().flat_map(|opt| opt).sum::<i32>());
+ assert_eq!(7, a.par_iter().flat_map(|opt| opt).sum::<i32>());
+
+ a.par_iter_mut()
+ .flat_map(|opt| opt)
+ .for_each(|x| *x = *x * *x);
+
+ assert_eq!(21, a.into_par_iter().flat_map(|opt| opt).sum::<i32>());
+}
+
+#[test]
+fn check_results() {
+ let mut a = vec![Err(()), Ok(1i32), Err(()), Err(()), Ok(2), Ok(4)];
+
+ assert_eq!(7, a.par_iter().flat_map(|res| res).sum::<i32>());
+
+ assert_eq!(Err::<i32, ()>(()), a.par_iter().cloned().sum());
+ assert_eq!(Ok(7), a.par_iter().cloned().filter(Result::is_ok).sum());
+
+ assert_eq!(Err::<i32, ()>(()), a.par_iter().cloned().product());
+ assert_eq!(Ok(8), a.par_iter().cloned().filter(Result::is_ok).product());
+
+ a.par_iter_mut()
+ .flat_map(|res| res)
+ .for_each(|x| *x = *x * *x);
+
+ assert_eq!(21, a.into_par_iter().flat_map(|res| res).sum::<i32>());
+}
+
+#[test]
+fn check_binary_heap() {
+ use std::collections::BinaryHeap;
+
+ let a: BinaryHeap<i32> = (0..10).collect();
+
+ assert_eq!(45, a.par_iter().sum::<i32>());
+ assert_eq!(45, a.into_par_iter().sum::<i32>());
+}
+
+#[test]
+fn check_btree_map() {
+ use std::collections::BTreeMap;
+
+ let mut a: BTreeMap<i32, i32> = (0..10).map(|i| (i, -i)).collect();
+
+ assert_eq!(45, a.par_iter().map(|(&k, _)| k).sum::<i32>());
+ assert_eq!(-45, a.par_iter().map(|(_, &v)| v).sum::<i32>());
+
+ a.par_iter_mut().for_each(|(k, v)| *v += *k);
+
+ assert_eq!(0, a.into_par_iter().map(|(_, v)| v).sum::<i32>());
+}
+
+#[test]
+fn check_btree_set() {
+ use std::collections::BTreeSet;
+
+ let a: BTreeSet<i32> = (0..10).collect();
+
+ assert_eq!(45, a.par_iter().sum::<i32>());
+ assert_eq!(45, a.into_par_iter().sum::<i32>());
+}
+
+#[test]
+fn check_hash_map() {
+ use std::collections::HashMap;
+
+ let mut a: HashMap<i32, i32> = (0..10).map(|i| (i, -i)).collect();
+
+ assert_eq!(45, a.par_iter().map(|(&k, _)| k).sum::<i32>());
+ assert_eq!(-45, a.par_iter().map(|(_, &v)| v).sum::<i32>());
+
+ a.par_iter_mut().for_each(|(k, v)| *v += *k);
+
+ assert_eq!(0, a.into_par_iter().map(|(_, v)| v).sum::<i32>());
+}
+
+#[test]
+fn check_hash_set() {
+ use std::collections::HashSet;
+
+ let a: HashSet<i32> = (0..10).collect();
+
+ assert_eq!(45, a.par_iter().sum::<i32>());
+ assert_eq!(45, a.into_par_iter().sum::<i32>());
+}
+
+#[test]
+fn check_linked_list() {
+ use std::collections::LinkedList;
+
+ let mut a: LinkedList<i32> = (0..10).collect();
+
+ assert_eq!(45, a.par_iter().sum::<i32>());
+
+ a.par_iter_mut().for_each(|x| *x = -*x);
+
+ assert_eq!(-45, a.into_par_iter().sum::<i32>());
+}
+
+#[test]
+fn check_vec_deque() {
+ use std::collections::VecDeque;
+
+ let mut a: VecDeque<i32> = (0..10).collect();
+
+ // try to get it to wrap around
+ a.drain(..5);
+ a.extend(0..5);
+
+ assert_eq!(45, a.par_iter().sum::<i32>());
+
+ a.par_iter_mut().for_each(|x| *x = -*x);
+
+ assert_eq!(-45, a.into_par_iter().sum::<i32>());
+}
+
+#[test]
+fn check_chain() {
+ let mut res = vec![];
+
+ // stays indexed in the face of madness
+ Some(0)
+ .into_par_iter()
+ .chain(Ok::<_, ()>(1))
+ .chain(1..4)
+ .chain(Err("huh?"))
+ .chain(None)
+ .chain(vec![5, 8, 13])
+ .map(|x| (x as u8 + b'a') as char)
+ .chain(vec!['x', 'y', 'z'])
+ .zip((0i32..1000).into_par_iter().map(|x| -x))
+ .enumerate()
+ .map(|(a, (b, c))| (a, b, c))
+ .chain(None)
+ .collect_into_vec(&mut res);
+
+ assert_eq!(
+ res,
+ vec![
+ (0, 'a', 0),
+ (1, 'b', -1),
+ (2, 'b', -2),
+ (3, 'c', -3),
+ (4, 'd', -4),
+ (5, 'f', -5),
+ (6, 'i', -6),
+ (7, 'n', -7),
+ (8, 'x', -8),
+ (9, 'y', -9),
+ (10, 'z', -10)
+ ]
+ );
+
+ // unindexed is ok too
+ let res: Vec<i32> = Some(1i32)
+ .into_par_iter()
+ .chain(
+ (2i32..4)
+ .into_par_iter()
+ .chain(vec![5, 6, 7, 8, 9])
+ .chain(Some((10, 100)).into_par_iter().flat_map(|(a, b)| a..b))
+ .filter(|x| x & 1 == 1),
+ )
+ .collect();
+ let other: Vec<i32> = (0..100).filter(|x| x & 1 == 1).collect();
+ assert_eq!(res, other);
+
+ // chain collect is ok with the "fake" specialization
+ let res: Vec<i32> = Some(1i32).into_par_iter().chain(None).collect();
+ assert_eq!(res, &[1]);
+}
+
+#[test]
+fn check_count() {
+ let c0 = (0_u32..24 * 1024).filter(|i| i % 2 == 0).count();
+ let c1 = (0_u32..24 * 1024)
+ .into_par_iter()
+ .filter(|i| i % 2 == 0)
+ .count();
+ assert_eq!(c0, c1);
+}
+
+#[test]
+fn find_any() {
+ let a: Vec<i32> = (0..1024).collect();
+
+ assert!(a.par_iter().find_any(|&&x| x % 42 == 41).is_some());
+ assert_eq!(
+ a.par_iter().find_any(|&&x| x % 19 == 1 && x % 53 == 0),
+ Some(&742_i32)
+ );
+ assert_eq!(a.par_iter().find_any(|&&x| x < 0), None);
+
+ assert!(a.par_iter().position_any(|&x| x % 42 == 41).is_some());
+ assert_eq!(
+ a.par_iter().position_any(|&x| x % 19 == 1 && x % 53 == 0),
+ Some(742_usize)
+ );
+ assert_eq!(a.par_iter().position_any(|&x| x < 0), None);
+
+ assert!(a.par_iter().any(|&x| x > 1000));
+ assert!(!a.par_iter().any(|&x| x < 0));
+
+ assert!(!a.par_iter().all(|&x| x > 1000));
+ assert!(a.par_iter().all(|&x| x >= 0));
+}
+
+#[test]
+fn find_first_or_last() {
+ let a: Vec<i32> = (0..1024).collect();
+
+ assert_eq!(a.par_iter().find_first(|&&x| x % 42 == 41), Some(&41_i32));
+ assert_eq!(
+ a.par_iter().find_first(|&&x| x % 19 == 1 && x % 53 == 0),
+ Some(&742_i32)
+ );
+ assert_eq!(a.par_iter().find_first(|&&x| x < 0), None);
+
+ assert_eq!(
+ a.par_iter().position_first(|&x| x % 42 == 41),
+ Some(41_usize)
+ );
+ assert_eq!(
+ a.par_iter().position_first(|&x| x % 19 == 1 && x % 53 == 0),
+ Some(742_usize)
+ );
+ assert_eq!(a.par_iter().position_first(|&x| x < 0), None);
+
+ assert_eq!(a.par_iter().find_last(|&&x| x % 42 == 41), Some(&1007_i32));
+ assert_eq!(
+ a.par_iter().find_last(|&&x| x % 19 == 1 && x % 53 == 0),
+ Some(&742_i32)
+ );
+ assert_eq!(a.par_iter().find_last(|&&x| x < 0), None);
+
+ assert_eq!(
+ a.par_iter().position_last(|&x| x % 42 == 41),
+ Some(1007_usize)
+ );
+ assert_eq!(
+ a.par_iter().position_last(|&x| x % 19 == 1 && x % 53 == 0),
+ Some(742_usize)
+ );
+ assert_eq!(a.par_iter().position_last(|&x| x < 0), None);
+}
+
+#[test]
+fn find_map_first_or_last_or_any() {
+ let mut a: Vec<i32> = vec![];
+
+ assert!(a.par_iter().find_map_any(half_if_positive).is_none());
+ assert!(a.par_iter().find_map_first(half_if_positive).is_none());
+ assert!(a.par_iter().find_map_last(half_if_positive).is_none());
+
+ a = (-1024..-3).collect();
+
+ assert!(a.par_iter().find_map_any(half_if_positive).is_none());
+ assert!(a.par_iter().find_map_first(half_if_positive).is_none());
+ assert!(a.par_iter().find_map_last(half_if_positive).is_none());
+
+ assert!(a.par_iter().find_map_any(half_if_negative).is_some());
+ assert_eq!(
+ a.par_iter().find_map_first(half_if_negative),
+ Some(-512_i32)
+ );
+ assert_eq!(a.par_iter().find_map_last(half_if_negative), Some(-2_i32));
+
+ a.append(&mut (2..1025).collect());
+
+ assert!(a.par_iter().find_map_any(half_if_positive).is_some());
+ assert_eq!(a.par_iter().find_map_first(half_if_positive), Some(1_i32));
+ assert_eq!(a.par_iter().find_map_last(half_if_positive), Some(512_i32));
+
+ fn half_if_positive(x: &i32) -> Option<i32> {
+ if *x > 0 {
+ Some(x / 2)
+ } else {
+ None
+ }
+ }
+
+ fn half_if_negative(x: &i32) -> Option<i32> {
+ if *x < 0 {
+ Some(x / 2)
+ } else {
+ None
+ }
+ }
+}
+
+#[test]
+fn check_find_not_present() {
+ let counter = AtomicUsize::new(0);
+ let value: Option<i32> = (0_i32..2048).into_par_iter().find_any(|&p| {
+ counter.fetch_add(1, Ordering::SeqCst);
+ p >= 2048
+ });
+ assert!(value.is_none());
+ assert!(counter.load(Ordering::SeqCst) == 2048); // should have visited every single one
+}
+
+#[test]
+fn check_find_is_present() {
+ let counter = AtomicUsize::new(0);
+ let value: Option<i32> = (0_i32..2048).into_par_iter().find_any(|&p| {
+ counter.fetch_add(1, Ordering::SeqCst);
+ (1024..1096).contains(&p)
+ });
+ let q = value.unwrap();
+ assert!((1024..1096).contains(&q));
+ assert!(counter.load(Ordering::SeqCst) < 2048); // should not have visited every single one
+}
+
+#[test]
+fn check_while_some() {
+ let value = (0_i32..2048).into_par_iter().map(Some).while_some().max();
+ assert_eq!(value, Some(2047));
+
+ let counter = AtomicUsize::new(0);
+ let value = (0_i32..2048)
+ .into_par_iter()
+ .map(|x| {
+ counter.fetch_add(1, Ordering::SeqCst);
+ if x < 1024 {
+ Some(x)
+ } else {
+ None
+ }
+ })
+ .while_some()
+ .max();
+ assert!(value < Some(1024));
+ assert!(counter.load(Ordering::SeqCst) < 2048); // should not have visited every single one
+}
+
+#[test]
+fn par_iter_collect_option() {
+ let a: Option<Vec<_>> = (0_i32..2048).map(Some).collect();
+ let b: Option<Vec<_>> = (0_i32..2048).into_par_iter().map(Some).collect();
+ assert_eq!(a, b);
+
+ let c: Option<Vec<_>> = (0_i32..2048)
+ .into_par_iter()
+ .map(|x| if x == 1234 { None } else { Some(x) })
+ .collect();
+ assert_eq!(c, None);
+}
+
+#[test]
+fn par_iter_collect_result() {
+ let a: Result<Vec<_>, ()> = (0_i32..2048).map(Ok).collect();
+ let b: Result<Vec<_>, ()> = (0_i32..2048).into_par_iter().map(Ok).collect();
+ assert_eq!(a, b);
+
+ let c: Result<Vec<_>, _> = (0_i32..2048)
+ .into_par_iter()
+ .map(|x| if x == 1234 { Err(x) } else { Ok(x) })
+ .collect();
+ assert_eq!(c, Err(1234));
+
+ let d: Result<Vec<_>, _> = (0_i32..2048)
+ .into_par_iter()
+ .map(|x| if x % 100 == 99 { Err(x) } else { Ok(x) })
+ .collect();
+ assert_eq!(d.map_err(|x| x % 100), Err(99));
+}
+
+#[test]
+fn par_iter_collect() {
+ let a: Vec<i32> = (0..1024).collect();
+ let b: Vec<i32> = a.par_iter().map(|&i| i + 1).collect();
+ let c: Vec<i32> = (0..1024).map(|i| i + 1).collect();
+ assert_eq!(b, c);
+}
+
+#[test]
+fn par_iter_collect_vecdeque() {
+ let a: Vec<i32> = (0..1024).collect();
+ let b: VecDeque<i32> = a.par_iter().cloned().collect();
+ let c: VecDeque<i32> = a.iter().cloned().collect();
+ assert_eq!(b, c);
+}
+
+#[test]
+fn par_iter_collect_binaryheap() {
+ let a: Vec<i32> = (0..1024).collect();
+ let mut b: BinaryHeap<i32> = a.par_iter().cloned().collect();
+ assert_eq!(b.peek(), Some(&1023));
+ assert_eq!(b.len(), 1024);
+ for n in (0..1024).rev() {
+ assert_eq!(b.pop(), Some(n));
+ assert_eq!(b.len() as i32, n);
+ }
+}
+
+#[test]
+fn par_iter_collect_hashmap() {
+ let a: Vec<i32> = (0..1024).collect();
+ let b: HashMap<i32, String> = a.par_iter().map(|&i| (i, format!("{}", i))).collect();
+ assert_eq!(&b[&3], "3");
+ assert_eq!(b.len(), 1024);
+}
+
+#[test]
+fn par_iter_collect_hashset() {
+ let a: Vec<i32> = (0..1024).collect();
+ let b: HashSet<i32> = a.par_iter().cloned().collect();
+ assert_eq!(b.len(), 1024);
+}
+
+#[test]
+fn par_iter_collect_btreemap() {
+ let a: Vec<i32> = (0..1024).collect();
+ let b: BTreeMap<i32, String> = a.par_iter().map(|&i| (i, format!("{}", i))).collect();
+ assert_eq!(&b[&3], "3");
+ assert_eq!(b.len(), 1024);
+}
+
+#[test]
+fn par_iter_collect_btreeset() {
+ let a: Vec<i32> = (0..1024).collect();
+ let b: BTreeSet<i32> = a.par_iter().cloned().collect();
+ assert_eq!(b.len(), 1024);
+}
+
+#[test]
+fn par_iter_collect_linked_list() {
+ let a: Vec<i32> = (0..1024).collect();
+ let b: LinkedList<_> = a.par_iter().map(|&i| (i, format!("{}", i))).collect();
+ let c: LinkedList<_> = a.iter().map(|&i| (i, format!("{}", i))).collect();
+ assert_eq!(b, c);
+}
+
+#[test]
+fn par_iter_collect_linked_list_flat_map_filter() {
+ let b: LinkedList<i32> = (0_i32..1024)
+ .into_par_iter()
+ .flat_map(|i| (0..i))
+ .filter(|&i| i % 2 == 0)
+ .collect();
+ let c: LinkedList<i32> = (0_i32..1024)
+ .flat_map(|i| (0..i))
+ .filter(|&i| i % 2 == 0)
+ .collect();
+ assert_eq!(b, c);
+}
+
+#[test]
+fn par_iter_collect_cows() {
+ use std::borrow::Cow;
+
+ let s = "Fearless Concurrency with Rust";
+
+ // Collects `i32` into a `Vec`
+ let a: Cow<'_, [i32]> = (0..1024).collect();
+ let b: Cow<'_, [i32]> = a.par_iter().cloned().collect();
+ assert_eq!(a, b);
+
+ // Collects `char` into a `String`
+ let a: Cow<'_, str> = s.chars().collect();
+ let b: Cow<'_, str> = s.par_chars().collect();
+ assert_eq!(a, b);
+
+ // Collects `str` into a `String`
+ let a: Cow<'_, str> = s.split_whitespace().collect();
+ let b: Cow<'_, str> = s.par_split_whitespace().collect();
+ assert_eq!(a, b);
+
+ // Collects `String` into a `String`
+ let a: Cow<'_, str> = s.split_whitespace().map(str::to_owned).collect();
+ let b: Cow<'_, str> = s.par_split_whitespace().map(str::to_owned).collect();
+ assert_eq!(a, b);
+}
+
+#[test]
+fn par_iter_unindexed_flat_map() {
+ let b: Vec<i64> = (0_i64..1024).into_par_iter().flat_map(Some).collect();
+ let c: Vec<i64> = (0_i64..1024).flat_map(Some).collect();
+ assert_eq!(b, c);
+}
+
+#[test]
+fn min_max() {
+ let rng = seeded_rng();
+ let a: Vec<i32> = rng.sample_iter(&Standard).take(1024).collect();
+ for i in 0..=a.len() {
+ let slice = &a[..i];
+ assert_eq!(slice.par_iter().min(), slice.iter().min());
+ assert_eq!(slice.par_iter().max(), slice.iter().max());
+ }
+}
+
+#[test]
+fn min_max_by() {
+ let rng = seeded_rng();
+ // Make sure there are duplicate keys, for testing sort stability
+ let r: Vec<i32> = rng.sample_iter(&Standard).take(512).collect();
+ let a: Vec<(i32, u16)> = r.iter().chain(&r).cloned().zip(0..).collect();
+ for i in 0..=a.len() {
+ let slice = &a[..i];
+ assert_eq!(
+ slice.par_iter().min_by(|x, y| x.0.cmp(&y.0)),
+ slice.iter().min_by(|x, y| x.0.cmp(&y.0))
+ );
+ assert_eq!(
+ slice.par_iter().max_by(|x, y| x.0.cmp(&y.0)),
+ slice.iter().max_by(|x, y| x.0.cmp(&y.0))
+ );
+ }
+}
+
+#[test]
+fn min_max_by_key() {
+ let rng = seeded_rng();
+ // Make sure there are duplicate keys, for testing sort stability
+ let r: Vec<i32> = rng.sample_iter(&Standard).take(512).collect();
+ let a: Vec<(i32, u16)> = r.iter().chain(&r).cloned().zip(0..).collect();
+ for i in 0..=a.len() {
+ let slice = &a[..i];
+ assert_eq!(
+ slice.par_iter().min_by_key(|x| x.0),
+ slice.iter().min_by_key(|x| x.0)
+ );
+ assert_eq!(
+ slice.par_iter().max_by_key(|x| x.0),
+ slice.iter().max_by_key(|x| x.0)
+ );
+ }
+}
+
+#[test]
+fn check_rev() {
+ let a: Vec<usize> = (0..1024).rev().collect();
+ let b: Vec<usize> = (0..1024).collect();
+
+ assert!(a.par_iter().rev().zip(b).all(|(&a, b)| a == b));
+}
+
+#[test]
+fn scope_mix() {
+ let counter_p = &AtomicUsize::new(0);
+ scope(|s| {
+ s.spawn(move |s| {
+ divide_and_conquer(s, counter_p, 1024);
+ });
+ s.spawn(move |_| {
+ let a: Vec<i32> = (0..1024).collect();
+ let r1 = a.par_iter().map(|&i| i + 1).reduce_with(|i, j| i + j);
+ let r2 = a.iter().map(|&i| i + 1).sum();
+ assert_eq!(r1.unwrap(), r2);
+ });
+ });
+}
+
+fn divide_and_conquer<'scope>(scope: &Scope<'scope>, counter: &'scope AtomicUsize, size: usize) {
+ if size > 1 {
+ scope.spawn(move |scope| divide_and_conquer(scope, counter, size / 2));
+ scope.spawn(move |scope| divide_and_conquer(scope, counter, size / 2));
+ } else {
+ // count the leaves
+ counter.fetch_add(1, Ordering::SeqCst);
+ }
+}
+
+#[test]
+fn check_split() {
+ use std::ops::Range;
+
+ let a = (0..1024).into_par_iter();
+
+ let b = split(0..1024, |Range { start, end }| {
+ let mid = (end - start) / 2;
+ if mid > start {
+ (start..mid, Some(mid..end))
+ } else {
+ (start..end, None)
+ }
+ })
+ .flat_map(|range| range);
+
+ assert_eq!(a.collect::<Vec<_>>(), b.collect::<Vec<_>>());
+}
+
+#[test]
+fn check_lengths() {
+ fn check(min: usize, max: usize) {
+ let range = 0..1024 * 1024;
+
+ // Check against normalized values.
+ let min_check = cmp::min(cmp::max(min, 1), range.len());
+ let max_check = cmp::max(max, min_check.saturating_add(min_check - 1));
+
+ assert!(
+ range
+ .into_par_iter()
+ .with_min_len(min)
+ .with_max_len(max)
+ .fold(|| 0, |count, _| count + 1)
+ .all(|c| c >= min_check && c <= max_check),
+ "check_lengths failed {:?} -> {:?} ",
+ (min, max),
+ (min_check, max_check)
+ );
+ }
+
+ let lengths = [0, 1, 10, 100, 1_000, 10_000, 100_000, 1_000_000, usize::MAX];
+ for &min in &lengths {
+ for &max in &lengths {
+ check(min, max);
+ }
+ }
+}
+
+#[test]
+fn check_map_with() {
+ let (sender, receiver) = mpsc::channel();
+ let a: HashSet<_> = (0..1024).collect();
+
+ a.par_iter()
+ .cloned()
+ .map_with(sender, |s, i| s.send(i).unwrap())
+ .count();
+
+ let b: HashSet<_> = receiver.iter().collect();
+ assert_eq!(a, b);
+}
+
+#[test]
+fn check_fold_with() {
+ let (sender, receiver) = mpsc::channel();
+ let a: HashSet<_> = (0..1024).collect();
+
+ a.par_iter()
+ .cloned()
+ .fold_with(sender, |s, i| {
+ s.send(i).unwrap();
+ s
+ })
+ .count();
+
+ let b: HashSet<_> = receiver.iter().collect();
+ assert_eq!(a, b);
+}
+
+#[test]
+fn check_for_each_with() {
+ let (sender, receiver) = mpsc::channel();
+ let a: HashSet<_> = (0..1024).collect();
+
+ a.par_iter()
+ .cloned()
+ .for_each_with(sender, |s, i| s.send(i).unwrap());
+
+ let b: HashSet<_> = receiver.iter().collect();
+ assert_eq!(a, b);
+}
+
+#[test]
+fn check_extend_items() {
+ fn check<C>()
+ where
+ C: Default
+ + Eq
+ + Debug
+ + Extend<i32>
+ + for<'a> Extend<&'a i32>
+ + ParallelExtend<i32>
+ + for<'a> ParallelExtend<&'a i32>,
+ {
+ let mut serial = C::default();
+ let mut parallel = C::default();
+
+ // extend with references
+ let v: Vec<_> = (0..128).collect();
+ serial.extend(&v);
+ parallel.par_extend(&v);
+ assert_eq!(serial, parallel);
+
+ // extend with values
+ serial.extend(-128..0);
+ parallel.par_extend(-128..0);
+ assert_eq!(serial, parallel);
+ }
+
+ check::<BTreeSet<_>>();
+ check::<HashSet<_>>();
+ check::<LinkedList<_>>();
+ check::<Vec<_>>();
+ check::<VecDeque<_>>();
+}
+
+#[test]
+fn check_extend_heap() {
+ let mut serial: BinaryHeap<_> = Default::default();
+ let mut parallel: BinaryHeap<_> = Default::default();
+
+ // extend with references
+ let v: Vec<_> = (0..128).collect();
+ serial.extend(&v);
+ parallel.par_extend(&v);
+ assert_eq!(
+ serial.clone().into_sorted_vec(),
+ parallel.clone().into_sorted_vec()
+ );
+
+ // extend with values
+ serial.extend(-128..0);
+ parallel.par_extend(-128..0);
+ assert_eq!(serial.into_sorted_vec(), parallel.into_sorted_vec());
+}
+
+#[test]
+fn check_extend_pairs() {
+ fn check<C>()
+ where
+ C: Default
+ + Eq
+ + Debug
+ + Extend<(usize, i32)>
+ + for<'a> Extend<(&'a usize, &'a i32)>
+ + ParallelExtend<(usize, i32)>
+ + for<'a> ParallelExtend<(&'a usize, &'a i32)>,
+ {
+ let mut serial = C::default();
+ let mut parallel = C::default();
+
+ // extend with references
+ let m: HashMap<_, _> = (0..128).enumerate().collect();
+ serial.extend(&m);
+ parallel.par_extend(&m);
+ assert_eq!(serial, parallel);
+
+ // extend with values
+ let v: Vec<(_, _)> = (-128..0).enumerate().collect();
+ serial.extend(v.clone());
+ parallel.par_extend(v);
+ assert_eq!(serial, parallel);
+ }
+
+ check::<BTreeMap<usize, i32>>();
+ check::<HashMap<usize, i32>>();
+}
+
+#[test]
+fn check_unzip_into_vecs() {
+ let mut a = vec![];
+ let mut b = vec![];
+ (0..1024)
+ .into_par_iter()
+ .map(|i| i * i)
+ .enumerate()
+ .unzip_into_vecs(&mut a, &mut b);
+
+ let (c, d): (Vec<_>, Vec<_>) = (0..1024).map(|i| i * i).enumerate().unzip();
+ assert_eq!(a, c);
+ assert_eq!(b, d);
+}
+
+#[test]
+fn check_unzip() {
+ // indexed, unindexed
+ let (a, b): (Vec<_>, HashSet<_>) = (0..1024).into_par_iter().map(|i| i * i).enumerate().unzip();
+ let (c, d): (Vec<_>, HashSet<_>) = (0..1024).map(|i| i * i).enumerate().unzip();
+ assert_eq!(a, c);
+ assert_eq!(b, d);
+
+ // unindexed, indexed
+ let (a, b): (HashSet<_>, Vec<_>) = (0..1024).into_par_iter().map(|i| i * i).enumerate().unzip();
+ let (c, d): (HashSet<_>, Vec<_>) = (0..1024).map(|i| i * i).enumerate().unzip();
+ assert_eq!(a, c);
+ assert_eq!(b, d);
+
+ // indexed, indexed
+ let (a, b): (Vec<_>, Vec<_>) = (0..1024).into_par_iter().map(|i| i * i).enumerate().unzip();
+ let (c, d): (Vec<_>, Vec<_>) = (0..1024).map(|i| i * i).enumerate().unzip();
+ assert_eq!(a, c);
+ assert_eq!(b, d);
+
+ // unindexed producer
+ let (a, b): (Vec<_>, Vec<_>) = (0..1024)
+ .into_par_iter()
+ .filter_map(|i| Some((i, i * i)))
+ .unzip();
+ let (c, d): (Vec<_>, Vec<_>) = (0..1024).map(|i| (i, i * i)).unzip();
+ assert_eq!(a, c);
+ assert_eq!(b, d);
+}
+
+#[test]
+fn check_partition() {
+ let (a, b): (Vec<_>, Vec<_>) = (0..1024).into_par_iter().partition(|&i| i % 3 == 0);
+ let (c, d): (Vec<_>, Vec<_>) = (0..1024).partition(|&i| i % 3 == 0);
+ assert_eq!(a, c);
+ assert_eq!(b, d);
+}
+
+#[test]
+fn check_partition_map() {
+ let input = "a b c 1 2 3 x y z";
+ let (a, b): (Vec<_>, String) =
+ input
+ .par_split_whitespace()
+ .partition_map(|s| match s.parse::<i32>() {
+ Ok(n) => Either::Left(n),
+ Err(_) => Either::Right(s),
+ });
+ assert_eq!(a, vec![1, 2, 3]);
+ assert_eq!(b, "abcxyz");
+}
+
+#[test]
+fn check_either() {
+ type I = crate::vec::IntoIter<i32>;
+ type E = Either<I, I>;
+
+ let v: Vec<i32> = (0..1024).collect();
+
+ // try iterating the left side
+ let left: E = Either::Left(v.clone().into_par_iter());
+ assert!(left.eq(v.clone()));
+
+ // try iterating the right side
+ let right: E = Either::Right(v.clone().into_par_iter());
+ assert!(right.eq(v.clone()));
+
+ // try an indexed iterator
+ let left: E = Either::Left(v.clone().into_par_iter());
+ assert!(left.enumerate().eq(v.into_par_iter().enumerate()));
+}
+
+#[test]
+fn check_either_extend() {
+ type E = Either<Vec<i32>, HashSet<i32>>;
+
+ let v: Vec<i32> = (0..1024).collect();
+
+ // try extending the left side
+ let mut left: E = Either::Left(vec![]);
+ left.par_extend(v.clone());
+ assert_eq!(left.as_ref(), Either::Left(&v));
+
+ // try extending the right side
+ let mut right: E = Either::Right(HashSet::default());
+ right.par_extend(v.clone());
+ assert_eq!(right, Either::Right(v.iter().cloned().collect()));
+}
+
+#[test]
+fn check_interleave_eq() {
+ let xs: Vec<usize> = (0..10).collect();
+ let ys: Vec<usize> = (10..20).collect();
+
+ let mut actual = vec![];
+ xs.par_iter()
+ .interleave(&ys)
+ .map(|&i| i)
+ .collect_into_vec(&mut actual);
+
+ let expected: Vec<usize> = (0..10)
+ .zip(10..20)
+ .flat_map(|(i, j)| vec![i, j].into_iter())
+ .collect();
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn check_interleave_uneven() {
+ let cases: Vec<(Vec<usize>, Vec<usize>, Vec<usize>)> = vec![
+ (
+ (0..9).collect(),
+ vec![10],
+ vec![0, 10, 1, 2, 3, 4, 5, 6, 7, 8],
+ ),
+ (
+ vec![10],
+ (0..9).collect(),
+ vec![10, 0, 1, 2, 3, 4, 5, 6, 7, 8],
+ ),
+ (
+ (0..5).collect(),
+ (5..10).collect(),
+ (0..5)
+ .zip(5..10)
+ .flat_map(|(i, j)| vec![i, j].into_iter())
+ .collect(),
+ ),
+ (vec![], (0..9).collect(), (0..9).collect()),
+ ((0..9).collect(), vec![], (0..9).collect()),
+ (
+ (0..50).collect(),
+ (50..100).collect(),
+ (0..50)
+ .zip(50..100)
+ .flat_map(|(i, j)| vec![i, j].into_iter())
+ .collect(),
+ ),
+ ];
+
+ for (i, (xs, ys, expected)) in cases.into_iter().enumerate() {
+ let mut res = vec![];
+ xs.par_iter()
+ .interleave(&ys)
+ .map(|&i| i)
+ .collect_into_vec(&mut res);
+ assert_eq!(expected, res, "Case {} failed", i);
+
+ res.truncate(0);
+ xs.par_iter()
+ .interleave(&ys)
+ .rev()
+ .map(|&i| i)
+ .collect_into_vec(&mut res);
+ assert_eq!(
+ expected.into_iter().rev().collect::<Vec<usize>>(),
+ res,
+ "Case {} reversed failed",
+ i
+ );
+ }
+}
+
+#[test]
+fn check_interleave_shortest() {
+ let cases: Vec<(Vec<usize>, Vec<usize>, Vec<usize>)> = vec![
+ ((0..9).collect(), vec![10], vec![0, 10, 1]),
+ (vec![10], (0..9).collect(), vec![10, 0]),
+ (
+ (0..5).collect(),
+ (5..10).collect(),
+ (0..5)
+ .zip(5..10)
+ .flat_map(|(i, j)| vec![i, j].into_iter())
+ .collect(),
+ ),
+ (vec![], (0..9).collect(), vec![]),
+ ((0..9).collect(), vec![], vec![0]),
+ (
+ (0..50).collect(),
+ (50..100).collect(),
+ (0..50)
+ .zip(50..100)
+ .flat_map(|(i, j)| vec![i, j].into_iter())
+ .collect(),
+ ),
+ ];
+
+ for (i, (xs, ys, expected)) in cases.into_iter().enumerate() {
+ let mut res = vec![];
+ xs.par_iter()
+ .interleave_shortest(&ys)
+ .map(|&i| i)
+ .collect_into_vec(&mut res);
+ assert_eq!(expected, res, "Case {} failed", i);
+
+ res.truncate(0);
+ xs.par_iter()
+ .interleave_shortest(&ys)
+ .rev()
+ .map(|&i| i)
+ .collect_into_vec(&mut res);
+ assert_eq!(
+ expected.into_iter().rev().collect::<Vec<usize>>(),
+ res,
+ "Case {} reversed failed",
+ i
+ );
+ }
+}
+
+#[test]
+#[should_panic(expected = "chunk_size must not be zero")]
+fn check_chunks_zero_size() {
+ let _: Vec<Vec<i32>> = vec![1, 2, 3].into_par_iter().chunks(0).collect();
+}
+
+#[test]
+fn check_chunks_even_size() {
+ assert_eq!(
+ vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]],
+ (1..10).into_par_iter().chunks(3).collect::<Vec<Vec<i32>>>()
+ );
+}
+
+#[test]
+fn check_chunks_empty() {
+ let v: Vec<i32> = vec![];
+ let expected: Vec<Vec<i32>> = vec![];
+ assert_eq!(
+ expected,
+ v.into_par_iter().chunks(2).collect::<Vec<Vec<i32>>>()
+ );
+}
+
+#[test]
+fn check_chunks_len() {
+ assert_eq!(4, (0..8).into_par_iter().chunks(2).len());
+ assert_eq!(3, (0..9).into_par_iter().chunks(3).len());
+ assert_eq!(3, (0..8).into_par_iter().chunks(3).len());
+ assert_eq!(1, [1].par_iter().chunks(3).len());
+ assert_eq!(0, (0..0).into_par_iter().chunks(3).len());
+}
+
+#[test]
+fn check_chunks_uneven() {
+ let cases: Vec<(Vec<u32>, usize, Vec<Vec<u32>>)> = vec![
+ ((0..5).collect(), 3, vec![vec![0, 1, 2], vec![3, 4]]),
+ (vec![1], 5, vec![vec![1]]),
+ ((0..4).collect(), 3, vec![vec![0, 1, 2], vec![3]]),
+ ];
+
+ for (i, (v, n, expected)) in cases.into_iter().enumerate() {
+ let mut res: Vec<Vec<u32>> = vec![];
+ v.par_iter()
+ .chunks(n)
+ .map(|v| v.into_iter().cloned().collect())
+ .collect_into_vec(&mut res);
+ assert_eq!(expected, res, "Case {} failed", i);
+
+ res.truncate(0);
+ v.into_par_iter().chunks(n).rev().collect_into_vec(&mut res);
+ assert_eq!(
+ expected.into_iter().rev().collect::<Vec<Vec<u32>>>(),
+ res,
+ "Case {} reversed failed",
+ i
+ );
+ }
+}
+
+#[test]
+#[ignore] // it's quick enough on optimized 32-bit platforms, but otherwise... ... ...
+#[should_panic(expected = "overflow")]
+#[cfg(debug_assertions)]
+fn check_repeat_unbounded() {
+ // use just one thread, so we don't get infinite adaptive splitting
+ // (forever stealing and re-splitting jobs that will panic on overflow)
+ let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
+ pool.install(|| {
+ println!("counted {} repeats", repeat(()).count());
+ });
+}
+
+#[test]
+fn check_repeat_find_any() {
+ let even = repeat(4).find_any(|&x| x % 2 == 0);
+ assert_eq!(even, Some(4));
+}
+
+#[test]
+fn check_repeat_take() {
+ let v: Vec<_> = repeat(4).take(4).collect();
+ assert_eq!(v, [4, 4, 4, 4]);
+}
+
+#[test]
+fn check_repeat_zip() {
+ let v = vec![4, 4, 4, 4];
+ let mut fours: Vec<_> = repeat(4).zip(v).collect();
+ assert_eq!(fours.len(), 4);
+ while let Some(item) = fours.pop() {
+ assert_eq!(item, (4, 4));
+ }
+}
+
+#[test]
+fn check_repeatn_zip_left() {
+ let v = vec![4, 4, 4, 4];
+ let mut fours: Vec<_> = repeatn(4, usize::MAX).zip(v).collect();
+ assert_eq!(fours.len(), 4);
+ while let Some(item) = fours.pop() {
+ assert_eq!(item, (4, 4));
+ }
+}
+
+#[test]
+fn check_repeatn_zip_right() {
+ let v = vec![4, 4, 4, 4];
+ let mut fours: Vec<_> = v.into_par_iter().zip(repeatn(4, usize::MAX)).collect();
+ assert_eq!(fours.len(), 4);
+ while let Some(item) = fours.pop() {
+ assert_eq!(item, (4, 4));
+ }
+}
+
+#[test]
+fn check_empty() {
+ // drive_unindexed
+ let mut v: Vec<i32> = empty().filter(|_| unreachable!()).collect();
+ assert!(v.is_empty());
+
+ // drive (indexed)
+ empty().collect_into_vec(&mut v);
+ assert!(v.is_empty());
+
+ // with_producer
+ let v: Vec<(i32, i32)> = empty().zip(1..10).collect();
+ assert!(v.is_empty());
+}
+
+#[test]
+fn check_once() {
+ // drive_unindexed
+ let mut v: Vec<i32> = once(42).filter(|_| true).collect();
+ assert_eq!(v, &[42]);
+
+ // drive (indexed)
+ once(42).collect_into_vec(&mut v);
+ assert_eq!(v, &[42]);
+
+ // with_producer
+ let v: Vec<(i32, i32)> = once(42).zip(1..10).collect();
+ assert_eq!(v, &[(42, 1)]);
+}
+
+#[test]
+fn check_update() {
+ let mut v: Vec<Vec<_>> = vec![vec![1], vec![3, 2, 1]];
+ v.par_iter_mut().update(|v| v.push(0)).for_each(|_| ());
+
+ assert_eq!(v, vec![vec![1, 0], vec![3, 2, 1, 0]]);
+}
diff --git a/third_party/rust/rayon/src/iter/try_fold.rs b/third_party/rust/rayon/src/iter/try_fold.rs
new file mode 100644
index 0000000000..6d1048d75d
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/try_fold.rs
@@ -0,0 +1,298 @@
+use super::plumbing::*;
+use super::ParallelIterator;
+use super::Try;
+
+use std::fmt::{self, Debug};
+use std::marker::PhantomData;
+use std::ops::ControlFlow::{self, Break, Continue};
+
+impl<U, I, ID, F> TryFold<I, U, ID, F>
+where
+ I: ParallelIterator,
+ F: Fn(U::Output, I::Item) -> U + Sync + Send,
+ ID: Fn() -> U::Output + Sync + Send,
+ U: Try + Send,
+{
+ pub(super) fn new(base: I, identity: ID, fold_op: F) -> Self {
+ TryFold {
+ base,
+ identity,
+ fold_op,
+ marker: PhantomData,
+ }
+ }
+}
+
+/// `TryFold` is an iterator that applies a function over an iterator producing a single value.
+/// This struct is created by the [`try_fold()`] method on [`ParallelIterator`]
+///
+/// [`try_fold()`]: trait.ParallelIterator.html#method.try_fold
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct TryFold<I, U, ID, F> {
+ base: I,
+ identity: ID,
+ fold_op: F,
+ marker: PhantomData<U>,
+}
+
+impl<U, I: ParallelIterator + Debug, ID, F> Debug for TryFold<I, U, ID, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("TryFold").field("base", &self.base).finish()
+ }
+}
+
+impl<U, I, ID, F> ParallelIterator for TryFold<I, U, ID, F>
+where
+ I: ParallelIterator,
+ F: Fn(U::Output, I::Item) -> U + Sync + Send,
+ ID: Fn() -> U::Output + Sync + Send,
+ U: Try + Send,
+{
+ type Item = U;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = TryFoldConsumer {
+ base: consumer,
+ identity: &self.identity,
+ fold_op: &self.fold_op,
+ marker: PhantomData,
+ };
+ self.base.drive_unindexed(consumer1)
+ }
+}
+
+struct TryFoldConsumer<'c, U, C, ID, F> {
+ base: C,
+ identity: &'c ID,
+ fold_op: &'c F,
+ marker: PhantomData<U>,
+}
+
+impl<'r, U, T, C, ID, F> Consumer<T> for TryFoldConsumer<'r, U, C, ID, F>
+where
+ C: Consumer<U>,
+ F: Fn(U::Output, T) -> U + Sync,
+ ID: Fn() -> U::Output + Sync,
+ U: Try + Send,
+{
+ type Folder = TryFoldFolder<'r, C::Folder, U, F>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ TryFoldConsumer { base: left, ..self },
+ TryFoldConsumer {
+ base: right,
+ ..self
+ },
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ TryFoldFolder {
+ base: self.base.into_folder(),
+ control: Continue((self.identity)()),
+ fold_op: self.fold_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'r, U, T, C, ID, F> UnindexedConsumer<T> for TryFoldConsumer<'r, U, C, ID, F>
+where
+ C: UnindexedConsumer<U>,
+ F: Fn(U::Output, T) -> U + Sync,
+ ID: Fn() -> U::Output + Sync,
+ U: Try + Send,
+{
+ fn split_off_left(&self) -> Self {
+ TryFoldConsumer {
+ base: self.base.split_off_left(),
+ ..*self
+ }
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct TryFoldFolder<'r, C, U: Try, F> {
+ base: C,
+ fold_op: &'r F,
+ control: ControlFlow<U::Residual, U::Output>,
+}
+
+impl<'r, C, U, F, T> Folder<T> for TryFoldFolder<'r, C, U, F>
+where
+ C: Folder<U>,
+ F: Fn(U::Output, T) -> U + Sync,
+ U: Try,
+{
+ type Result = C::Result;
+
+ fn consume(mut self, item: T) -> Self {
+ let fold_op = self.fold_op;
+ if let Continue(acc) = self.control {
+ self.control = fold_op(acc, item).branch();
+ }
+ self
+ }
+
+ fn complete(self) -> C::Result {
+ let item = match self.control {
+ Continue(c) => U::from_output(c),
+ Break(r) => U::from_residual(r),
+ };
+ self.base.consume(item).complete()
+ }
+
+ fn full(&self) -> bool {
+ match self.control {
+ Break(_) => true,
+ _ => self.base.full(),
+ }
+ }
+}
+
+// ///////////////////////////////////////////////////////////////////////////
+
+impl<U, I, F> TryFoldWith<I, U, F>
+where
+ I: ParallelIterator,
+ F: Fn(U::Output, I::Item) -> U + Sync,
+ U: Try + Send,
+ U::Output: Clone + Send,
+{
+ pub(super) fn new(base: I, item: U::Output, fold_op: F) -> Self {
+ TryFoldWith {
+ base,
+ item,
+ fold_op,
+ }
+ }
+}
+
+/// `TryFoldWith` is an iterator that applies a function over an iterator producing a single value.
+/// This struct is created by the [`try_fold_with()`] method on [`ParallelIterator`]
+///
+/// [`try_fold_with()`]: trait.ParallelIterator.html#method.try_fold_with
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct TryFoldWith<I, U: Try, F> {
+ base: I,
+ item: U::Output,
+ fold_op: F,
+}
+
+impl<I: ParallelIterator + Debug, U: Try, F> Debug for TryFoldWith<I, U, F>
+where
+ U::Output: Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("TryFoldWith")
+ .field("base", &self.base)
+ .field("item", &self.item)
+ .finish()
+ }
+}
+
+impl<U, I, F> ParallelIterator for TryFoldWith<I, U, F>
+where
+ I: ParallelIterator,
+ F: Fn(U::Output, I::Item) -> U + Sync + Send,
+ U: Try + Send,
+ U::Output: Clone + Send,
+{
+ type Item = U;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = TryFoldWithConsumer {
+ base: consumer,
+ item: self.item,
+ fold_op: &self.fold_op,
+ };
+ self.base.drive_unindexed(consumer1)
+ }
+}
+
+struct TryFoldWithConsumer<'c, C, U: Try, F> {
+ base: C,
+ item: U::Output,
+ fold_op: &'c F,
+}
+
+impl<'r, U, T, C, F> Consumer<T> for TryFoldWithConsumer<'r, C, U, F>
+where
+ C: Consumer<U>,
+ F: Fn(U::Output, T) -> U + Sync,
+ U: Try + Send,
+ U::Output: Clone + Send,
+{
+ type Folder = TryFoldFolder<'r, C::Folder, U, F>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ TryFoldWithConsumer {
+ base: left,
+ item: self.item.clone(),
+ ..self
+ },
+ TryFoldWithConsumer {
+ base: right,
+ ..self
+ },
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ TryFoldFolder {
+ base: self.base.into_folder(),
+ control: Continue(self.item),
+ fold_op: self.fold_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'r, U, T, C, F> UnindexedConsumer<T> for TryFoldWithConsumer<'r, C, U, F>
+where
+ C: UnindexedConsumer<U>,
+ F: Fn(U::Output, T) -> U + Sync,
+ U: Try + Send,
+ U::Output: Clone + Send,
+{
+ fn split_off_left(&self) -> Self {
+ TryFoldWithConsumer {
+ base: self.base.split_off_left(),
+ item: self.item.clone(),
+ ..*self
+ }
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/try_reduce.rs b/third_party/rust/rayon/src/iter/try_reduce.rs
new file mode 100644
index 0000000000..35a724c94f
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/try_reduce.rs
@@ -0,0 +1,131 @@
+use super::plumbing::*;
+use super::ParallelIterator;
+use super::Try;
+
+use std::ops::ControlFlow::{self, Break, Continue};
+use std::sync::atomic::{AtomicBool, Ordering};
+
+pub(super) fn try_reduce<PI, R, ID, T>(pi: PI, identity: ID, reduce_op: R) -> T
+where
+ PI: ParallelIterator<Item = T>,
+ R: Fn(T::Output, T::Output) -> T + Sync,
+ ID: Fn() -> T::Output + Sync,
+ T: Try + Send,
+{
+ let full = AtomicBool::new(false);
+ let consumer = TryReduceConsumer {
+ identity: &identity,
+ reduce_op: &reduce_op,
+ full: &full,
+ };
+ pi.drive_unindexed(consumer)
+}
+
+struct TryReduceConsumer<'r, R, ID> {
+ identity: &'r ID,
+ reduce_op: &'r R,
+ full: &'r AtomicBool,
+}
+
+impl<'r, R, ID> Copy for TryReduceConsumer<'r, R, ID> {}
+
+impl<'r, R, ID> Clone for TryReduceConsumer<'r, R, ID> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<'r, R, ID, T> Consumer<T> for TryReduceConsumer<'r, R, ID>
+where
+ R: Fn(T::Output, T::Output) -> T + Sync,
+ ID: Fn() -> T::Output + Sync,
+ T: Try + Send,
+{
+ type Folder = TryReduceFolder<'r, R, T>;
+ type Reducer = Self;
+ type Result = T;
+
+ fn split_at(self, _index: usize) -> (Self, Self, Self) {
+ (self, self, self)
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ TryReduceFolder {
+ reduce_op: self.reduce_op,
+ control: Continue((self.identity)()),
+ full: self.full,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.full.load(Ordering::Relaxed)
+ }
+}
+
+impl<'r, R, ID, T> UnindexedConsumer<T> for TryReduceConsumer<'r, R, ID>
+where
+ R: Fn(T::Output, T::Output) -> T + Sync,
+ ID: Fn() -> T::Output + Sync,
+ T: Try + Send,
+{
+ fn split_off_left(&self) -> Self {
+ *self
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ *self
+ }
+}
+
+impl<'r, R, ID, T> Reducer<T> for TryReduceConsumer<'r, R, ID>
+where
+ R: Fn(T::Output, T::Output) -> T + Sync,
+ T: Try,
+{
+ fn reduce(self, left: T, right: T) -> T {
+ match (left.branch(), right.branch()) {
+ (Continue(left), Continue(right)) => (self.reduce_op)(left, right),
+ (Break(r), _) | (_, Break(r)) => T::from_residual(r),
+ }
+ }
+}
+
+struct TryReduceFolder<'r, R, T: Try> {
+ reduce_op: &'r R,
+ control: ControlFlow<T::Residual, T::Output>,
+ full: &'r AtomicBool,
+}
+
+impl<'r, R, T> Folder<T> for TryReduceFolder<'r, R, T>
+where
+ R: Fn(T::Output, T::Output) -> T,
+ T: Try,
+{
+ type Result = T;
+
+ fn consume(mut self, item: T) -> Self {
+ let reduce_op = self.reduce_op;
+ self.control = match (self.control, item.branch()) {
+ (Continue(left), Continue(right)) => reduce_op(left, right).branch(),
+ (control @ Break(_), _) | (_, control @ Break(_)) => control,
+ };
+ if let Break(_) = self.control {
+ self.full.store(true, Ordering::Relaxed);
+ }
+ self
+ }
+
+ fn complete(self) -> T {
+ match self.control {
+ Continue(c) => T::from_output(c),
+ Break(r) => T::from_residual(r),
+ }
+ }
+
+ fn full(&self) -> bool {
+ match self.control {
+ Break(_) => true,
+ _ => self.full.load(Ordering::Relaxed),
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/try_reduce_with.rs b/third_party/rust/rayon/src/iter/try_reduce_with.rs
new file mode 100644
index 0000000000..cd7c83e272
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/try_reduce_with.rs
@@ -0,0 +1,132 @@
+use super::plumbing::*;
+use super::ParallelIterator;
+use super::Try;
+
+use std::ops::ControlFlow::{self, Break, Continue};
+use std::sync::atomic::{AtomicBool, Ordering};
+
+pub(super) fn try_reduce_with<PI, R, T>(pi: PI, reduce_op: R) -> Option<T>
+where
+ PI: ParallelIterator<Item = T>,
+ R: Fn(T::Output, T::Output) -> T + Sync,
+ T: Try + Send,
+{
+ let full = AtomicBool::new(false);
+ let consumer = TryReduceWithConsumer {
+ reduce_op: &reduce_op,
+ full: &full,
+ };
+ pi.drive_unindexed(consumer)
+}
+
+struct TryReduceWithConsumer<'r, R> {
+ reduce_op: &'r R,
+ full: &'r AtomicBool,
+}
+
+impl<'r, R> Copy for TryReduceWithConsumer<'r, R> {}
+
+impl<'r, R> Clone for TryReduceWithConsumer<'r, R> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<'r, R, T> Consumer<T> for TryReduceWithConsumer<'r, R>
+where
+ R: Fn(T::Output, T::Output) -> T + Sync,
+ T: Try + Send,
+{
+ type Folder = TryReduceWithFolder<'r, R, T>;
+ type Reducer = Self;
+ type Result = Option<T>;
+
+ fn split_at(self, _index: usize) -> (Self, Self, Self) {
+ (self, self, self)
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ TryReduceWithFolder {
+ reduce_op: self.reduce_op,
+ opt_control: None,
+ full: self.full,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.full.load(Ordering::Relaxed)
+ }
+}
+
+impl<'r, R, T> UnindexedConsumer<T> for TryReduceWithConsumer<'r, R>
+where
+ R: Fn(T::Output, T::Output) -> T + Sync,
+ T: Try + Send,
+{
+ fn split_off_left(&self) -> Self {
+ *self
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ *self
+ }
+}
+
+impl<'r, R, T> Reducer<Option<T>> for TryReduceWithConsumer<'r, R>
+where
+ R: Fn(T::Output, T::Output) -> T + Sync,
+ T: Try,
+{
+ fn reduce(self, left: Option<T>, right: Option<T>) -> Option<T> {
+ let reduce_op = self.reduce_op;
+ match (left, right) {
+ (Some(left), Some(right)) => match (left.branch(), right.branch()) {
+ (Continue(left), Continue(right)) => Some(reduce_op(left, right)),
+ (Break(r), _) | (_, Break(r)) => Some(T::from_residual(r)),
+ },
+ (None, x) | (x, None) => x,
+ }
+ }
+}
+
+struct TryReduceWithFolder<'r, R, T: Try> {
+ reduce_op: &'r R,
+ opt_control: Option<ControlFlow<T::Residual, T::Output>>,
+ full: &'r AtomicBool,
+}
+
+impl<'r, R, T> Folder<T> for TryReduceWithFolder<'r, R, T>
+where
+ R: Fn(T::Output, T::Output) -> T,
+ T: Try,
+{
+ type Result = Option<T>;
+
+ fn consume(mut self, item: T) -> Self {
+ let reduce_op = self.reduce_op;
+ let control = match (self.opt_control, item.branch()) {
+ (Some(Continue(left)), Continue(right)) => reduce_op(left, right).branch(),
+ (Some(control @ Break(_)), _) | (_, control) => control,
+ };
+ if let Break(_) = control {
+ self.full.store(true, Ordering::Relaxed)
+ }
+ self.opt_control = Some(control);
+ self
+ }
+
+ fn complete(self) -> Option<T> {
+ match self.opt_control {
+ Some(Continue(c)) => Some(T::from_output(c)),
+ Some(Break(r)) => Some(T::from_residual(r)),
+ None => None,
+ }
+ }
+
+ fn full(&self) -> bool {
+ match self.opt_control {
+ Some(Break(_)) => true,
+ _ => self.full.load(Ordering::Relaxed),
+ }
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/unzip.rs b/third_party/rust/rayon/src/iter/unzip.rs
new file mode 100644
index 0000000000..0b7074e929
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/unzip.rs
@@ -0,0 +1,525 @@
+use super::plumbing::*;
+use super::*;
+
+/// This trait abstracts the different ways we can "unzip" one parallel
+/// iterator into two distinct consumers, which we can handle almost
+/// identically apart from how to process the individual items.
+trait UnzipOp<T>: Sync + Send {
+ /// The type of item expected by the left consumer.
+ type Left: Send;
+
+ /// The type of item expected by the right consumer.
+ type Right: Send;
+
+ /// Consumes one item and feeds it to one or both of the underlying folders.
+ fn consume<FA, FB>(&self, item: T, left: FA, right: FB) -> (FA, FB)
+ where
+ FA: Folder<Self::Left>,
+ FB: Folder<Self::Right>;
+
+ /// Reports whether this op may support indexed consumers.
+ /// - e.g. true for `unzip` where the item count passed through directly.
+ /// - e.g. false for `partition` where the sorting is not yet known.
+ fn indexable() -> bool {
+ false
+ }
+}
+
+/// Runs an unzip-like operation into default `ParallelExtend` collections.
+fn execute<I, OP, FromA, FromB>(pi: I, op: OP) -> (FromA, FromB)
+where
+ I: ParallelIterator,
+ OP: UnzipOp<I::Item>,
+ FromA: Default + Send + ParallelExtend<OP::Left>,
+ FromB: Default + Send + ParallelExtend<OP::Right>,
+{
+ let mut a = FromA::default();
+ let mut b = FromB::default();
+ execute_into(&mut a, &mut b, pi, op);
+ (a, b)
+}
+
+/// Runs an unzip-like operation into `ParallelExtend` collections.
+fn execute_into<I, OP, FromA, FromB>(a: &mut FromA, b: &mut FromB, pi: I, op: OP)
+where
+ I: ParallelIterator,
+ OP: UnzipOp<I::Item>,
+ FromA: Send + ParallelExtend<OP::Left>,
+ FromB: Send + ParallelExtend<OP::Right>,
+{
+ // We have no idea what the consumers will look like for these
+ // collections' `par_extend`, but we can intercept them in our own
+ // `drive_unindexed`. Start with the left side, type `A`:
+ let iter = UnzipA { base: pi, op, b };
+ a.par_extend(iter);
+}
+
+/// Unzips the items of a parallel iterator into a pair of arbitrary
+/// `ParallelExtend` containers.
+///
+/// This is called by `ParallelIterator::unzip`.
+pub(super) fn unzip<I, A, B, FromA, FromB>(pi: I) -> (FromA, FromB)
+where
+ I: ParallelIterator<Item = (A, B)>,
+ FromA: Default + Send + ParallelExtend<A>,
+ FromB: Default + Send + ParallelExtend<B>,
+ A: Send,
+ B: Send,
+{
+ execute(pi, Unzip)
+}
+
+/// Unzips an `IndexedParallelIterator` into two arbitrary `Consumer`s.
+///
+/// This is called by `super::collect::unzip_into_vecs`.
+pub(super) fn unzip_indexed<I, A, B, CA, CB>(pi: I, left: CA, right: CB) -> (CA::Result, CB::Result)
+where
+ I: IndexedParallelIterator<Item = (A, B)>,
+ CA: Consumer<A>,
+ CB: Consumer<B>,
+ A: Send,
+ B: Send,
+{
+ let consumer = UnzipConsumer {
+ op: &Unzip,
+ left,
+ right,
+ };
+ pi.drive(consumer)
+}
+
+/// An `UnzipOp` that splits a tuple directly into the two consumers.
+struct Unzip;
+
+impl<A: Send, B: Send> UnzipOp<(A, B)> for Unzip {
+ type Left = A;
+ type Right = B;
+
+ fn consume<FA, FB>(&self, item: (A, B), left: FA, right: FB) -> (FA, FB)
+ where
+ FA: Folder<A>,
+ FB: Folder<B>,
+ {
+ (left.consume(item.0), right.consume(item.1))
+ }
+
+ fn indexable() -> bool {
+ true
+ }
+}
+
+/// Partitions the items of a parallel iterator into a pair of arbitrary
+/// `ParallelExtend` containers.
+///
+/// This is called by `ParallelIterator::partition`.
+pub(super) fn partition<I, A, B, P>(pi: I, predicate: P) -> (A, B)
+where
+ I: ParallelIterator,
+ A: Default + Send + ParallelExtend<I::Item>,
+ B: Default + Send + ParallelExtend<I::Item>,
+ P: Fn(&I::Item) -> bool + Sync + Send,
+{
+ execute(pi, Partition { predicate })
+}
+
+/// An `UnzipOp` that routes items depending on a predicate function.
+struct Partition<P> {
+ predicate: P,
+}
+
+impl<P, T> UnzipOp<T> for Partition<P>
+where
+ P: Fn(&T) -> bool + Sync + Send,
+ T: Send,
+{
+ type Left = T;
+ type Right = T;
+
+ fn consume<FA, FB>(&self, item: T, left: FA, right: FB) -> (FA, FB)
+ where
+ FA: Folder<T>,
+ FB: Folder<T>,
+ {
+ if (self.predicate)(&item) {
+ (left.consume(item), right)
+ } else {
+ (left, right.consume(item))
+ }
+ }
+}
+
+/// Partitions and maps the items of a parallel iterator into a pair of
+/// arbitrary `ParallelExtend` containers.
+///
+/// This called by `ParallelIterator::partition_map`.
+pub(super) fn partition_map<I, A, B, P, L, R>(pi: I, predicate: P) -> (A, B)
+where
+ I: ParallelIterator,
+ A: Default + Send + ParallelExtend<L>,
+ B: Default + Send + ParallelExtend<R>,
+ P: Fn(I::Item) -> Either<L, R> + Sync + Send,
+ L: Send,
+ R: Send,
+{
+ execute(pi, PartitionMap { predicate })
+}
+
+/// An `UnzipOp` that routes items depending on how they are mapped `Either`.
+struct PartitionMap<P> {
+ predicate: P,
+}
+
+impl<P, L, R, T> UnzipOp<T> for PartitionMap<P>
+where
+ P: Fn(T) -> Either<L, R> + Sync + Send,
+ L: Send,
+ R: Send,
+{
+ type Left = L;
+ type Right = R;
+
+ fn consume<FA, FB>(&self, item: T, left: FA, right: FB) -> (FA, FB)
+ where
+ FA: Folder<L>,
+ FB: Folder<R>,
+ {
+ match (self.predicate)(item) {
+ Either::Left(item) => (left.consume(item), right),
+ Either::Right(item) => (left, right.consume(item)),
+ }
+ }
+}
+
+/// A fake iterator to intercept the `Consumer` for type `A`.
+struct UnzipA<'b, I, OP, FromB> {
+ base: I,
+ op: OP,
+ b: &'b mut FromB,
+}
+
+impl<'b, I, OP, FromB> ParallelIterator for UnzipA<'b, I, OP, FromB>
+where
+ I: ParallelIterator,
+ OP: UnzipOp<I::Item>,
+ FromB: Send + ParallelExtend<OP::Right>,
+{
+ type Item = OP::Left;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let mut result = None;
+ {
+ // Now it's time to find the consumer for type `B`
+ let iter = UnzipB {
+ base: self.base,
+ op: self.op,
+ left_consumer: consumer,
+ left_result: &mut result,
+ };
+ self.b.par_extend(iter);
+ }
+ // NB: If for some reason `b.par_extend` doesn't actually drive the
+ // iterator, then we won't have a result for the left side to return
+ // at all. We can't fake an arbitrary consumer's result, so panic.
+ result.expect("unzip consumers didn't execute!")
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ if OP::indexable() {
+ self.base.opt_len()
+ } else {
+ None
+ }
+ }
+}
+
+/// A fake iterator to intercept the `Consumer` for type `B`.
+struct UnzipB<'r, I, OP, CA>
+where
+ I: ParallelIterator,
+ OP: UnzipOp<I::Item>,
+ CA: UnindexedConsumer<OP::Left>,
+ CA::Result: 'r,
+{
+ base: I,
+ op: OP,
+ left_consumer: CA,
+ left_result: &'r mut Option<CA::Result>,
+}
+
+impl<'r, I, OP, CA> ParallelIterator for UnzipB<'r, I, OP, CA>
+where
+ I: ParallelIterator,
+ OP: UnzipOp<I::Item>,
+ CA: UnindexedConsumer<OP::Left>,
+{
+ type Item = OP::Right;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ // Now that we have two consumers, we can unzip the real iterator.
+ let consumer = UnzipConsumer {
+ op: &self.op,
+ left: self.left_consumer,
+ right: consumer,
+ };
+
+ let result = self.base.drive_unindexed(consumer);
+ *self.left_result = Some(result.0);
+ result.1
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ if OP::indexable() {
+ self.base.opt_len()
+ } else {
+ None
+ }
+ }
+}
+
+/// `Consumer` that unzips into two other `Consumer`s
+struct UnzipConsumer<'a, OP, CA, CB> {
+ op: &'a OP,
+ left: CA,
+ right: CB,
+}
+
+impl<'a, T, OP, CA, CB> Consumer<T> for UnzipConsumer<'a, OP, CA, CB>
+where
+ OP: UnzipOp<T>,
+ CA: Consumer<OP::Left>,
+ CB: Consumer<OP::Right>,
+{
+ type Folder = UnzipFolder<'a, OP, CA::Folder, CB::Folder>;
+ type Reducer = UnzipReducer<CA::Reducer, CB::Reducer>;
+ type Result = (CA::Result, CB::Result);
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left1, left2, left_reducer) = self.left.split_at(index);
+ let (right1, right2, right_reducer) = self.right.split_at(index);
+
+ (
+ UnzipConsumer {
+ op: self.op,
+ left: left1,
+ right: right1,
+ },
+ UnzipConsumer {
+ op: self.op,
+ left: left2,
+ right: right2,
+ },
+ UnzipReducer {
+ left: left_reducer,
+ right: right_reducer,
+ },
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ UnzipFolder {
+ op: self.op,
+ left: self.left.into_folder(),
+ right: self.right.into_folder(),
+ }
+ }
+
+ fn full(&self) -> bool {
+ // don't stop until everyone is full
+ self.left.full() && self.right.full()
+ }
+}
+
+impl<'a, T, OP, CA, CB> UnindexedConsumer<T> for UnzipConsumer<'a, OP, CA, CB>
+where
+ OP: UnzipOp<T>,
+ CA: UnindexedConsumer<OP::Left>,
+ CB: UnindexedConsumer<OP::Right>,
+{
+ fn split_off_left(&self) -> Self {
+ UnzipConsumer {
+ op: self.op,
+ left: self.left.split_off_left(),
+ right: self.right.split_off_left(),
+ }
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ UnzipReducer {
+ left: self.left.to_reducer(),
+ right: self.right.to_reducer(),
+ }
+ }
+}
+
+/// `Folder` that unzips into two other `Folder`s
+struct UnzipFolder<'a, OP, FA, FB> {
+ op: &'a OP,
+ left: FA,
+ right: FB,
+}
+
+impl<'a, T, OP, FA, FB> Folder<T> for UnzipFolder<'a, OP, FA, FB>
+where
+ OP: UnzipOp<T>,
+ FA: Folder<OP::Left>,
+ FB: Folder<OP::Right>,
+{
+ type Result = (FA::Result, FB::Result);
+
+ fn consume(self, item: T) -> Self {
+ let (left, right) = self.op.consume(item, self.left, self.right);
+ UnzipFolder {
+ op: self.op,
+ left,
+ right,
+ }
+ }
+
+ fn complete(self) -> Self::Result {
+ (self.left.complete(), self.right.complete())
+ }
+
+ fn full(&self) -> bool {
+ // don't stop until everyone is full
+ self.left.full() && self.right.full()
+ }
+}
+
+/// `Reducer` that unzips into two other `Reducer`s
+struct UnzipReducer<RA, RB> {
+ left: RA,
+ right: RB,
+}
+
+impl<A, B, RA, RB> Reducer<(A, B)> for UnzipReducer<RA, RB>
+where
+ RA: Reducer<A>,
+ RB: Reducer<B>,
+{
+ fn reduce(self, left: (A, B), right: (A, B)) -> (A, B) {
+ (
+ self.left.reduce(left.0, right.0),
+ self.right.reduce(left.1, right.1),
+ )
+ }
+}
+
+impl<A, B, FromA, FromB> ParallelExtend<(A, B)> for (FromA, FromB)
+where
+ A: Send,
+ B: Send,
+ FromA: Send + ParallelExtend<A>,
+ FromB: Send + ParallelExtend<B>,
+{
+ fn par_extend<I>(&mut self, pi: I)
+ where
+ I: IntoParallelIterator<Item = (A, B)>,
+ {
+ execute_into(&mut self.0, &mut self.1, pi.into_par_iter(), Unzip);
+ }
+}
+
+impl<L, R, A, B> ParallelExtend<Either<L, R>> for (A, B)
+where
+ L: Send,
+ R: Send,
+ A: Send + ParallelExtend<L>,
+ B: Send + ParallelExtend<R>,
+{
+ fn par_extend<I>(&mut self, pi: I)
+ where
+ I: IntoParallelIterator<Item = Either<L, R>>,
+ {
+ execute_into(&mut self.0, &mut self.1, pi.into_par_iter(), UnEither);
+ }
+}
+
+/// An `UnzipOp` that routes items depending on their `Either` variant.
+struct UnEither;
+
+impl<L, R> UnzipOp<Either<L, R>> for UnEither
+where
+ L: Send,
+ R: Send,
+{
+ type Left = L;
+ type Right = R;
+
+ fn consume<FL, FR>(&self, item: Either<L, R>, left: FL, right: FR) -> (FL, FR)
+ where
+ FL: Folder<L>,
+ FR: Folder<R>,
+ {
+ match item {
+ Either::Left(item) => (left.consume(item), right),
+ Either::Right(item) => (left, right.consume(item)),
+ }
+ }
+}
+
+impl<A, B, FromA, FromB> FromParallelIterator<(A, B)> for (FromA, FromB)
+where
+ A: Send,
+ B: Send,
+ FromA: Send + FromParallelIterator<A>,
+ FromB: Send + FromParallelIterator<B>,
+{
+ fn from_par_iter<I>(pi: I) -> Self
+ where
+ I: IntoParallelIterator<Item = (A, B)>,
+ {
+ let (a, b): (Collector<FromA>, Collector<FromB>) = pi.into_par_iter().unzip();
+ (a.result.unwrap(), b.result.unwrap())
+ }
+}
+
+impl<L, R, A, B> FromParallelIterator<Either<L, R>> for (A, B)
+where
+ L: Send,
+ R: Send,
+ A: Send + FromParallelIterator<L>,
+ B: Send + FromParallelIterator<R>,
+{
+ fn from_par_iter<I>(pi: I) -> Self
+ where
+ I: IntoParallelIterator<Item = Either<L, R>>,
+ {
+ fn identity<T>(x: T) -> T {
+ x
+ }
+
+ let (a, b): (Collector<A>, Collector<B>) = pi.into_par_iter().partition_map(identity);
+ (a.result.unwrap(), b.result.unwrap())
+ }
+}
+
+/// Shim to implement a one-time `ParallelExtend` using `FromParallelIterator`.
+struct Collector<FromT> {
+ result: Option<FromT>,
+}
+
+impl<FromT> Default for Collector<FromT> {
+ fn default() -> Self {
+ Collector { result: None }
+ }
+}
+
+impl<T, FromT> ParallelExtend<T> for Collector<FromT>
+where
+ T: Send,
+ FromT: Send + FromParallelIterator<T>,
+{
+ fn par_extend<I>(&mut self, pi: I)
+ where
+ I: IntoParallelIterator<Item = T>,
+ {
+ debug_assert!(self.result.is_none());
+ self.result = Some(pi.into_par_iter().collect());
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/update.rs b/third_party/rust/rayon/src/iter/update.rs
new file mode 100644
index 0000000000..c693ac8d60
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/update.rs
@@ -0,0 +1,327 @@
+use super::plumbing::*;
+use super::*;
+
+use std::fmt::{self, Debug};
+
+/// `Update` is an iterator that mutates the elements of an
+/// underlying iterator before they are yielded.
+///
+/// This struct is created by the [`update()`] method on [`ParallelIterator`]
+///
+/// [`update()`]: trait.ParallelIterator.html#method.update
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Clone)]
+pub struct Update<I: ParallelIterator, F> {
+ base: I,
+ update_op: F,
+}
+
+impl<I: ParallelIterator + Debug, F> Debug for Update<I, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Update").field("base", &self.base).finish()
+ }
+}
+
+impl<I, F> Update<I, F>
+where
+ I: ParallelIterator,
+{
+ /// Creates a new `Update` iterator.
+ pub(super) fn new(base: I, update_op: F) -> Self {
+ Update { base, update_op }
+ }
+}
+
+impl<I, F> ParallelIterator for Update<I, F>
+where
+ I: ParallelIterator,
+ F: Fn(&mut I::Item) + Send + Sync,
+{
+ type Item = I::Item;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let consumer1 = UpdateConsumer::new(consumer, &self.update_op);
+ self.base.drive_unindexed(consumer1)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ self.base.opt_len()
+ }
+}
+
+impl<I, F> IndexedParallelIterator for Update<I, F>
+where
+ I: IndexedParallelIterator,
+ F: Fn(&mut I::Item) + Send + Sync,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ let consumer1 = UpdateConsumer::new(consumer, &self.update_op);
+ self.base.drive(consumer1)
+ }
+
+ fn len(&self) -> usize {
+ self.base.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.base.with_producer(Callback {
+ callback,
+ update_op: self.update_op,
+ });
+
+ struct Callback<CB, F> {
+ callback: CB,
+ update_op: F,
+ }
+
+ impl<T, F, CB> ProducerCallback<T> for Callback<CB, F>
+ where
+ CB: ProducerCallback<T>,
+ F: Fn(&mut T) + Send + Sync,
+ {
+ type Output = CB::Output;
+
+ fn callback<P>(self, base: P) -> CB::Output
+ where
+ P: Producer<Item = T>,
+ {
+ let producer = UpdateProducer {
+ base,
+ update_op: &self.update_op,
+ };
+ self.callback.callback(producer)
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+
+struct UpdateProducer<'f, P, F> {
+ base: P,
+ update_op: &'f F,
+}
+
+impl<'f, P, F> Producer for UpdateProducer<'f, P, F>
+where
+ P: Producer,
+ F: Fn(&mut P::Item) + Send + Sync,
+{
+ type Item = P::Item;
+ type IntoIter = UpdateSeq<P::IntoIter, &'f F>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ UpdateSeq {
+ base: self.base.into_iter(),
+ update_op: self.update_op,
+ }
+ }
+
+ fn min_len(&self) -> usize {
+ self.base.min_len()
+ }
+ fn max_len(&self) -> usize {
+ self.base.max_len()
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (left, right) = self.base.split_at(index);
+ (
+ UpdateProducer {
+ base: left,
+ update_op: self.update_op,
+ },
+ UpdateProducer {
+ base: right,
+ update_op: self.update_op,
+ },
+ )
+ }
+
+ fn fold_with<G>(self, folder: G) -> G
+ where
+ G: Folder<Self::Item>,
+ {
+ let folder1 = UpdateFolder {
+ base: folder,
+ update_op: self.update_op,
+ };
+ self.base.fold_with(folder1).base
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct UpdateConsumer<'f, C, F> {
+ base: C,
+ update_op: &'f F,
+}
+
+impl<'f, C, F> UpdateConsumer<'f, C, F> {
+ fn new(base: C, update_op: &'f F) -> Self {
+ UpdateConsumer { base, update_op }
+ }
+}
+
+impl<'f, T, C, F> Consumer<T> for UpdateConsumer<'f, C, F>
+where
+ C: Consumer<T>,
+ F: Fn(&mut T) + Send + Sync,
+{
+ type Folder = UpdateFolder<'f, C::Folder, F>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ UpdateConsumer::new(left, self.update_op),
+ UpdateConsumer::new(right, self.update_op),
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ UpdateFolder {
+ base: self.base.into_folder(),
+ update_op: self.update_op,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+impl<'f, T, C, F> UnindexedConsumer<T> for UpdateConsumer<'f, C, F>
+where
+ C: UnindexedConsumer<T>,
+ F: Fn(&mut T) + Send + Sync,
+{
+ fn split_off_left(&self) -> Self {
+ UpdateConsumer::new(self.base.split_off_left(), self.update_op)
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct UpdateFolder<'f, C, F> {
+ base: C,
+ update_op: &'f F,
+}
+
+fn apply<T>(update_op: impl Fn(&mut T)) -> impl Fn(T) -> T {
+ move |mut item| {
+ update_op(&mut item);
+ item
+ }
+}
+
+impl<'f, T, C, F> Folder<T> for UpdateFolder<'f, C, F>
+where
+ C: Folder<T>,
+ F: Fn(&mut T),
+{
+ type Result = C::Result;
+
+ fn consume(self, mut item: T) -> Self {
+ (self.update_op)(&mut item);
+
+ UpdateFolder {
+ base: self.base.consume(item),
+ update_op: self.update_op,
+ }
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ {
+ let update_op = self.update_op;
+ self.base = self
+ .base
+ .consume_iter(iter.into_iter().map(apply(update_op)));
+ self
+ }
+
+ fn complete(self) -> C::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.base.full()
+ }
+}
+
+/// Standard Update adaptor, based on `itertools::adaptors::Update`
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+struct UpdateSeq<I, F> {
+ base: I,
+ update_op: F,
+}
+
+impl<I, F> Iterator for UpdateSeq<I, F>
+where
+ I: Iterator,
+ F: Fn(&mut I::Item),
+{
+ type Item = I::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let mut v = self.base.next()?;
+ (self.update_op)(&mut v);
+ Some(v)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.base.size_hint()
+ }
+
+ fn fold<Acc, G>(self, init: Acc, g: G) -> Acc
+ where
+ G: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.base.map(apply(self.update_op)).fold(init, g)
+ }
+
+ // if possible, re-use inner iterator specializations in collect
+ fn collect<C>(self) -> C
+ where
+ C: ::std::iter::FromIterator<Self::Item>,
+ {
+ self.base.map(apply(self.update_op)).collect()
+ }
+}
+
+impl<I, F> ExactSizeIterator for UpdateSeq<I, F>
+where
+ I: ExactSizeIterator,
+ F: Fn(&mut I::Item),
+{
+}
+
+impl<I, F> DoubleEndedIterator for UpdateSeq<I, F>
+where
+ I: DoubleEndedIterator,
+ F: Fn(&mut I::Item),
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ let mut v = self.base.next_back()?;
+ (self.update_op)(&mut v);
+ Some(v)
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/while_some.rs b/third_party/rust/rayon/src/iter/while_some.rs
new file mode 100644
index 0000000000..215047bc6e
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/while_some.rs
@@ -0,0 +1,154 @@
+use super::plumbing::*;
+use super::*;
+use std::sync::atomic::{AtomicBool, Ordering};
+
+/// `WhileSome` is an iterator that yields the `Some` elements of an iterator,
+/// halting as soon as any `None` is produced.
+///
+/// This struct is created by the [`while_some()`] method on [`ParallelIterator`]
+///
+/// [`while_some()`]: trait.ParallelIterator.html#method.while_some
+/// [`ParallelIterator`]: trait.ParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct WhileSome<I: ParallelIterator> {
+ base: I,
+}
+
+impl<I> WhileSome<I>
+where
+ I: ParallelIterator,
+{
+ /// Creates a new `WhileSome` iterator.
+ pub(super) fn new(base: I) -> Self {
+ WhileSome { base }
+ }
+}
+
+impl<I, T> ParallelIterator for WhileSome<I>
+where
+ I: ParallelIterator<Item = Option<T>>,
+ T: Send,
+{
+ type Item = T;
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ let full = AtomicBool::new(false);
+ let consumer1 = WhileSomeConsumer {
+ base: consumer,
+ full: &full,
+ };
+ self.base.drive_unindexed(consumer1)
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+/// Consumer implementation
+
+struct WhileSomeConsumer<'f, C> {
+ base: C,
+ full: &'f AtomicBool,
+}
+
+impl<'f, T, C> Consumer<Option<T>> for WhileSomeConsumer<'f, C>
+where
+ C: Consumer<T>,
+ T: Send,
+{
+ type Folder = WhileSomeFolder<'f, C::Folder>;
+ type Reducer = C::Reducer;
+ type Result = C::Result;
+
+ fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
+ let (left, right, reducer) = self.base.split_at(index);
+ (
+ WhileSomeConsumer { base: left, ..self },
+ WhileSomeConsumer {
+ base: right,
+ ..self
+ },
+ reducer,
+ )
+ }
+
+ fn into_folder(self) -> Self::Folder {
+ WhileSomeFolder {
+ base: self.base.into_folder(),
+ full: self.full,
+ }
+ }
+
+ fn full(&self) -> bool {
+ self.full.load(Ordering::Relaxed) || self.base.full()
+ }
+}
+
+impl<'f, T, C> UnindexedConsumer<Option<T>> for WhileSomeConsumer<'f, C>
+where
+ C: UnindexedConsumer<T>,
+ T: Send,
+{
+ fn split_off_left(&self) -> Self {
+ WhileSomeConsumer {
+ base: self.base.split_off_left(),
+ ..*self
+ }
+ }
+
+ fn to_reducer(&self) -> Self::Reducer {
+ self.base.to_reducer()
+ }
+}
+
+struct WhileSomeFolder<'f, C> {
+ base: C,
+ full: &'f AtomicBool,
+}
+
+impl<'f, T, C> Folder<Option<T>> for WhileSomeFolder<'f, C>
+where
+ C: Folder<T>,
+{
+ type Result = C::Result;
+
+ fn consume(mut self, item: Option<T>) -> Self {
+ match item {
+ Some(item) => self.base = self.base.consume(item),
+ None => self.full.store(true, Ordering::Relaxed),
+ }
+ self
+ }
+
+ fn consume_iter<I>(mut self, iter: I) -> Self
+ where
+ I: IntoIterator<Item = Option<T>>,
+ {
+ fn some<T>(full: &AtomicBool) -> impl Fn(&Option<T>) -> bool + '_ {
+ move |x| match *x {
+ Some(_) => !full.load(Ordering::Relaxed),
+ None => {
+ full.store(true, Ordering::Relaxed);
+ false
+ }
+ }
+ }
+
+ self.base = self.base.consume_iter(
+ iter.into_iter()
+ .take_while(some(self.full))
+ .map(Option::unwrap),
+ );
+ self
+ }
+
+ fn complete(self) -> C::Result {
+ self.base.complete()
+ }
+
+ fn full(&self) -> bool {
+ self.full.load(Ordering::Relaxed) || self.base.full()
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/zip.rs b/third_party/rust/rayon/src/iter/zip.rs
new file mode 100644
index 0000000000..33823db9e4
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/zip.rs
@@ -0,0 +1,159 @@
+use super::plumbing::*;
+use super::*;
+use std::cmp;
+use std::iter;
+
+/// `Zip` is an iterator that zips up `a` and `b` into a single iterator
+/// of pairs. This struct is created by the [`zip()`] method on
+/// [`IndexedParallelIterator`]
+///
+/// [`zip()`]: trait.IndexedParallelIterator.html#method.zip
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct Zip<A: IndexedParallelIterator, B: IndexedParallelIterator> {
+ a: A,
+ b: B,
+}
+
+impl<A, B> Zip<A, B>
+where
+ A: IndexedParallelIterator,
+ B: IndexedParallelIterator,
+{
+ /// Creates a new `Zip` iterator.
+ pub(super) fn new(a: A, b: B) -> Self {
+ Zip { a, b }
+ }
+}
+
+impl<A, B> ParallelIterator for Zip<A, B>
+where
+ A: IndexedParallelIterator,
+ B: IndexedParallelIterator,
+{
+ type Item = (A::Item, B::Item);
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.len())
+ }
+}
+
+impl<A, B> IndexedParallelIterator for Zip<A, B>
+where
+ A: IndexedParallelIterator,
+ B: IndexedParallelIterator,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ bridge(self, consumer)
+ }
+
+ fn len(&self) -> usize {
+ cmp::min(self.a.len(), self.b.len())
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ return self.a.with_producer(CallbackA {
+ callback,
+ b: self.b,
+ });
+
+ struct CallbackA<CB, B> {
+ callback: CB,
+ b: B,
+ }
+
+ impl<CB, ITEM, B> ProducerCallback<ITEM> for CallbackA<CB, B>
+ where
+ B: IndexedParallelIterator,
+ CB: ProducerCallback<(ITEM, B::Item)>,
+ {
+ type Output = CB::Output;
+
+ fn callback<A>(self, a_producer: A) -> Self::Output
+ where
+ A: Producer<Item = ITEM>,
+ {
+ self.b.with_producer(CallbackB {
+ a_producer,
+ callback: self.callback,
+ })
+ }
+ }
+
+ struct CallbackB<CB, A> {
+ a_producer: A,
+ callback: CB,
+ }
+
+ impl<CB, A, ITEM> ProducerCallback<ITEM> for CallbackB<CB, A>
+ where
+ A: Producer,
+ CB: ProducerCallback<(A::Item, ITEM)>,
+ {
+ type Output = CB::Output;
+
+ fn callback<B>(self, b_producer: B) -> Self::Output
+ where
+ B: Producer<Item = ITEM>,
+ {
+ self.callback.callback(ZipProducer {
+ a: self.a_producer,
+ b: b_producer,
+ })
+ }
+ }
+ }
+}
+
+/// ////////////////////////////////////////////////////////////////////////
+
+struct ZipProducer<A: Producer, B: Producer> {
+ a: A,
+ b: B,
+}
+
+impl<A: Producer, B: Producer> Producer for ZipProducer<A, B> {
+ type Item = (A::Item, B::Item);
+ type IntoIter = iter::Zip<A::IntoIter, B::IntoIter>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.a.into_iter().zip(self.b.into_iter())
+ }
+
+ fn min_len(&self) -> usize {
+ cmp::max(self.a.min_len(), self.b.min_len())
+ }
+
+ fn max_len(&self) -> usize {
+ cmp::min(self.a.max_len(), self.b.max_len())
+ }
+
+ fn split_at(self, index: usize) -> (Self, Self) {
+ let (a_left, a_right) = self.a.split_at(index);
+ let (b_left, b_right) = self.b.split_at(index);
+ (
+ ZipProducer {
+ a: a_left,
+ b: b_left,
+ },
+ ZipProducer {
+ a: a_right,
+ b: b_right,
+ },
+ )
+ }
+}
diff --git a/third_party/rust/rayon/src/iter/zip_eq.rs b/third_party/rust/rayon/src/iter/zip_eq.rs
new file mode 100644
index 0000000000..4e64397d91
--- /dev/null
+++ b/third_party/rust/rayon/src/iter/zip_eq.rs
@@ -0,0 +1,72 @@
+use super::plumbing::*;
+use super::*;
+
+/// An [`IndexedParallelIterator`] that iterates over two parallel iterators of equal
+/// length simultaneously.
+///
+/// This struct is created by the [`zip_eq`] method on [`IndexedParallelIterator`],
+/// see its documentation for more information.
+///
+/// [`zip_eq`]: trait.IndexedParallelIterator.html#method.zip_eq
+/// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[derive(Debug, Clone)]
+pub struct ZipEq<A: IndexedParallelIterator, B: IndexedParallelIterator> {
+ zip: Zip<A, B>,
+}
+
+impl<A, B> ZipEq<A, B>
+where
+ A: IndexedParallelIterator,
+ B: IndexedParallelIterator,
+{
+ /// Creates a new `ZipEq` iterator.
+ pub(super) fn new(a: A, b: B) -> Self {
+ ZipEq {
+ zip: super::Zip::new(a, b),
+ }
+ }
+}
+
+impl<A, B> ParallelIterator for ZipEq<A, B>
+where
+ A: IndexedParallelIterator,
+ B: IndexedParallelIterator,
+{
+ type Item = (A::Item, B::Item);
+
+ fn drive_unindexed<C>(self, consumer: C) -> C::Result
+ where
+ C: UnindexedConsumer<Self::Item>,
+ {
+ bridge(self.zip, consumer)
+ }
+
+ fn opt_len(&self) -> Option<usize> {
+ Some(self.zip.len())
+ }
+}
+
+impl<A, B> IndexedParallelIterator for ZipEq<A, B>
+where
+ A: IndexedParallelIterator,
+ B: IndexedParallelIterator,
+{
+ fn drive<C>(self, consumer: C) -> C::Result
+ where
+ C: Consumer<Self::Item>,
+ {
+ bridge(self.zip, consumer)
+ }
+
+ fn len(&self) -> usize {
+ self.zip.len()
+ }
+
+ fn with_producer<CB>(self, callback: CB) -> CB::Output
+ where
+ CB: ProducerCallback<Self::Item>,
+ {
+ self.zip.with_producer(callback)
+ }
+}