//! 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]: http://doc.rust-lang.org/std/iter/trait.Iterator.html
+//! [regular iterator]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
//! [`ParallelIterator`]: trait.ParallelIterator.html
//! [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html
//! [split]: fn.split.html
};
mod step_by;
-#[cfg(step_by)]
+#[cfg(has_step_by_rev)]
pub use self::step_by::StepBy;
/// `IntoParallelIterator` implements the conversion to a [`ParallelIterator`].
fn try_for_each<OP, R>(self, op: OP) -> R
where
OP: Fn(Self::Item) -> R + Sync + Send,
- R: Try<Ok = ()> + Send,
+ R: Try<Output = ()> + Send,
{
- fn ok<R: Try<Ok = ()>>(_: (), _: ()) -> R {
- R::from_ok(())
+ fn ok<R: Try<Output = ()>>(_: (), _: ()) -> R {
+ R::from_output(())
}
self.map(op).try_reduce(<()>::default, ok)
where
OP: Fn(&mut T, Self::Item) -> R + Sync + Send,
T: Send + Clone,
- R: Try<Ok = ()> + Send,
+ R: Try<Output = ()> + Send,
{
- fn ok<R: Try<Ok = ()>>(_: (), _: ()) -> R {
- R::from_ok(())
+ fn ok<R: Try<Output = ()>>(_: (), _: ()) -> R {
+ R::from_output(())
}
self.map_with(init, op).try_reduce(<()>::default, ok)
where
OP: Fn(&mut T, Self::Item) -> R + Sync + Send,
INIT: Fn() -> T + Sync + Send,
- R: Try<Ok = ()> + Send,
+ R: Try<Output = ()> + Send,
{
- fn ok<R: Try<Ok = ()>>(_: (), _: ()) -> R {
- R::from_ok(())
+ fn ok<R: Try<Output = ()>>(_: (), _: ()) -> R {
+ R::from_output(())
}
self.map_init(init, op).try_reduce(<()>::default, ok)
where
OP: Fn(T, T) -> Self::Item + Sync + Send,
ID: Fn() -> T + Sync + Send,
- Self::Item: Try<Ok = T>,
+ Self::Item: Try<Output = T>,
{
try_reduce::try_reduce(self, identity, op)
}
fn try_reduce_with<T, OP>(self, op: OP) -> Option<Self::Item>
where
OP: Fn(T, T) -> Self::Item + Sync + Send,
- Self::Item: Try<Ok = T>,
+ Self::Item: Try<Output = T>,
{
try_reduce_with::try_reduce_with(self, op)
}
where
F: Fn(T, Self::Item) -> R + Sync + Send,
ID: Fn() -> T + Sync + Send,
- R: Try<Ok = T> + Send,
+ R: Try<Output = T> + Send,
{
TryFold::new(self, identity, fold_op)
}
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<Ok = T> + Send,
+ R: Try<Output = T> + Send,
T: Clone + Send,
{
TryFoldWith::new(self, init, fold_op)
///
/// 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>,
/// See the [README] for more details on the internals of parallel
/// iterators.
///
- /// [README]: README.md
+ /// [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>;
/// # Compatibility
///
/// This method is only available on Rust 1.38 or greater.
- #[cfg(step_by)]
+ #[cfg(has_step_by_rev)]
fn step_by(self, step: usize) -> StepBy<Self> {
StepBy::new(self, step)
}
}
/// Sets the minimum length of iterators desired to process in each
- /// thread. Rayon will not split any smaller than this length, but
+ /// 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
}
/// Sets the maximum length of iterators desired to process in each
- /// thread. Rayon will try to split at least below this length,
+ /// 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.
/// See the [README] for more details on the internals of parallel
/// iterators.
///
- /// [README]: README.md
+ /// [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
/// See the [README] for more details on the internals of parallel
/// iterators.
///
- /// [README]: README.md
+ /// [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;
}
/// 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::task::Poll;
+
+ #[cfg(has_control_flow)]
+ pub(crate) use std::ops::ControlFlow;
+
+ #[cfg(not(has_control_flow))]
+ #[allow(missing_debug_implementations)]
+ pub enum ControlFlow<B, C = ()> {
+ Continue(C),
+ Break(B),
+ }
+
+ use self::ControlFlow::{Break, Continue};
+
/// Clone of `std::ops::Try`.
///
/// Implementing this trait is not permitted outside of `rayon`.
pub trait Try {
private_decl! {}
- type Ok;
- type Error;
- fn into_result(self) -> Result<Self::Ok, Self::Error>;
- fn from_ok(v: Self::Ok) -> Self;
- fn from_error(v: Self::Error) -> Self;
+ 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>;
+ }
+
+ #[cfg(has_control_flow)]
+ 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 Ok = T;
- type Error = ();
+ type Output = T;
+ type Residual = Option<Infallible>;
- fn into_result(self) -> Result<T, ()> {
- self.ok_or(())
+ fn from_output(output: Self::Output) -> Self {
+ Some(output)
}
- fn from_ok(v: T) -> Self {
- Some(v)
+
+ fn from_residual(residual: Self::Residual) -> Self {
+ match residual {
+ None => None,
+ Some(_) => unreachable!(),
+ }
}
- fn from_error(_: ()) -> Self {
- None
+
+ 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 Ok = T;
- type Error = E;
+ type Output = T;
+ type Residual = Result<Infallible, E>;
- fn into_result(self) -> Result<T, E> {
- self
+ fn from_output(output: Self::Output) -> Self {
+ Ok(output)
}
- fn from_ok(v: T) -> Self {
- Ok(v)
+
+ 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)),
+ }
}
- fn from_error(v: E) -> Self {
- Err(v)
+ }
+
+ 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)),
+ }
}
}
}