Skip to content

Commit c571f8f

Browse files
bors[bot]cuviper
andauthored
Merge #802
802: impl FromParallelIterator for tuple pairs r=nikomatsakis a=cuviper Like #604 for `ParallelExtend`, implementing `FromParallelIterator` for tuple pairs opens up new possibilities for nesting `collect`. The possibility of short-circuiting into `Result<(T, U), E>` for #801 is particularly motivating. - `FromParallelIterator<(A, B)> for (FromA, FromB)` works like `unzip` - `FromParallelIterator<Either<L, R>> for (A, B)` works like `partition_map` Co-authored-by: Josh Stone <[email protected]>
2 parents d5f9e31 + 08345e1 commit c571f8f

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

src/iter/mod.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,6 +1966,79 @@ pub trait ParallelIterator: Sized + Send {
19661966
///
19671967
/// assert_eq!(sync_vec, async_vec);
19681968
/// ```
1969+
///
1970+
/// You can collect a pair of collections like [`unzip`](#method.unzip)
1971+
/// for paired items:
1972+
///
1973+
/// ```
1974+
/// use rayon::prelude::*;
1975+
///
1976+
/// let a = [(0, 1), (1, 2), (2, 3), (3, 4)];
1977+
/// let (first, second): (Vec<_>, Vec<_>) = a.into_par_iter().collect();
1978+
///
1979+
/// assert_eq!(first, [0, 1, 2, 3]);
1980+
/// assert_eq!(second, [1, 2, 3, 4]);
1981+
/// ```
1982+
///
1983+
/// Or like [`partition_map`](#method.partition_map) for `Either` items:
1984+
///
1985+
/// ```
1986+
/// use rayon::prelude::*;
1987+
/// use rayon::iter::Either;
1988+
///
1989+
/// let (left, right): (Vec<_>, Vec<_>) = (0..8).into_par_iter().map(|x| {
1990+
/// if x % 2 == 0 {
1991+
/// Either::Left(x * 4)
1992+
/// } else {
1993+
/// Either::Right(x * 3)
1994+
/// }
1995+
/// }).collect();
1996+
///
1997+
/// assert_eq!(left, [0, 8, 16, 24]);
1998+
/// assert_eq!(right, [3, 9, 15, 21]);
1999+
/// ```
2000+
///
2001+
/// You can even collect an arbitrarily-nested combination of pairs and `Either`:
2002+
///
2003+
/// ```
2004+
/// use rayon::prelude::*;
2005+
/// use rayon::iter::Either;
2006+
///
2007+
/// let (first, (left, right)): (Vec<_>, (Vec<_>, Vec<_>))
2008+
/// = (0..8).into_par_iter().map(|x| {
2009+
/// if x % 2 == 0 {
2010+
/// (x, Either::Left(x * 4))
2011+
/// } else {
2012+
/// (-x, Either::Right(x * 3))
2013+
/// }
2014+
/// }).collect();
2015+
///
2016+
/// assert_eq!(first, [0, -1, 2, -3, 4, -5, 6, -7]);
2017+
/// assert_eq!(left, [0, 8, 16, 24]);
2018+
/// assert_eq!(right, [3, 9, 15, 21]);
2019+
/// ```
2020+
///
2021+
/// All of that can _also_ be combined with short-circuiting collection of
2022+
/// `Result` or `Option` types:
2023+
///
2024+
/// ```
2025+
/// use rayon::prelude::*;
2026+
/// use rayon::iter::Either;
2027+
///
2028+
/// let result: Result<(Vec<_>, (Vec<_>, Vec<_>)), _>
2029+
/// = (0..8).into_par_iter().map(|x| {
2030+
/// if x > 5 {
2031+
/// Err(x)
2032+
/// } else if x % 2 == 0 {
2033+
/// Ok((x, Either::Left(x * 4)))
2034+
/// } else {
2035+
/// Ok((-x, Either::Right(x * 3)))
2036+
/// }
2037+
/// }).collect();
2038+
///
2039+
/// let error = result.unwrap_err();
2040+
/// assert!(error == 6 || error == 7);
2041+
/// ```
19692042
fn collect<C>(self) -> C
19702043
where
19712044
C: FromParallelIterator<Self::Item>,

src/iter/unzip.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,3 +462,64 @@ where
462462
}
463463
}
464464
}
465+
466+
impl<A, B, FromA, FromB> FromParallelIterator<(A, B)> for (FromA, FromB)
467+
where
468+
A: Send,
469+
B: Send,
470+
FromA: Send + FromParallelIterator<A>,
471+
FromB: Send + FromParallelIterator<B>,
472+
{
473+
fn from_par_iter<I>(pi: I) -> Self
474+
where
475+
I: IntoParallelIterator<Item = (A, B)>,
476+
{
477+
let (a, b): (Collector<FromA>, Collector<FromB>) = pi.into_par_iter().unzip();
478+
(a.result.unwrap(), b.result.unwrap())
479+
}
480+
}
481+
482+
impl<L, R, A, B> FromParallelIterator<Either<L, R>> for (A, B)
483+
where
484+
L: Send,
485+
R: Send,
486+
A: Send + FromParallelIterator<L>,
487+
B: Send + FromParallelIterator<R>,
488+
{
489+
fn from_par_iter<I>(pi: I) -> Self
490+
where
491+
I: IntoParallelIterator<Item = Either<L, R>>,
492+
{
493+
fn identity<T>(x: T) -> T {
494+
x
495+
}
496+
497+
let (a, b): (Collector<A>, Collector<B>) = pi.into_par_iter().partition_map(identity);
498+
(a.result.unwrap(), b.result.unwrap())
499+
}
500+
}
501+
502+
/// Shim to implement a one-time `ParallelExtend` using `FromParallelIterator`.
503+
struct Collector<FromT> {
504+
result: Option<FromT>,
505+
}
506+
507+
impl<FromT> Default for Collector<FromT> {
508+
fn default() -> Self {
509+
Collector { result: None }
510+
}
511+
}
512+
513+
impl<T, FromT> ParallelExtend<T> for Collector<FromT>
514+
where
515+
T: Send,
516+
FromT: Send + FromParallelIterator<T>,
517+
{
518+
fn par_extend<I>(&mut self, pi: I)
519+
where
520+
I: IntoParallelIterator<Item = T>,
521+
{
522+
debug_assert!(self.result.is_none());
523+
self.result = Some(pi.into_par_iter().collect());
524+
}
525+
}

0 commit comments

Comments
 (0)