I have a function that operates on a Vec<T>
which purpose is to extend the vector with new items generated using reference to existing items. I'm trying to run the generation of new data in parallel using rayon
.
This is a minimal example:
use itertools::Itertools;
use rayon::prelude::*;
fn main() {
let mut foo = Foo {
data: (0..1000).into_iter().collect(),
};
foo.run();
}
struct Foo<T> {
data: Vec<T>,
}
type Pair<'a, T> = (&'a T, &'a T);
impl<'a, T: Clone + 'a> Foo<T>
where
Vec<Pair<'a, T>>: IntoParallelIterator<Item = Pair<'a, T>>,
[T; 2]: IntoParallelIterator,
Vec<T>: FromParallelIterator<<[T; 2] as IntoParallelIterator>::Item>,
{
fn run(&'a mut self) {
let combinations: Vec<Pair<'a, T>> = self
.data
.iter()
.combinations(2)
.map(|x| (x[0], x[1]))
.collect();
let mut new_combinations: Vec<T> = combinations
.into_par_iter()
.flat_map(|(a, b)| bar(a, b))
.collect();
self.data.append(&mut new_combinations);
}
}
fn bar<T: Clone>(a: &T, b: &T) -> [T; 2] {
[a.clone(), b.clone()]
}
You can find a link to Playground here.
Building the above example raises this error:
error[E0502]: cannot borrow `self.data` as mutable because it is also borrowed as immutable
--> src/main.rs:36:9
|
17 | impl<'a, T: Clone + 'a> Foo<T>
| -- lifetime `'a` defined here
...
24 | let combinations: Vec<Pair<'a, T>> = self
| ___________________________----------------___-
| | |
| | type annotation requires that `self.data` is borrowed for `'a`
25 | | .data
26 | | .iter()
| |___________________- immutable borrow occurs here
...
36 | self.data.append(&mut new_combinations);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
As far as I understand since I am collecting into a let new_combinations: Vec<T>
there should be no immutable references to self.data
and I should be able in theory to borrow it mutably to append the new combinations. However, it seems that self.data
is borrowed for 'a
which extends beyond the scope of this method. I cannot find a way to avoid specifying the lifetime fn run(&'a mut self)
since I need to specify that the lifetimes of the references to the items of self.data
cannot outlive self
when creating the combinations.
Is there a way to allow this method to operate as expected, that is: 1) select a list of references to the items in self.data
, 2) apply a function that creates new items T
in parallel and finally 3) update self.data
with the new items.
Note that as a workaround one could return the new_combinations
from the method and append them to self.data
separately.
Would be great if all of this would be possible by avoiding as many collect()
as possible while operating directly with iterators only.