Search code examples
rustcallbackmutabilityrayon

In Rust, how do you pass a function with a mutable parameter to be used in parllel?


I've been playing around with collision detection, and I've been working on a function that collides two sets of objects with each other. To allow it to be run in parallel, only the first set is mutable, and the elements of the first set are iterated through with rayon.

All of that seems to be fine, except that I want to be able to pass a collision resolution function. Because its first argument is a mutable reference, Rust also seems to want the function itself to be mutable. This doesn't work if I want the function to run in parallel.

pub fn collide_with_binned_static<T1: Send + Sync, T2: Send + Sync>(
    items_a: &mut [T1],
    aabb: impl Fn(&T1) -> Rect + Send + Sync,
    items_b: &[T2],
    bin_index_b: &BinIndex,
    f: impl FnMut(&mut T1, &T2) + Send + Sync)
{
    items_a.par_iter_mut().for_each(|item_a| {
        let collisions = bin_index_b.check_rect_collision(&aabb(item_a));
        for collision in collisions {
            f(&mut *item_a, &items_b[collision]);
//          ^ cannot borrow as mutable
        }
    });
}

Basically, I don't see how a function that takes mutable items needs to be mutable itself. If I was calling a static function with static types, instead of a generic function with generic types, I'm confident this would work. Is there anything I can do to fix it?


Solution

  • I thought I was using a function reference, which would have worked.

    f: fn(&mut T1, &T2)
    

    Instead I was using a closure, which could have mutated state in its scope, allowing previous calls to affect subsequent calls.