Error for extending rayon method

I'm writing an extension function that implements a parallel for_each method for any type that implements into_par_iter.

I tried the following code:

use rayon::prelude::*;

trait ParExt<T> {
    fn for_each<R>(self, f: impl Fn(T) -> R + Sync + Send);
}

impl<T, P> ParExt<T> for P where T: Send + Sync, P: ParallelIterator<Item = T> {
    fn for_each<R>(self, f: impl Fn(T) -> R + Sync + Send) {
        self.into_par_iter().for_each(|e| { f(e); });
    }
}

fn main() {
    vec![String::from("abc"), String::from("xyz")].for_each(|s| dbg!(s));
}
Getting error message:
error[E0599]: the method `for_each` exists for struct `Vec<String>`, but its trait bounds were not satisfied
  --> src/main.rs:14:52
   |
14 |     vec![String::from("abc"), String::from("xyz")].for_each(|s| dbg!(s));
   |                                                    ^^^^^^^^ method cannot be called on `Vec<String>` due to unsatisfied trait bounds
   |
note: trait bound `[String]: Sized` was not satisfied
  --> src/main.rs:7:9
   |
7  | impl<T, P> ParExt<T> for P where T: Send + Sync, P: ParallelIterator<Item = T> {
   |         ^  ---------     -
   |         |
   |         unsatisfied trait bound introduced here
note: the following trait bounds were not satisfied:
      `&Vec<String>: rayon::iter::ParallelIterator`
      `&[String]: rayon::iter::ParallelIterator`
      `&mut Vec<String>: rayon::iter::ParallelIterator`
      `&mut [String]: rayon::iter::ParallelIterator`
      `Vec<String>: rayon::iter::ParallelIterator`
      `[String]: rayon::iter::ParallelIterator`
  --> src/main.rs:7:53
   |
7  | impl<T, P> ParExt<T> for P where T: Send + Sync, P: ParallelIterator<Item = T> {
   |            ---------     -                          ^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
note: the following trait bounds were not satisfied:
      `<&Vec<String> as rayon::iter::ParallelIterator>::Item = _`
      `<&[String] as rayon::iter::ParallelIterator>::Item = _`
      `<&mut Vec<String> as rayon::iter::ParallelIterator>::Item = _`
      `<&mut [String] as rayon::iter::ParallelIterator>::Item = _`
      `<Vec<String> as rayon::iter::ParallelIterator>::Item = _`
      `<[String] as rayon::iter::ParallelIterator>::Item = _`
  --> src/main.rs:7:70
   |
7  | impl<T, P> ParExt<T> for P where T: Send + Sync, P: ParallelIterator<Item = T> {
   |            ---------     -                                           ^^^^^^^^ unsatisfied trait bound introduced here
   = note: the following trait bounds were not satisfied:
           `Vec<String>: Iterator`
           which is required by `&mut Vec<String>: Iterator`
           `[String]: Iterator`
           which is required by `&mut [String]: Iterator`
help: consider relaxing the type parameter's implicit `Sized` bound
   |
7  | impl<T, P: ?Sized> ParExt<T> for P where T: Send + Sync, P: ParallelIterator<Item = T> {
   |          ++++++++

For more information about this error, try `rustc --explain E0599`.
error: could not compile `playground` due to previous error

How should I fix this error?

After a lot of trial and error, I finally wrote it myself:

use rayon::prelude::*;

trait ParExt<T> {
    fn for_each<R>(self, f: impl Fn(T) -> R + Sync + Send);
}

impl<T, P> ParExt<T> for P where T: Send + Sync, P: IntoParallelIterator<Item = T> + for<'a> IntoParallelRefIterator<'a> {
    fn for_each<R>(self, f: impl Fn(T) -> R + Sync + Send) {
        self.into_par_iter().for_each(|e| { f(e); });
    }
}

fn main() {
    vec![String::from("abc"), String::from("xyz")].for_each(|s| dbg!(s));
}

The problem has been solved, if there is a better answer, welcome to propose.

The "better" answer would be to just write:

source.into_par_iter().for_each(fn);

Though I guess that's unsatisfactory for you. But it hides less. The into hints that the source is consumed, par hints that this is a parallelization method, iter tells me this is a consuming parallel iterator.

With just a for_each I don't see any of that context, so your extension method doesn't make anything meaningfully shorter or more expressive.

Someone used to reading Rust coming across that code will just wonder how you got the standard Iterator::for_each on something that isn't an iterator (such as a Vec).

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.