I am currently in process of learning Rust by porting a Constructive Solid Geometry (CSG) library and I have been wrestling with borrow checker and its' "no 2 mutable references on single object" policy. In the CSG library, I have a function for cutting mesh, which in rust-like pseudo-code looks something like this:
fn cut(
mesh: &Vec<Polygon>,
cutting_plane: &Plane,
front: &mut Vec<Polygon>,
back: &mut Vec<Polygon>,
coplanar_front: &mut Vec<Polygon>,
coplanar_back: &mut Vec<Polygon>)
{
for polygon in mesh.iter() {
let polygon_position = calculate_polygon_position_in_relation_to_plane(&polygon, &cutting_plane);
match polygon_position {
InFront => {
front.push(polygon.clone());
}
InBack => {
back.push(polygon.clone());
}
Coplanar => {
if polygon is coplanar with cutting_plane but still a little bit in the front {
coplanar_front.push(polygon.clone());
} else {
coplanar_back.push(polygon.clone());
}
}
Spanning => {
let front_polygon, back_polygon = cut_polygon(&polygon, &cutting_plane);
front.push(front_polygon);
back.push(back_polygon);
}
}
}
}
The result of this function then depends on how the function will fill the 4 vectors (front, back, coplanar_front, coplanar_back) passed in the arguments. The problem is, that I need to call the function both like this:
/* ... setup some_mesh and some_cutting_plane ... */
let front = Vec::new();
let back = Vec::new();
let coplanar_front = Vec::new();
let coplanar_back = Vec::new();
//I care about where the coplanar polygons precisely lie
cut(&some_mesh, &some_cutting_plane, &mut front, &mut back, &mut coplanar_front, &mut coplanar_back);
/* ... use coplanar_front, coplanar_back, front and back vectors */
and like this:
/* ... setup some_mesh and some_cutting_plane ... */
let front = Vec::new();
let back = Vec::new();
let coplanar = Vec::new();
//I don't care where the coplanar polygons actually lie
cut(&some_mesh, &some_cutting_plane, &mut front, &mut back, &mut coplanar, &mut coplanar);
/* ... use coplanar, front and back vectors ... */
Where obviously in the second case, the borrow checker will stop me, since borrowing 2 mutable references for the same value is a big no no.
The naive solution in the second case, is to create a temporary array for one co-planar half and then merge it with the other, however this also comes with a price of a needless array copy.
I also don't want to create 2 versions of the same function, where one would work with just 1 co-planar vector and the other with 2 co-planar vectors, since most of the code would be the same.
I know that there are structures like Box, that allow borrowing multiple mutable references, but I have been unable to fully grasp the concept of how to use it properly, because I always stumble back to the original problem, where I need 2 mutable references on the same object.
Is there something Rust can do I am not aware of, or is there a better way to approach this problem?